stellavault 0.8.2 → 0.8.3
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/stellavault.js +56 -14
- package/package.json +1 -1
package/dist/stellavault.js
CHANGED
|
@@ -40,7 +40,9 @@ function mergeConfig(defaults, overrides) {
|
|
|
40
40
|
...defaults.search,
|
|
41
41
|
...overrides.search,
|
|
42
42
|
// B3 §4 — deep-merge weights so a partial override keeps the other defaults.
|
|
43
|
-
weights: { ...defaults.search.weights, ...overrides.search?.weights }
|
|
43
|
+
weights: { ...defaults.search.weights, ...overrides.search?.weights },
|
|
44
|
+
// B2.2 — merge alias groups (override wins per-key).
|
|
45
|
+
entityAliases: { ...defaults.search.entityAliases, ...overrides.search?.entityAliases }
|
|
44
46
|
},
|
|
45
47
|
mcp: { ...defaults.mcp, ...overrides.mcp }
|
|
46
48
|
};
|
|
@@ -96,8 +98,10 @@ var init_config = __esm({
|
|
|
96
98
|
rrfK: 60,
|
|
97
99
|
weights: { semantic: 1, bm25: 1, entity: 1.5 },
|
|
98
100
|
// B2.1: entity leads (per-doc cap prevents flooding)
|
|
99
|
-
recencyWeight: 0.2
|
|
101
|
+
recencyWeight: 0.2,
|
|
100
102
|
// B3 §1.3 (±10% bound)
|
|
103
|
+
entityAliases: {}
|
|
104
|
+
// B2.2 — user-defined synonym groups
|
|
101
105
|
},
|
|
102
106
|
mcp: {
|
|
103
107
|
mode: "stdio",
|
|
@@ -496,6 +500,34 @@ function extractQueryTerms(query) {
|
|
|
496
500
|
}
|
|
497
501
|
return [...set].slice(0, MAX_QUERY_TERMS);
|
|
498
502
|
}
|
|
503
|
+
function buildAliasIndex(aliases) {
|
|
504
|
+
const index = /* @__PURE__ */ new Map();
|
|
505
|
+
if (!aliases)
|
|
506
|
+
return index;
|
|
507
|
+
for (const [key, arr] of Object.entries(aliases)) {
|
|
508
|
+
const group = [normalize(key), ...(Array.isArray(arr) ? arr : []).map(normalize)].filter(Boolean);
|
|
509
|
+
const uniq = [...new Set(group)];
|
|
510
|
+
if (uniq.length < 2)
|
|
511
|
+
continue;
|
|
512
|
+
for (const term of uniq) {
|
|
513
|
+
const others = uniq.filter((t2) => t2 !== term);
|
|
514
|
+
index.set(term, [.../* @__PURE__ */ new Set([...index.get(term) ?? [], ...others])]);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return index;
|
|
518
|
+
}
|
|
519
|
+
function expandWithAliases(terms, aliasIndex) {
|
|
520
|
+
if (!aliasIndex || aliasIndex.size === 0)
|
|
521
|
+
return terms;
|
|
522
|
+
const out = new Set(terms);
|
|
523
|
+
for (const t2 of terms) {
|
|
524
|
+
const syn = aliasIndex.get(t2);
|
|
525
|
+
if (syn)
|
|
526
|
+
for (const s of syn)
|
|
527
|
+
out.add(s);
|
|
528
|
+
}
|
|
529
|
+
return [...out].slice(0, MAX_QUERY_TERMS);
|
|
530
|
+
}
|
|
499
531
|
var MAX_ENTITIES_PER_CHUNK, MAX_QUERY_TERMS, STOPWORDS;
|
|
500
532
|
var init_entity_extractor = __esm({
|
|
501
533
|
"packages/core/dist/indexer/entity-extractor.js"() {
|
|
@@ -3905,16 +3937,17 @@ function createSqliteVecStore(dbPath, dimensions = 384) {
|
|
|
3905
3937
|
// FTS5 rank is negative (lower = better)
|
|
3906
3938
|
}));
|
|
3907
3939
|
},
|
|
3908
|
-
async searchEntities(entities, limit) {
|
|
3909
|
-
if (!entities || entities.length === 0)
|
|
3940
|
+
async searchEntities(entities, limit, exactExtra = []) {
|
|
3941
|
+
if ((!entities || entities.length === 0) && exactExtra.length === 0)
|
|
3910
3942
|
return [];
|
|
3911
|
-
const
|
|
3943
|
+
const allExact = [...entities, ...exactExtra];
|
|
3944
|
+
const exactPH = allExact.map(() => "?").join(",");
|
|
3912
3945
|
const fuzzy = entities.filter((t2) => t2.length >= 4 && (/\s/.test(t2) || /[^\x00-\x7f]/.test(t2) || t2.length >= 6)).slice(0, 16);
|
|
3913
3946
|
let matched;
|
|
3914
3947
|
let matchedParams;
|
|
3915
3948
|
if (fuzzy.length === 0) {
|
|
3916
3949
|
matched = `SELECT chunk_id, CAST(COUNT(*) AS REAL) AS score FROM chunk_entities WHERE entity IN (${exactPH}) GROUP BY chunk_id`;
|
|
3917
|
-
matchedParams = [...
|
|
3950
|
+
matchedParams = [...allExact];
|
|
3918
3951
|
} else {
|
|
3919
3952
|
const esc = (t2) => t2.replace(/[\\%_]/g, "\\$&");
|
|
3920
3953
|
const likeClause = fuzzy.map(() => `entity LIKE ? ESCAPE '\\'`).join(" OR ");
|
|
@@ -3925,7 +3958,7 @@ function createSqliteVecStore(dbPath, dimensions = 384) {
|
|
|
3925
3958
|
SELECT chunk_id, 0.4 AS w FROM chunk_entities
|
|
3926
3959
|
WHERE (${likeClause}) AND entity NOT IN (${exactPH})
|
|
3927
3960
|
) GROUP BY chunk_id`;
|
|
3928
|
-
matchedParams = [...
|
|
3961
|
+
matchedParams = [...allExact, ...fuzzy.map((t2) => `%${esc(t2)}%`), ...allExact];
|
|
3929
3962
|
}
|
|
3930
3963
|
const rows = db.prepare(`
|
|
3931
3964
|
SELECT chunk_id, score FROM (
|
|
@@ -4143,13 +4176,14 @@ async function searchSemantic(store, embedder, query, limit) {
|
|
|
4143
4176
|
|
|
4144
4177
|
// packages/core/dist/search/entity.js
|
|
4145
4178
|
init_entity_extractor();
|
|
4146
|
-
async function searchEntities(store, query, limit) {
|
|
4179
|
+
async function searchEntities(store, query, limit, aliasIndex) {
|
|
4147
4180
|
if (typeof store.searchEntities !== "function")
|
|
4148
4181
|
return [];
|
|
4149
4182
|
const terms = extractQueryTerms(query);
|
|
4150
4183
|
if (terms.length === 0)
|
|
4151
4184
|
return [];
|
|
4152
|
-
|
|
4185
|
+
const aliasExact = expandWithAliases(terms, aliasIndex).filter((t2) => !terms.includes(t2));
|
|
4186
|
+
return store.searchEntities(terms, limit, aliasExact);
|
|
4153
4187
|
}
|
|
4154
4188
|
|
|
4155
4189
|
// packages/core/dist/search/rrf.js
|
|
@@ -4173,6 +4207,9 @@ function rrfFusionN(lists, k = 60, limit = 10, opts = {}) {
|
|
|
4173
4207
|
return [...scores.entries()].sort((a, b) => b[1] - a[1]).slice(0, limit).map(([chunkId, score]) => ({ chunkId, score }));
|
|
4174
4208
|
}
|
|
4175
4209
|
|
|
4210
|
+
// packages/core/dist/search/index.js
|
|
4211
|
+
init_entity_extractor();
|
|
4212
|
+
|
|
4176
4213
|
// packages/core/dist/search/adaptive.js
|
|
4177
4214
|
function createAdaptiveSearch(deps) {
|
|
4178
4215
|
const { baseSearch } = deps;
|
|
@@ -4243,6 +4280,7 @@ var DEFAULT_SIGNAL_WEIGHTS = {
|
|
|
4243
4280
|
function createSearchEngine(deps) {
|
|
4244
4281
|
const { store, embedder, rrfK = 60, getDecayEngine } = deps;
|
|
4245
4282
|
const baseWeights = { ...DEFAULT_SIGNAL_WEIGHTS, ...deps.weights };
|
|
4283
|
+
const aliasIndex = buildAliasIndex(deps.entityAliases);
|
|
4246
4284
|
const FETCH_LIMIT = 30;
|
|
4247
4285
|
return {
|
|
4248
4286
|
async search(options) {
|
|
@@ -4251,7 +4289,7 @@ function createSearchEngine(deps) {
|
|
|
4251
4289
|
const [bm25Results, semanticResults, entityResults] = await Promise.all([
|
|
4252
4290
|
searchBm25(store, query, FETCH_LIMIT),
|
|
4253
4291
|
searchSemantic(store, embedder, query, FETCH_LIMIT),
|
|
4254
|
-
searchEntities(store, query, FETCH_LIMIT)
|
|
4292
|
+
searchEntities(store, query, FETCH_LIMIT, aliasIndex)
|
|
4255
4293
|
]);
|
|
4256
4294
|
const lists = [semanticResults, bm25Results, entityResults];
|
|
4257
4295
|
const weights = [w.semantic, w.bm25, w.entity];
|
|
@@ -5757,7 +5795,7 @@ function createMcpServer(options) {
|
|
|
5757
5795
|
const askTool = createAskTool(searchEngine, vaultPath);
|
|
5758
5796
|
const generateDraftTool = createGenerateDraftTool(searchEngine, vaultPath);
|
|
5759
5797
|
const agenticTools = embedder ? createAgenticGraphTools(store, embedder, vaultPath) : [];
|
|
5760
|
-
const server = new Server({ name: "stellavault", version: "0.8.
|
|
5798
|
+
const server = new Server({ name: "stellavault", version: "0.8.3" }, { capabilities: { tools: {} } });
|
|
5761
5799
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
5762
5800
|
tools: [
|
|
5763
5801
|
searchToolDef,
|
|
@@ -7963,7 +8001,9 @@ function createKnowledgeHub(config, options = {}) {
|
|
|
7963
8001
|
embedder,
|
|
7964
8002
|
rrfK: config.search.rrfK,
|
|
7965
8003
|
weights: { semantic: sw.semantic, bm25: sw.bm25, entity: sw.entity, recency: sw.recency },
|
|
7966
|
-
getDecayEngine
|
|
8004
|
+
getDecayEngine,
|
|
8005
|
+
entityAliases: config.search.entityAliases
|
|
8006
|
+
// B2.2 — cross-lingual/synonym groups
|
|
7967
8007
|
});
|
|
7968
8008
|
const mcpServer = createMcpServer({ store, searchEngine, vaultPath: config.vaultPath, ready: options.ready });
|
|
7969
8009
|
return { store, embedder, searchEngine, mcpServer, config };
|
|
@@ -8100,7 +8140,9 @@ async function searchCommand(query, options, cmd) {
|
|
|
8100
8140
|
store,
|
|
8101
8141
|
embedder,
|
|
8102
8142
|
rrfK: config.search.rrfK,
|
|
8103
|
-
weights: { semantic: sw.semantic, bm25: sw.bm25, entity: sw.entity, recency: sw.recency }
|
|
8143
|
+
weights: { semantic: sw.semantic, bm25: sw.bm25, entity: sw.entity, recency: sw.recency },
|
|
8144
|
+
entityAliases: config.search.entityAliases
|
|
8145
|
+
// B2.2
|
|
8104
8146
|
});
|
|
8105
8147
|
const results = await engine.search({ query, limit });
|
|
8106
8148
|
await store.close();
|
|
@@ -10934,7 +10976,7 @@ if (nodeVersion < 20) {
|
|
|
10934
10976
|
process.exit(1);
|
|
10935
10977
|
}
|
|
10936
10978
|
var program = new Command();
|
|
10937
|
-
var SV_VERSION = true ? "0.8.
|
|
10979
|
+
var SV_VERSION = true ? "0.8.3" : "0.0.0-dev";
|
|
10938
10980
|
program.name("stellavault").description("Stellavault \u2014 Self-compiling knowledge base for your Obsidian vault").version(SV_VERSION).option("--json", "Output in JSON format (for scripting)").option("--quiet", "Suppress non-essential output");
|
|
10939
10981
|
program.command("init").description("Interactive setup wizard \u2014 get started in 3 minutes").action(initCommand);
|
|
10940
10982
|
program.command("doctor").description("Diagnose setup issues (config, vault, DB, model, Node version)").action(doctorCommand);
|
package/package.json
CHANGED