stellavault 0.8.1 → 0.8.2

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.
Files changed (2) hide show
  1. package/dist/stellavault.js +33 -27
  2. package/package.json +1 -1
@@ -49,7 +49,7 @@ function resolveSearchWeights(config, env = process.env) {
49
49
  const base = {
50
50
  semantic: config.search.weights?.semantic ?? 1,
51
51
  bm25: config.search.weights?.bm25 ?? 1,
52
- entity: config.search.weights?.entity ?? 0.5,
52
+ entity: config.search.weights?.entity ?? 1.5,
53
53
  recency: config.search.recencyWeight ?? 0.2
54
54
  };
55
55
  const parse = (raw, min, max) => {
@@ -94,8 +94,8 @@ var init_config = __esm({
94
94
  search: {
95
95
  defaultLimit: 10,
96
96
  rrfK: 60,
97
- weights: { semantic: 1, bm25: 1, entity: 0.5 },
98
- // B3 §1.2
97
+ weights: { semantic: 1, bm25: 1, entity: 1.5 },
98
+ // B2.1: entity leads (per-doc cap prevents flooding)
99
99
  recencyWeight: 0.2
100
100
  // B3 §1.3 (±10% bound)
101
101
  },
@@ -3910,30 +3910,34 @@ function createSqliteVecStore(dbPath, dimensions = 384) {
3910
3910
  return [];
3911
3911
  const exactPH = entities.map(() => "?").join(",");
3912
3912
  const fuzzy = entities.filter((t2) => t2.length >= 4 && (/\s/.test(t2) || /[^\x00-\x7f]/.test(t2) || t2.length >= 6)).slice(0, 16);
3913
+ let matched;
3914
+ let matchedParams;
3913
3915
  if (fuzzy.length === 0) {
3914
- const rows2 = db.prepare(`
3915
- SELECT chunk_id, COUNT(*) AS score
3916
- FROM chunk_entities
3917
- WHERE entity IN (${exactPH})
3918
- GROUP BY chunk_id
3919
- ORDER BY score DESC
3920
- LIMIT ?
3921
- `).all(...entities, limit);
3922
- return rows2.map((r) => ({ chunkId: r.chunk_id, score: r.score }));
3923
- }
3924
- const esc = (t2) => t2.replace(/[\\%_]/g, "\\$&");
3925
- const likeClause = fuzzy.map(() => `entity LIKE ? ESCAPE '\\'`).join(" OR ");
3916
+ matched = `SELECT chunk_id, CAST(COUNT(*) AS REAL) AS score FROM chunk_entities WHERE entity IN (${exactPH}) GROUP BY chunk_id`;
3917
+ matchedParams = [...entities];
3918
+ } else {
3919
+ const esc = (t2) => t2.replace(/[\\%_]/g, "\\$&");
3920
+ const likeClause = fuzzy.map(() => `entity LIKE ? ESCAPE '\\'`).join(" OR ");
3921
+ matched = `
3922
+ SELECT chunk_id, SUM(w) AS score FROM (
3923
+ SELECT chunk_id, 1.0 AS w FROM chunk_entities WHERE entity IN (${exactPH})
3924
+ UNION ALL
3925
+ SELECT chunk_id, 0.4 AS w FROM chunk_entities
3926
+ WHERE (${likeClause}) AND entity NOT IN (${exactPH})
3927
+ ) GROUP BY chunk_id`;
3928
+ matchedParams = [...entities, ...fuzzy.map((t2) => `%${esc(t2)}%`), ...entities];
3929
+ }
3926
3930
  const rows = db.prepare(`
3927
- SELECT chunk_id, SUM(w) AS score FROM (
3928
- SELECT chunk_id, 1.0 AS w FROM chunk_entities WHERE entity IN (${exactPH})
3929
- UNION ALL
3930
- SELECT chunk_id, 0.4 AS w FROM chunk_entities
3931
- WHERE (${likeClause}) AND entity NOT IN (${exactPH})
3931
+ SELECT chunk_id, score FROM (
3932
+ SELECT m.chunk_id AS chunk_id, m.score AS score,
3933
+ ROW_NUMBER() OVER (PARTITION BY c.document_id ORDER BY m.score DESC, m.chunk_id) AS rn
3934
+ FROM (${matched}) m
3935
+ JOIN chunks c ON c.id = m.chunk_id
3932
3936
  )
3933
- GROUP BY chunk_id
3934
- ORDER BY score DESC
3937
+ WHERE rn <= 2
3938
+ ORDER BY score DESC, chunk_id
3935
3939
  LIMIT ?
3936
- `).all(...entities, ...fuzzy.map((t2) => `%${esc(t2)}%`), ...entities, limit);
3940
+ `).all(...matchedParams, limit);
3937
3941
  return rows.map((r) => ({ chunkId: r.chunk_id, score: r.score }));
3938
3942
  },
3939
3943
  async getDocument(documentId) {
@@ -4229,8 +4233,10 @@ function createAdaptiveSearch(deps) {
4229
4233
  var DEFAULT_SIGNAL_WEIGHTS = {
4230
4234
  semantic: 1,
4231
4235
  bm25: 1,
4232
- entity: 0.5,
4233
- // conservative: ~20% candidate coverage (arxiv 2508.01405)
4236
+ entity: 1.5,
4237
+ // B2.1: leading curated-graph signal. Per-doc cap in searchEntities
4238
+ // prevents one large note flooding top-k. Tune via STELLAVAULT_W_ENTITY
4239
+ // (e.g. 2.0 for aggressive project-name surfacing, 0.5 for conservative).
4234
4240
  recency: 0.2
4235
4241
  // ±10% bound on relevance
4236
4242
  };
@@ -5751,7 +5757,7 @@ function createMcpServer(options) {
5751
5757
  const askTool = createAskTool(searchEngine, vaultPath);
5752
5758
  const generateDraftTool = createGenerateDraftTool(searchEngine, vaultPath);
5753
5759
  const agenticTools = embedder ? createAgenticGraphTools(store, embedder, vaultPath) : [];
5754
- const server = new Server({ name: "stellavault", version: "0.8.1" }, { capabilities: { tools: {} } });
5760
+ const server = new Server({ name: "stellavault", version: "0.8.2" }, { capabilities: { tools: {} } });
5755
5761
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
5756
5762
  tools: [
5757
5763
  searchToolDef,
@@ -10928,7 +10934,7 @@ if (nodeVersion < 20) {
10928
10934
  process.exit(1);
10929
10935
  }
10930
10936
  var program = new Command();
10931
- var SV_VERSION = true ? "0.8.1" : "0.0.0-dev";
10937
+ var SV_VERSION = true ? "0.8.2" : "0.0.0-dev";
10932
10938
  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");
10933
10939
  program.command("init").description("Interactive setup wizard \u2014 get started in 3 minutes").action(initCommand);
10934
10940
  program.command("doctor").description("Diagnose setup issues (config, vault, DB, model, Node version)").action(doctorCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stellavault",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "description": "Drop anything. It compiles itself into knowledge. Claude remembers everything you know. Local-first MCP server, vault files never modified.",
5
5
  "repository": {
6
6
  "type": "git",