mindlore 0.6.3 → 0.6.5
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 +1 -1
- package/dist/scripts/cc-memory-bulk-sync.js +1 -1
- package/dist/scripts/cc-memory-bulk-sync.js.map +1 -1
- package/dist/scripts/cc-session-sync.js +2 -2
- package/dist/scripts/cc-session-sync.js.map +1 -1
- package/dist/scripts/fetch-raw.js +17 -8
- package/dist/scripts/fetch-raw.js.map +1 -1
- package/dist/scripts/init.js +8 -8
- package/dist/scripts/init.js.map +1 -1
- package/dist/scripts/lib/chunker.d.ts.map +1 -1
- package/dist/scripts/lib/chunker.js +3 -0
- package/dist/scripts/lib/chunker.js.map +1 -1
- package/dist/scripts/lib/constants.d.ts +5 -0
- package/dist/scripts/lib/constants.d.ts.map +1 -1
- package/dist/scripts/lib/constants.js +35 -1
- package/dist/scripts/lib/constants.js.map +1 -1
- package/dist/scripts/lib/daemon.d.ts.map +1 -1
- package/dist/scripts/lib/daemon.js +3 -0
- package/dist/scripts/lib/daemon.js.map +1 -1
- package/dist/scripts/lib/fuzzy.d.ts.map +1 -1
- package/dist/scripts/lib/fuzzy.js +6 -4
- package/dist/scripts/lib/fuzzy.js.map +1 -1
- package/dist/scripts/lib/input-validation.d.ts +5 -0
- package/dist/scripts/lib/input-validation.d.ts.map +1 -0
- package/dist/scripts/lib/input-validation.js +48 -0
- package/dist/scripts/lib/input-validation.js.map +1 -0
- package/dist/scripts/lib/privacy-filter.d.ts.map +1 -1
- package/dist/scripts/lib/privacy-filter.js +3 -0
- package/dist/scripts/lib/privacy-filter.js.map +1 -1
- package/dist/scripts/lib/proximity.d.ts.map +1 -1
- package/dist/scripts/lib/proximity.js +6 -0
- package/dist/scripts/lib/proximity.js.map +1 -1
- package/dist/scripts/lib/rrf.d.ts +7 -2
- package/dist/scripts/lib/rrf.d.ts.map +1 -1
- package/dist/scripts/lib/rrf.js +20 -16
- package/dist/scripts/lib/rrf.js.map +1 -1
- package/dist/scripts/lib/search-cache.d.ts +15 -0
- package/dist/scripts/lib/search-cache.d.ts.map +1 -1
- package/dist/scripts/lib/search-cache.js +50 -2
- package/dist/scripts/lib/search-cache.js.map +1 -1
- package/dist/scripts/lib/search-engine.d.ts +1 -1
- package/dist/scripts/lib/search-engine.d.ts.map +1 -1
- package/dist/scripts/lib/search-engine.js +31 -31
- package/dist/scripts/lib/search-engine.js.map +1 -1
- package/dist/scripts/mindlore-daemon.js +1 -3
- package/dist/scripts/mindlore-daemon.js.map +1 -1
- package/dist/scripts/mindlore-obsidian.js +4 -0
- package/dist/scripts/mindlore-obsidian.js.map +1 -1
- package/dist/scripts/mindlore-rrf-bench.d.ts +2 -0
- package/dist/scripts/mindlore-rrf-bench.d.ts.map +1 -0
- package/dist/scripts/mindlore-rrf-bench.js +30 -0
- package/dist/scripts/mindlore-rrf-bench.js.map +1 -0
- package/dist/tests/fetch-raw-security.test.d.ts +2 -0
- package/dist/tests/fetch-raw-security.test.d.ts.map +1 -0
- package/dist/tests/fetch-raw-security.test.js +72 -0
- package/dist/tests/fetch-raw-security.test.js.map +1 -0
- package/dist/tests/fetch-raw.test.js +4 -4
- package/dist/tests/fetch-raw.test.js.map +1 -1
- package/dist/tests/fts5.test.js +0 -22
- package/dist/tests/fts5.test.js.map +1 -1
- package/dist/tests/input-validation.test.d.ts +2 -0
- package/dist/tests/input-validation.test.d.ts.map +1 -0
- package/dist/tests/input-validation.test.js +113 -0
- package/dist/tests/input-validation.test.js.map +1 -0
- package/dist/tests/privacy-filter.test.js +25 -50
- package/dist/tests/privacy-filter.test.js.map +1 -1
- package/dist/tests/rrf.test.js +42 -3
- package/dist/tests/rrf.test.js.map +1 -1
- package/dist/tests/search-cache.test.js +44 -12
- package/dist/tests/search-cache.test.js.map +1 -1
- package/dist/tests/search-hook.test.js +0 -44
- package/dist/tests/search-hook.test.js.map +1 -1
- package/dist/tests/sec-regression.test.d.ts +2 -0
- package/dist/tests/sec-regression.test.d.ts.map +1 -0
- package/dist/tests/sec-regression.test.js +174 -0
- package/dist/tests/sec-regression.test.js.map +1 -0
- package/dist/tests/stop-words.test.d.ts +2 -0
- package/dist/tests/stop-words.test.d.ts.map +1 -0
- package/dist/tests/stop-words.test.js +47 -0
- package/dist/tests/stop-words.test.js.map +1 -0
- package/hooks/lib/mindlore-common.cjs +39 -36
- package/hooks/mindlore-fts5-sync.cjs +4 -3
- package/hooks/mindlore-index.cjs +6 -7
- package/hooks/mindlore-pre-compact.cjs +5 -4
- package/hooks/mindlore-search.cjs +3 -2
- package/hooks/mindlore-session-end.cjs +10 -10
- package/hooks/mindlore-session-focus.cjs +11 -1
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/templates/SCHEMA.md +10 -108
- package/templates/config.json +1 -1
- package/dist/scripts/lib/hybrid-search.d.ts +0 -62
- package/dist/scripts/lib/hybrid-search.d.ts.map +0 -1
- package/dist/scripts/lib/hybrid-search.js +0 -171
- package/dist/scripts/lib/hybrid-search.js.map +0 -1
- package/dist/tests/hybrid-search.test.d.ts +0 -2
- package/dist/tests/hybrid-search.test.d.ts.map +0 -1
- package/dist/tests/hybrid-search.test.js +0 -139
- package/dist/tests/hybrid-search.test.js.map +0 -1
- package/dist/tests/index-cli-embed.test.d.ts +0 -7
- package/dist/tests/index-cli-embed.test.d.ts.map +0 -1
- package/dist/tests/index-cli-embed.test.js +0 -128
- package/dist/tests/index-cli-embed.test.js.map +0 -1
- package/dist/tests/search-cli-hybrid.test.d.ts +0 -6
- package/dist/tests/search-cli-hybrid.test.d.ts.map +0 -1
- package/dist/tests/search-cli-hybrid.test.js +0 -103
- package/dist/tests/search-cli-hybrid.test.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hybrid-search.d.ts","sourceRoot":"","sources":["../../../scripts/lib/hybrid-search.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,OAAO,KAAK,aAAa,MAAM,gBAAgB,CAAC;AAIhD,KAAK,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC;AAEvC,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAcD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1D;AAID;;;GAGG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAGrD;AAKD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAID,wBAAgB,UAAU,CACxB,UAAU,EAAE,SAAS,EAAE,EACvB,UAAU,EAAE,SAAS,EAAE,EACvB,OAAO,GAAE,UAAe,GACvB,WAAW,EAAE,CAsDf;AAID,wBAAgB,UAAU,CACxB,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,MAAM,EACb,KAAK,GAAE,MAAW,EAClB,OAAO,CAAC,EAAE,MAAM,GACf,SAAS,EAAE,CA8Bb;AAED,wBAAgB,SAAS,CACvB,EAAE,EAAE,QAAQ,EACZ,cAAc,EAAE,MAAM,EAAE,EACxB,KAAK,GAAE,MAAW,GACjB,SAAS,EAAE,CAeb;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,mBAAwB,GAChC,WAAW,EAAE,CAoCf"}
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getCategoryWeight = getCategoryWeight;
|
|
4
|
-
exports.l2ToCosine = l2ToCosine;
|
|
5
|
-
exports.normalizeBM25 = normalizeBM25;
|
|
6
|
-
exports.computeRRF = computeRRF;
|
|
7
|
-
exports.searchFts5 = searchFts5;
|
|
8
|
-
exports.searchVec = searchVec;
|
|
9
|
-
exports.hybridSearch = hybridSearch;
|
|
10
|
-
const db_helpers_js_1 = require("./db-helpers.js");
|
|
11
|
-
const constants_js_1 = require("./constants.js");
|
|
12
|
-
// ── Category Weights (v0.6.1) ─────────────────────────────────────
|
|
13
|
-
const CATEGORY_WEIGHTS = {
|
|
14
|
-
sources: 2.0,
|
|
15
|
-
domains: 1.8,
|
|
16
|
-
analyses: 1.6,
|
|
17
|
-
decisions: 1.5,
|
|
18
|
-
diary: 1.0,
|
|
19
|
-
'cc-session': 0.8,
|
|
20
|
-
'cc-subagent': 0.5,
|
|
21
|
-
};
|
|
22
|
-
function getCategoryWeight(category) {
|
|
23
|
-
return CATEGORY_WEIGHTS[category] ?? 1.0;
|
|
24
|
-
}
|
|
25
|
-
// ── Utility Functions ──────────────────────────────────────────────
|
|
26
|
-
/**
|
|
27
|
-
* Convert L2 distance to cosine similarity.
|
|
28
|
-
* For normalized vectors: cosine_sim = 1.0 - (l2_dist² / 2.0)
|
|
29
|
-
*/
|
|
30
|
-
function l2ToCosine(l2Distance) {
|
|
31
|
-
const cosine = 1.0 - (l2Distance * l2Distance / 2.0);
|
|
32
|
-
return Math.max(0.0, Math.min(1.0, cosine));
|
|
33
|
-
}
|
|
34
|
-
// Empirical upper bound for BM25 absolute rank in Mindlore corpus (~150 docs)
|
|
35
|
-
const BM25_MAX_RANK = 25.0;
|
|
36
|
-
/**
|
|
37
|
-
* Normalize FTS5 BM25 rank to 0-1 range.
|
|
38
|
-
* FTS5 returns negative rank — more negative = better match.
|
|
39
|
-
*/
|
|
40
|
-
function normalizeBM25(rank) {
|
|
41
|
-
return Math.abs(rank) / BM25_MAX_RANK;
|
|
42
|
-
}
|
|
43
|
-
// ── RRF Fusion ─────────────────────────────────────────────────────
|
|
44
|
-
function computeRRF(ftsResults, vecResults, options = {}) {
|
|
45
|
-
const k = options.k ?? 60;
|
|
46
|
-
const ftsWeight = options.ftsWeight ?? 0.4;
|
|
47
|
-
const vecWeight = options.vecWeight ?? 0.6;
|
|
48
|
-
const scores = new Map();
|
|
49
|
-
// FTS5 results — already sorted by rank (most negative first = best)
|
|
50
|
-
for (let i = 0; i < ftsResults.length; i++) {
|
|
51
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- loop guard: i < length
|
|
52
|
-
const r = ftsResults[i];
|
|
53
|
-
const rrfScore = ftsWeight * (1.0 / (k + i + 1));
|
|
54
|
-
const existing = scores.get(r.slug);
|
|
55
|
-
if (existing) {
|
|
56
|
-
existing.score += rrfScore;
|
|
57
|
-
existing.ftsRank = r.rank;
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
scores.set(r.slug, {
|
|
61
|
-
slug: r.slug,
|
|
62
|
-
score: rrfScore,
|
|
63
|
-
ftsRank: r.rank,
|
|
64
|
-
path: r.path,
|
|
65
|
-
description: r.description,
|
|
66
|
-
title: r.title,
|
|
67
|
-
category: r.category,
|
|
68
|
-
tags: r.tags,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
// Vec results — already sorted by distance (lowest first = most similar)
|
|
73
|
-
for (let i = 0; i < vecResults.length; i++) {
|
|
74
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- loop guard: i < length
|
|
75
|
-
const r = vecResults[i];
|
|
76
|
-
const rrfScore = vecWeight * (1.0 / (k + i + 1));
|
|
77
|
-
const existing = scores.get(r.slug);
|
|
78
|
-
if (existing) {
|
|
79
|
-
existing.score += rrfScore;
|
|
80
|
-
existing.vecDistance = r.distance;
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
scores.set(r.slug, {
|
|
84
|
-
slug: r.slug,
|
|
85
|
-
score: rrfScore,
|
|
86
|
-
vecDistance: r.distance,
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
const results = Array.from(scores.values());
|
|
91
|
-
for (const r of results) {
|
|
92
|
-
if (r.category === constants_js_1.CC_MEMORY_CATEGORY)
|
|
93
|
-
r.score *= constants_js_1.CC_MEMORY_BOOST;
|
|
94
|
-
r.score *= getCategoryWeight(r.category ?? '');
|
|
95
|
-
}
|
|
96
|
-
return results.sort((a, b) => b.score - a.score);
|
|
97
|
-
}
|
|
98
|
-
// ── Search Functions ───────────────────────────────────────────────
|
|
99
|
-
function searchFts5(db, query, limit = 20, project) {
|
|
100
|
-
const sanitized = query.replace(/["*(){}[\]^~:]/g, '').trim();
|
|
101
|
-
if (!sanitized)
|
|
102
|
-
return [];
|
|
103
|
-
const terms = sanitized.split(/\s+/).map(t => `"${t}"`).join(' OR ');
|
|
104
|
-
try {
|
|
105
|
-
if (project) {
|
|
106
|
-
return (0, db_helpers_js_1.dbAll)(db, `SELECT slug, path, description, title, category, tags, rank
|
|
107
|
-
FROM mindlore_fts
|
|
108
|
-
WHERE mindlore_fts MATCH ? AND project = ?
|
|
109
|
-
ORDER BY rank
|
|
110
|
-
LIMIT ?`, terms, project, limit);
|
|
111
|
-
}
|
|
112
|
-
return (0, db_helpers_js_1.dbAll)(db, `SELECT slug, path, description, title, category, tags, rank
|
|
113
|
-
FROM mindlore_fts
|
|
114
|
-
WHERE mindlore_fts MATCH ?
|
|
115
|
-
ORDER BY rank
|
|
116
|
-
LIMIT ?`, terms, limit);
|
|
117
|
-
}
|
|
118
|
-
catch (_err) {
|
|
119
|
-
return [];
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
function searchVec(db, queryEmbedding, limit = 20) {
|
|
123
|
-
try {
|
|
124
|
-
const buf = Buffer.from(new Float32Array(queryEmbedding).buffer);
|
|
125
|
-
return (0, db_helpers_js_1.dbAll)(db, `SELECT slug, distance
|
|
126
|
-
FROM documents_vec
|
|
127
|
-
WHERE embedding MATCH ?
|
|
128
|
-
ORDER BY distance
|
|
129
|
-
LIMIT ?`, buf, limit);
|
|
130
|
-
}
|
|
131
|
-
catch (_err) {
|
|
132
|
-
return [];
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Main hybrid search entry point.
|
|
137
|
-
* Falls back to pure FTS5 when vec table or embedding is not available.
|
|
138
|
-
*/
|
|
139
|
-
function hybridSearch(db, query, options = {}) {
|
|
140
|
-
const maxResults = options.maxResults ?? 5;
|
|
141
|
-
const ftsLimit = 20;
|
|
142
|
-
const vecLimit = 20;
|
|
143
|
-
// Always search FTS5
|
|
144
|
-
const ftsResults = searchFts5(db, query, ftsLimit, options.project);
|
|
145
|
-
// Try vec search if embedding is provided and vec table exists
|
|
146
|
-
let vecResults = [];
|
|
147
|
-
if (options.queryEmbedding && (0, db_helpers_js_1.hasVecTable)(db)) {
|
|
148
|
-
vecResults = searchVec(db, options.queryEmbedding, vecLimit);
|
|
149
|
-
}
|
|
150
|
-
// If no vec results, return FTS5 results directly
|
|
151
|
-
if (vecResults.length === 0) {
|
|
152
|
-
return ftsResults.slice(0, maxResults).map(r => ({
|
|
153
|
-
slug: r.slug,
|
|
154
|
-
score: normalizeBM25(r.rank) * getCategoryWeight(r.category ?? ''),
|
|
155
|
-
ftsRank: r.rank,
|
|
156
|
-
path: r.path,
|
|
157
|
-
description: r.description,
|
|
158
|
-
title: r.title,
|
|
159
|
-
category: r.category,
|
|
160
|
-
tags: r.tags,
|
|
161
|
-
}));
|
|
162
|
-
}
|
|
163
|
-
// Fuse results with RRF
|
|
164
|
-
const fused = computeRRF(ftsResults, vecResults, {
|
|
165
|
-
k: options.k,
|
|
166
|
-
ftsWeight: options.ftsWeight,
|
|
167
|
-
vecWeight: options.vecWeight,
|
|
168
|
-
});
|
|
169
|
-
return fused.slice(0, maxResults);
|
|
170
|
-
}
|
|
171
|
-
//# sourceMappingURL=hybrid-search.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hybrid-search.js","sourceRoot":"","sources":["../../../scripts/lib/hybrid-search.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hybrid-search.test.d.ts","sourceRoot":"","sources":["../../tests/hybrid-search.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const path_1 = __importDefault(require("path"));
|
|
7
|
-
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
8
|
-
const db_js_1 = require("./helpers/db.js");
|
|
9
|
-
const hybrid_search_js_1 = require("../scripts/lib/hybrid-search.js");
|
|
10
|
-
const TEST_DIR = path_1.default.join(__dirname, '..', '.test-hybrid-search');
|
|
11
|
-
const DB_PATH = path_1.default.join(TEST_DIR, 'mindlore.db');
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
(0, db_js_1.setupTestDir)(TEST_DIR, ['sources']);
|
|
14
|
-
const db = (0, db_js_1.createTestDb)(DB_PATH);
|
|
15
|
-
db.close();
|
|
16
|
-
});
|
|
17
|
-
afterEach(() => {
|
|
18
|
-
(0, db_js_1.teardownTestDir)(TEST_DIR);
|
|
19
|
-
});
|
|
20
|
-
describe('RRF Fusion', () => {
|
|
21
|
-
test('should compute RRF scores correctly', () => {
|
|
22
|
-
const { computeRRF } = require('../scripts/lib/hybrid-search.js');
|
|
23
|
-
const ftsResults = [
|
|
24
|
-
{ slug: 'a', rank: -10 },
|
|
25
|
-
{ slug: 'b', rank: -5 },
|
|
26
|
-
];
|
|
27
|
-
const vecResults = [
|
|
28
|
-
{ slug: 'b', distance: 0.5 },
|
|
29
|
-
{ slug: 'c', distance: 0.8 },
|
|
30
|
-
];
|
|
31
|
-
const fused = computeRRF(ftsResults, vecResults, { k: 60, ftsWeight: 0.4, vecWeight: 0.6 });
|
|
32
|
-
// 'b' appears in both — should have highest score
|
|
33
|
-
expect(fused[0].slug).toBe('b');
|
|
34
|
-
expect(fused.length).toBe(3); // a, b, c
|
|
35
|
-
// All scores should be positive
|
|
36
|
-
fused.forEach((r) => expect(r.score).toBeGreaterThan(0));
|
|
37
|
-
});
|
|
38
|
-
test('should handle FTS-only results (vec empty)', () => {
|
|
39
|
-
const { computeRRF } = require('../scripts/lib/hybrid-search.js');
|
|
40
|
-
const ftsResults = [
|
|
41
|
-
{ slug: 'a', rank: -10 },
|
|
42
|
-
{ slug: 'b', rank: -5 },
|
|
43
|
-
];
|
|
44
|
-
const fused = computeRRF(ftsResults, [], { k: 60, ftsWeight: 0.4, vecWeight: 0.6 });
|
|
45
|
-
expect(fused.length).toBe(2);
|
|
46
|
-
expect(fused[0].slug).toBe('a');
|
|
47
|
-
});
|
|
48
|
-
test('should handle vec-only results (FTS empty)', () => {
|
|
49
|
-
const { computeRRF } = require('../scripts/lib/hybrid-search.js');
|
|
50
|
-
const vecResults = [
|
|
51
|
-
{ slug: 'a', distance: 0.3 },
|
|
52
|
-
{ slug: 'b', distance: 0.9 },
|
|
53
|
-
];
|
|
54
|
-
const fused = computeRRF([], vecResults, { k: 60, ftsWeight: 0.4, vecWeight: 0.6 });
|
|
55
|
-
expect(fused.length).toBe(2);
|
|
56
|
-
expect(fused[0].slug).toBe('a'); // lower distance = more similar
|
|
57
|
-
});
|
|
58
|
-
test('should convert L2 distance to cosine similarity', () => {
|
|
59
|
-
const { l2ToCosine } = require('../scripts/lib/hybrid-search.js');
|
|
60
|
-
// L2 distance 0 = identical = cosine 1.0
|
|
61
|
-
expect(l2ToCosine(0)).toBeCloseTo(1.0, 5);
|
|
62
|
-
// L2 distance 2 = opposite = cosine 0.0 (for normalized vectors)
|
|
63
|
-
expect(l2ToCosine(2)).toBeCloseTo(0.0, 5);
|
|
64
|
-
// L2 distance 1 (90 degrees for normalized) = cosine 0.5
|
|
65
|
-
expect(l2ToCosine(1)).toBeCloseTo(0.5, 5);
|
|
66
|
-
});
|
|
67
|
-
test('should normalize BM25 scores', () => {
|
|
68
|
-
const { normalizeBM25 } = require('../scripts/lib/hybrid-search.js');
|
|
69
|
-
// FTS5 returns negative ranks — more negative = better match
|
|
70
|
-
expect(normalizeBM25(-25)).toBeCloseTo(1.0, 5);
|
|
71
|
-
expect(normalizeBM25(-12.5)).toBeCloseTo(0.5, 5);
|
|
72
|
-
expect(normalizeBM25(0)).toBeCloseTo(0.0, 5);
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
describe('Hybrid Search Integration', () => {
|
|
76
|
-
test('should search FTS5 and return results with path and score', () => {
|
|
77
|
-
const { searchFts5 } = require('../scripts/lib/hybrid-search.js');
|
|
78
|
-
const db = new better_sqlite3_1.default(DB_PATH);
|
|
79
|
-
(0, db_js_1.insertFts)(db, {
|
|
80
|
-
path: path_1.default.join(TEST_DIR, 'sources', 'test.md'),
|
|
81
|
-
slug: 'test-doc',
|
|
82
|
-
description: 'TypeScript guide for beginners',
|
|
83
|
-
type: 'source',
|
|
84
|
-
category: 'sources',
|
|
85
|
-
title: 'Test Doc',
|
|
86
|
-
content: 'TypeScript is a typed superset of JavaScript',
|
|
87
|
-
tags: 'typescript,javascript',
|
|
88
|
-
});
|
|
89
|
-
const results = searchFts5(db, 'TypeScript', 10);
|
|
90
|
-
expect(results.length).toBe(1);
|
|
91
|
-
expect(results[0].slug).toBe('test-doc');
|
|
92
|
-
expect(results[0].rank).toBeDefined();
|
|
93
|
-
db.close();
|
|
94
|
-
});
|
|
95
|
-
test('should fall back to pure FTS5 when vec table is missing', () => {
|
|
96
|
-
const { hybridSearch } = require('../scripts/lib/hybrid-search.js');
|
|
97
|
-
const db = new better_sqlite3_1.default(DB_PATH);
|
|
98
|
-
(0, db_js_1.insertFts)(db, {
|
|
99
|
-
path: path_1.default.join(TEST_DIR, 'sources', 'fallback.md'),
|
|
100
|
-
slug: 'fallback-doc',
|
|
101
|
-
description: 'Fallback test document',
|
|
102
|
-
type: 'source',
|
|
103
|
-
category: 'sources',
|
|
104
|
-
title: 'Fallback Doc',
|
|
105
|
-
content: 'This tests the graceful fallback to pure FTS5',
|
|
106
|
-
tags: 'test',
|
|
107
|
-
});
|
|
108
|
-
// No vec table loaded — should still work via FTS5 fallback
|
|
109
|
-
const results = hybridSearch(db, 'fallback', { maxResults: 5 });
|
|
110
|
-
expect(results.length).toBe(1);
|
|
111
|
-
expect(results[0].slug).toBe('fallback-doc');
|
|
112
|
-
db.close();
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
describe('category boost (v0.6.1)', () => {
|
|
116
|
-
test('sources weight is higher than cc-session', () => {
|
|
117
|
-
expect((0, hybrid_search_js_1.getCategoryWeight)('sources')).toBeGreaterThan((0, hybrid_search_js_1.getCategoryWeight)('cc-session'));
|
|
118
|
-
});
|
|
119
|
-
test('domains weight is higher than cc-subagent', () => {
|
|
120
|
-
expect((0, hybrid_search_js_1.getCategoryWeight)('domains')).toBeGreaterThan((0, hybrid_search_js_1.getCategoryWeight)('cc-subagent'));
|
|
121
|
-
});
|
|
122
|
-
test('unknown category returns 1.0', () => {
|
|
123
|
-
expect((0, hybrid_search_js_1.getCategoryWeight)('unknown-category')).toBe(1.0);
|
|
124
|
-
});
|
|
125
|
-
test('category boost affects FTS-only hybrid results', () => {
|
|
126
|
-
const dbPath = path_1.default.join(TEST_DIR, 'boost.db');
|
|
127
|
-
(0, db_js_1.setupTestDir)(TEST_DIR, ['sources']);
|
|
128
|
-
const db = (0, db_js_1.createTestDb)(dbPath);
|
|
129
|
-
(0, db_js_1.insertFts)(db, { path: '/src.md', slug: 'src', content: 'karar alindi mimari', category: 'sources' });
|
|
130
|
-
(0, db_js_1.insertFts)(db, { path: '/sess.md', slug: 'sess', content: 'karar alindi mimari', category: 'cc-session' });
|
|
131
|
-
const { hybridSearch } = require('../scripts/lib/hybrid-search.js');
|
|
132
|
-
const results = hybridSearch(db, 'karar', { maxResults: 5 });
|
|
133
|
-
expect(results.length).toBe(2);
|
|
134
|
-
expect(results[0].category).toBe('sources');
|
|
135
|
-
db.close();
|
|
136
|
-
(0, db_js_1.teardownTestDir)(TEST_DIR);
|
|
137
|
-
});
|
|
138
|
-
});
|
|
139
|
-
//# sourceMappingURL=hybrid-search.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hybrid-search.test.js","sourceRoot":"","sources":["../../tests/hybrid-search.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-cli-embed.test.d.ts","sourceRoot":"","sources":["../../tests/index-cli-embed.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Tests for embedding pipeline used by --embed flag in index script.
|
|
4
|
-
* Tests the library functions (embedding.ts, db-helpers.ts vec functions)
|
|
5
|
-
* rather than the CLI subprocess.
|
|
6
|
-
*/
|
|
7
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
-
};
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
const path_1 = __importDefault(require("path"));
|
|
12
|
-
const db_js_1 = require("./helpers/db.js");
|
|
13
|
-
const { hasVecTable, dbAll: dbAllFn } = require('../scripts/lib/db-helpers.js');
|
|
14
|
-
const { searchFts5, searchVec, hybridSearch } = require('../scripts/lib/hybrid-search.js');
|
|
15
|
-
const TEST_DIR = path_1.default.join(__dirname, '..', '.test-index-cli-embed');
|
|
16
|
-
const DB_PATH = path_1.default.join(TEST_DIR, 'mindlore.db');
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
(0, db_js_1.setupTestDir)(TEST_DIR, ['sources']);
|
|
19
|
-
});
|
|
20
|
-
afterEach(() => {
|
|
21
|
-
(0, db_js_1.teardownTestDir)(TEST_DIR);
|
|
22
|
-
});
|
|
23
|
-
describe('Embedding Pipeline — vec table management', () => {
|
|
24
|
-
test('should create vec table when sqlite-vec is available', () => {
|
|
25
|
-
const { db, vecLoaded } = (0, db_js_1.createTestDbWithVec)(DB_PATH);
|
|
26
|
-
if (vecLoaded) {
|
|
27
|
-
expect(hasVecTable(db)).toBe(true);
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
expect(hasVecTable(db)).toBe(false);
|
|
31
|
-
}
|
|
32
|
-
db.close();
|
|
33
|
-
});
|
|
34
|
-
test('should handle missing sqlite-vec gracefully', () => {
|
|
35
|
-
const db = (0, db_js_1.createTestDb)(DB_PATH);
|
|
36
|
-
expect(hasVecTable(db)).toBe(false);
|
|
37
|
-
db.close();
|
|
38
|
-
});
|
|
39
|
-
test('should insert and query vec embeddings when vec is available', () => {
|
|
40
|
-
const { db, vecLoaded } = (0, db_js_1.createTestDbWithVec)(DB_PATH);
|
|
41
|
-
if (!vecLoaded) {
|
|
42
|
-
db.close();
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
const testEmbedding = new Float32Array(384);
|
|
46
|
-
testEmbedding[0] = 1.0;
|
|
47
|
-
(0, db_js_1.insertVec)(db, 'test-doc', testEmbedding, 'test-model');
|
|
48
|
-
const rows = dbAllFn(db, 'SELECT slug FROM documents_vec WHERE slug = ?', 'test-doc');
|
|
49
|
-
expect(rows).toHaveLength(1);
|
|
50
|
-
expect(rows[0]?.slug).toBe('test-doc');
|
|
51
|
-
db.close();
|
|
52
|
-
});
|
|
53
|
-
test('should search vec table with embedding match when available', () => {
|
|
54
|
-
const { db, vecLoaded } = (0, db_js_1.createTestDbWithVec)(DB_PATH);
|
|
55
|
-
if (!vecLoaded) {
|
|
56
|
-
db.close();
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
const embed1 = new Float32Array(384);
|
|
60
|
-
embed1[0] = 1.0;
|
|
61
|
-
(0, db_js_1.insertVec)(db, 'doc-a', embed1, 'test-model');
|
|
62
|
-
const embed2 = new Float32Array(384);
|
|
63
|
-
embed2[1] = 1.0;
|
|
64
|
-
(0, db_js_1.insertVec)(db, 'doc-b', embed2, 'test-model');
|
|
65
|
-
const queryEmbed = new Float32Array(384);
|
|
66
|
-
queryEmbed[0] = 0.9;
|
|
67
|
-
const results = searchVec(db, Array.from(queryEmbed), 5);
|
|
68
|
-
expect(results.length).toBe(2);
|
|
69
|
-
expect(results[0].slug).toBe('doc-a');
|
|
70
|
-
db.close();
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
describe('Embedding Pipeline — FTS5 + vec coexistence', () => {
|
|
74
|
-
test('should allow FTS5 and vec tables in same database', () => {
|
|
75
|
-
const { db, vecLoaded } = (0, db_js_1.createTestDbWithVec)(DB_PATH);
|
|
76
|
-
(0, db_js_1.insertFts)(db, {
|
|
77
|
-
path: path_1.default.join(TEST_DIR, 'sources', 'coexist.md'),
|
|
78
|
-
slug: 'coexist-doc',
|
|
79
|
-
description: 'Test coexistence of FTS5 and vec tables',
|
|
80
|
-
type: 'source',
|
|
81
|
-
category: 'sources',
|
|
82
|
-
title: 'Coexist Doc',
|
|
83
|
-
content: 'Testing that both FTS5 and vec work together',
|
|
84
|
-
tags: 'test',
|
|
85
|
-
});
|
|
86
|
-
const ftsResults = searchFts5(db, 'coexistence', 5);
|
|
87
|
-
expect(ftsResults.length).toBeGreaterThan(0);
|
|
88
|
-
if (vecLoaded) {
|
|
89
|
-
const testEmbed = new Float32Array(384);
|
|
90
|
-
testEmbed[0] = 1.0;
|
|
91
|
-
(0, db_js_1.insertVec)(db, 'coexist-doc', testEmbed, 'test-model');
|
|
92
|
-
expect(hasVecTable(db)).toBe(true);
|
|
93
|
-
}
|
|
94
|
-
db.close();
|
|
95
|
-
});
|
|
96
|
-
test('should run hybridSearch with both FTS5 data and vec embeddings', () => {
|
|
97
|
-
const { db, vecLoaded } = (0, db_js_1.createTestDbWithVec)(DB_PATH);
|
|
98
|
-
(0, db_js_1.insertFts)(db, {
|
|
99
|
-
path: path_1.default.join(TEST_DIR, 'sources', 'hybrid-test.md'),
|
|
100
|
-
slug: 'hybrid-test',
|
|
101
|
-
description: 'Document for hybrid search integration test',
|
|
102
|
-
type: 'source',
|
|
103
|
-
category: 'sources',
|
|
104
|
-
title: 'Hybrid Test',
|
|
105
|
-
content: 'Hybrid search combines FTS5 keyword and vector semantic results',
|
|
106
|
-
tags: 'hybrid,search',
|
|
107
|
-
});
|
|
108
|
-
if (vecLoaded) {
|
|
109
|
-
const testEmbed = new Float32Array(384);
|
|
110
|
-
testEmbed[0] = 1.0;
|
|
111
|
-
(0, db_js_1.insertVec)(db, 'hybrid-test', testEmbed, 'test-model');
|
|
112
|
-
}
|
|
113
|
-
let queryEmbed;
|
|
114
|
-
if (vecLoaded) {
|
|
115
|
-
const q = new Float32Array(384);
|
|
116
|
-
q[0] = 0.9;
|
|
117
|
-
queryEmbed = Array.from(q);
|
|
118
|
-
}
|
|
119
|
-
const results = hybridSearch(db, 'hybrid search', {
|
|
120
|
-
maxResults: 5,
|
|
121
|
-
queryEmbedding: queryEmbed,
|
|
122
|
-
});
|
|
123
|
-
expect(results.length).toBeGreaterThan(0);
|
|
124
|
-
expect(results[0].slug).toBe('hybrid-test');
|
|
125
|
-
db.close();
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
//# sourceMappingURL=index-cli-embed.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-cli-embed.test.js","sourceRoot":"","sources":["../../tests/index-cli-embed.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"search-cli-hybrid.test.d.ts","sourceRoot":"","sources":["../../tests/search-cli-hybrid.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Tests for hybrid search CLI path — tests the library functions
|
|
4
|
-
* that --hybrid flag invokes (synonym expansion + hybridSearch integration).
|
|
5
|
-
*/
|
|
6
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
-
};
|
|
9
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
12
|
-
const db_js_1 = require("./helpers/db.js");
|
|
13
|
-
const { hybridSearch } = require('../scripts/lib/hybrid-search.js');
|
|
14
|
-
const { expandQuery, loadSynonyms } = require('../scripts/lib/synonym.js');
|
|
15
|
-
const TEST_DIR = path_1.default.join(__dirname, '..', '.test-search-cli-hybrid');
|
|
16
|
-
const DB_PATH = path_1.default.join(TEST_DIR, 'mindlore.db');
|
|
17
|
-
beforeEach(() => {
|
|
18
|
-
(0, db_js_1.setupTestDir)(TEST_DIR, ['sources', 'domains']);
|
|
19
|
-
const db = (0, db_js_1.createTestDb)(DB_PATH);
|
|
20
|
-
(0, db_js_1.insertFts)(db, {
|
|
21
|
-
path: path_1.default.join(TEST_DIR, 'sources', 'auth-guide.md'),
|
|
22
|
-
slug: 'auth-guide',
|
|
23
|
-
description: 'Authentication patterns and JWT token management',
|
|
24
|
-
type: 'source',
|
|
25
|
-
category: 'sources',
|
|
26
|
-
title: 'Auth Guide',
|
|
27
|
-
content: 'Authentication login patterns for secure applications with JWT tokens',
|
|
28
|
-
tags: 'auth,security',
|
|
29
|
-
});
|
|
30
|
-
(0, db_js_1.insertFts)(db, {
|
|
31
|
-
path: path_1.default.join(TEST_DIR, 'domains', 'database.md'),
|
|
32
|
-
slug: 'database',
|
|
33
|
-
description: 'SQLite and database optimization techniques',
|
|
34
|
-
type: 'domain',
|
|
35
|
-
category: 'domains',
|
|
36
|
-
title: 'Database',
|
|
37
|
-
content: 'SQLite FTS5 database optimization and indexing strategies',
|
|
38
|
-
tags: 'sqlite,database',
|
|
39
|
-
});
|
|
40
|
-
db.close();
|
|
41
|
-
});
|
|
42
|
-
afterEach(() => {
|
|
43
|
-
(0, db_js_1.teardownTestDir)(TEST_DIR);
|
|
44
|
-
});
|
|
45
|
-
describe('Hybrid Search CLI Path — synonym expansion + hybridSearch', () => {
|
|
46
|
-
test('should find results via synonym expansion through hybridSearch', () => {
|
|
47
|
-
const synonyms = loadSynonyms({
|
|
48
|
-
synonyms: {
|
|
49
|
-
auth: ['authentication', 'login', 'kimlik doğrulama'],
|
|
50
|
-
db: ['database', 'veritabanı', 'sqlite'],
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
const query = expandQuery('auth', synonyms).join(' ');
|
|
54
|
-
const db = new better_sqlite3_1.default(DB_PATH, { readonly: true });
|
|
55
|
-
const results = hybridSearch(db, query, { maxResults: 3 });
|
|
56
|
-
expect(results.length).toBeGreaterThan(0);
|
|
57
|
-
expect(results[0].slug).toBe('auth-guide');
|
|
58
|
-
expect(results[0].score).toBeGreaterThan(0);
|
|
59
|
-
db.close();
|
|
60
|
-
});
|
|
61
|
-
test('should boost results when synonym matches additional terms', () => {
|
|
62
|
-
const synonyms = { db: ['database', 'sqlite'] };
|
|
63
|
-
const expandedQuery = expandQuery('db', synonyms).join(' ');
|
|
64
|
-
const db = new better_sqlite3_1.default(DB_PATH, { readonly: true });
|
|
65
|
-
const results = hybridSearch(db, expandedQuery, { maxResults: 3 });
|
|
66
|
-
expect(results.length).toBeGreaterThan(0);
|
|
67
|
-
expect(results[0].slug).toBe('database');
|
|
68
|
-
db.close();
|
|
69
|
-
});
|
|
70
|
-
test('should return FusedResult format with all expected fields', () => {
|
|
71
|
-
const db = new better_sqlite3_1.default(DB_PATH, { readonly: true });
|
|
72
|
-
const results = hybridSearch(db, 'authentication', { maxResults: 3 });
|
|
73
|
-
expect(results.length).toBeGreaterThan(0);
|
|
74
|
-
expect(results[0]).toMatchObject({
|
|
75
|
-
slug: expect.any(String),
|
|
76
|
-
score: expect.any(Number),
|
|
77
|
-
ftsRank: expect.any(Number),
|
|
78
|
-
});
|
|
79
|
-
db.close();
|
|
80
|
-
});
|
|
81
|
-
test('should respect maxResults option', () => {
|
|
82
|
-
const db = new better_sqlite3_1.default(DB_PATH, { readonly: true });
|
|
83
|
-
const results = hybridSearch(db, 'authentication OR database', { maxResults: 1 });
|
|
84
|
-
expect(results.length).toBe(1);
|
|
85
|
-
db.close();
|
|
86
|
-
});
|
|
87
|
-
test('should return empty array for unmatched query', () => {
|
|
88
|
-
const db = new better_sqlite3_1.default(DB_PATH, { readonly: true });
|
|
89
|
-
const results = hybridSearch(db, 'kubernetes docker', { maxResults: 3 });
|
|
90
|
-
expect(results).toHaveLength(0);
|
|
91
|
-
db.close();
|
|
92
|
-
});
|
|
93
|
-
test('should handle empty synonyms gracefully', () => {
|
|
94
|
-
const synonyms = loadSynonyms({});
|
|
95
|
-
const query = expandQuery('database', synonyms).join(' ');
|
|
96
|
-
expect(query).toBe('database');
|
|
97
|
-
const db = new better_sqlite3_1.default(DB_PATH, { readonly: true });
|
|
98
|
-
const results = hybridSearch(db, query, { maxResults: 3 });
|
|
99
|
-
expect(results.length).toBeGreaterThan(0);
|
|
100
|
-
db.close();
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
//# sourceMappingURL=search-cli-hybrid.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"search-cli-hybrid.test.js","sourceRoot":"","sources":["../../tests/search-cli-hybrid.test.ts"],"names":[],"mappings":"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"}
|