@velvetmonkey/flywheel-memory 2.0.37 → 2.0.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/dist/index.js +55 -4
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -6986,7 +6986,7 @@ function refreshIfStale(vaultPath2, index, excludeTags) {
|
|
|
6986
6986
|
}
|
|
6987
6987
|
|
|
6988
6988
|
// src/index.ts
|
|
6989
|
-
import { openStateDb, scanVaultEntities as scanVaultEntities3, getSessionId, getAllEntitiesFromDb as getAllEntitiesFromDb3 } from "@velvetmonkey/vault-core";
|
|
6989
|
+
import { openStateDb, scanVaultEntities as scanVaultEntities3, getSessionId, getAllEntitiesFromDb as getAllEntitiesFromDb3, findEntityMatches as findEntityMatches2, getProtectedZones as getProtectedZones2, rangeOverlapsProtectedZone } from "@velvetmonkey/vault-core";
|
|
6990
6990
|
|
|
6991
6991
|
// src/tools/read/graph.ts
|
|
6992
6992
|
import * as fs9 from "fs";
|
|
@@ -17533,6 +17533,10 @@ async function runPostIndexWork(index) {
|
|
|
17533
17533
|
const markPositive = stateDb.db.prepare(`
|
|
17534
17534
|
UPDATE note_link_history SET last_positive_at = datetime('now') WHERE note_path = ? AND target = ?
|
|
17535
17535
|
`);
|
|
17536
|
+
const getEdgeCount = stateDb.db.prepare(
|
|
17537
|
+
"SELECT edits_survived FROM note_link_history WHERE note_path=? AND target=?"
|
|
17538
|
+
);
|
|
17539
|
+
const survivedLinks2 = [];
|
|
17536
17540
|
for (const entry of forwardLinkResults) {
|
|
17537
17541
|
const currentSet = /* @__PURE__ */ new Set([
|
|
17538
17542
|
...entry.resolved.map((n) => n.toLowerCase()),
|
|
@@ -17551,6 +17555,10 @@ async function runPostIndexWork(index) {
|
|
|
17551
17555
|
for (const link of currentSet) {
|
|
17552
17556
|
if (!previousSet.has(link)) continue;
|
|
17553
17557
|
upsertHistory.run(entry.file, link);
|
|
17558
|
+
const countRow = getEdgeCount.get(entry.file, link);
|
|
17559
|
+
if (countRow) {
|
|
17560
|
+
survivedLinks2.push({ entity: link, file: entry.file, count: countRow.edits_survived });
|
|
17561
|
+
}
|
|
17554
17562
|
const hit = checkThreshold.get(entry.file, link);
|
|
17555
17563
|
if (hit) {
|
|
17556
17564
|
const entity = entitiesAfter.find(
|
|
@@ -17572,12 +17580,23 @@ async function runPostIndexWork(index) {
|
|
|
17572
17580
|
}
|
|
17573
17581
|
}
|
|
17574
17582
|
}
|
|
17583
|
+
const processedFiles = new Set(forwardLinkResults.map((r) => r.file));
|
|
17584
|
+
for (const event of filteredEvents) {
|
|
17585
|
+
if (event.type === "delete" || !event.path.endsWith(".md")) continue;
|
|
17586
|
+
if (processedFiles.has(event.path)) continue;
|
|
17587
|
+
const previousSet = getStoredNoteLinks(stateDb, event.path);
|
|
17588
|
+
if (previousSet.size > 0) {
|
|
17589
|
+
linkDiffs.push({ file: event.path, added: [], removed: [...previousSet] });
|
|
17590
|
+
updateStoredNoteLinks(stateDb, event.path, /* @__PURE__ */ new Set());
|
|
17591
|
+
}
|
|
17592
|
+
}
|
|
17575
17593
|
}
|
|
17576
17594
|
tracker.end({
|
|
17577
17595
|
total_resolved: totalResolved,
|
|
17578
17596
|
total_dead: totalDead,
|
|
17579
17597
|
links: forwardLinkResults,
|
|
17580
|
-
link_diffs: linkDiffs
|
|
17598
|
+
link_diffs: linkDiffs,
|
|
17599
|
+
survived: survivedLinks
|
|
17581
17600
|
});
|
|
17582
17601
|
serverLog("watcher", `Forward links: ${totalResolved} resolved, ${totalDead} dead`);
|
|
17583
17602
|
tracker.start("wikilink_check", { files: filteredEvents.length });
|
|
@@ -17607,8 +17626,40 @@ async function runPostIndexWork(index) {
|
|
|
17607
17626
|
trackedLinks.push({ file: diff.file, entities: diff.added });
|
|
17608
17627
|
}
|
|
17609
17628
|
}
|
|
17610
|
-
|
|
17611
|
-
|
|
17629
|
+
const mentionResults = [];
|
|
17630
|
+
for (const event of filteredEvents) {
|
|
17631
|
+
if (event.type === "delete" || !event.path.endsWith(".md")) continue;
|
|
17632
|
+
try {
|
|
17633
|
+
const content = await fs30.readFile(path31.join(vaultPath, event.path), "utf-8");
|
|
17634
|
+
const zones = getProtectedZones2(content);
|
|
17635
|
+
const linked = new Set(
|
|
17636
|
+
(forwardLinkResults.find((r) => r.file === event.path)?.resolved ?? []).map((n) => n.toLowerCase())
|
|
17637
|
+
);
|
|
17638
|
+
const mentions = [];
|
|
17639
|
+
for (const entity of entitiesAfter) {
|
|
17640
|
+
if (linked.has(entity.nameLower)) continue;
|
|
17641
|
+
const matches = findEntityMatches2(content, entity.name, true);
|
|
17642
|
+
const valid = matches.some((m) => !rangeOverlapsProtectedZone(m.start, m.end, zones));
|
|
17643
|
+
if (valid) {
|
|
17644
|
+
mentions.push(entity.name);
|
|
17645
|
+
continue;
|
|
17646
|
+
}
|
|
17647
|
+
for (const alias of entity.aliases ?? []) {
|
|
17648
|
+
const aliasMatches = findEntityMatches2(content, alias, true);
|
|
17649
|
+
if (aliasMatches.some((m) => !rangeOverlapsProtectedZone(m.start, m.end, zones))) {
|
|
17650
|
+
mentions.push(entity.name);
|
|
17651
|
+
break;
|
|
17652
|
+
}
|
|
17653
|
+
}
|
|
17654
|
+
}
|
|
17655
|
+
if (mentions.length > 0) {
|
|
17656
|
+
mentionResults.push({ file: event.path, entities: mentions });
|
|
17657
|
+
}
|
|
17658
|
+
} catch {
|
|
17659
|
+
}
|
|
17660
|
+
}
|
|
17661
|
+
tracker.end({ tracked: trackedLinks, mentions: mentionResults });
|
|
17662
|
+
serverLog("watcher", `Wikilink check: ${trackedLinks.reduce((s, t) => s + t.entities.length, 0)} tracked links in ${trackedLinks.length} files, ${mentionResults.reduce((s, m) => s + m.entities.length, 0)} unwikified mentions`);
|
|
17612
17663
|
tracker.start("implicit_feedback", { files: filteredEvents.length });
|
|
17613
17664
|
const feedbackResults = [];
|
|
17614
17665
|
if (stateDb) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velvetmonkey/flywheel-memory",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.38",
|
|
4
4
|
"description": "MCP server that gives Claude full read/write access to your Obsidian vault. 42 tools for search, backlinks, graph queries, mutations, and hybrid semantic search.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
55
|
-
"@velvetmonkey/vault-core": "^2.0.
|
|
55
|
+
"@velvetmonkey/vault-core": "^2.0.38",
|
|
56
56
|
"better-sqlite3": "^11.0.0",
|
|
57
57
|
"chokidar": "^4.0.0",
|
|
58
58
|
"gray-matter": "^4.0.3",
|