@velvetmonkey/flywheel-memory 2.0.39 → 2.0.40
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 +43 -3
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3506,9 +3506,11 @@ var FEEDBACK_BOOST_TIERS = [
|
|
|
3506
3506
|
];
|
|
3507
3507
|
function recordFeedback(stateDb2, entity, context, notePath, correct) {
|
|
3508
3508
|
try {
|
|
3509
|
-
|
|
3509
|
+
console.error(`[Flywheel] recordFeedback: entity="${entity}" context="${context}" notePath="${notePath}" correct=${correct}`);
|
|
3510
|
+
const result = stateDb2.db.prepare(
|
|
3510
3511
|
"INSERT INTO wikilink_feedback (entity, context, note_path, correct) VALUES (?, ?, ?, ?)"
|
|
3511
3512
|
).run(entity, context, notePath, correct ? 1 : 0);
|
|
3513
|
+
console.error(`[Flywheel] recordFeedback: inserted id=${result.lastInsertRowid}`);
|
|
3512
3514
|
} catch (e) {
|
|
3513
3515
|
console.error(`[Flywheel] recordFeedback failed for entity="${entity}": ${e}`);
|
|
3514
3516
|
throw e;
|
|
@@ -5387,6 +5389,9 @@ function getEffectiveStrictness(notePath) {
|
|
|
5387
5389
|
function getCooccurrenceIndex() {
|
|
5388
5390
|
return cooccurrenceIndex;
|
|
5389
5391
|
}
|
|
5392
|
+
function setCooccurrenceIndex(index) {
|
|
5393
|
+
cooccurrenceIndex = index;
|
|
5394
|
+
}
|
|
5390
5395
|
var entityIndex = null;
|
|
5391
5396
|
var indexReady = false;
|
|
5392
5397
|
var indexError2 = null;
|
|
@@ -5502,6 +5507,11 @@ function checkAndRefreshIfStale() {
|
|
|
5502
5507
|
console.error(`[Flywheel] Reloaded ${dbIndex._metadata.total_entities} entities`);
|
|
5503
5508
|
}
|
|
5504
5509
|
}
|
|
5510
|
+
const freshRecency = loadRecencyFromStateDb();
|
|
5511
|
+
if (freshRecency && freshRecency.lastUpdated > (recencyIndex?.lastUpdated ?? 0)) {
|
|
5512
|
+
recencyIndex = freshRecency;
|
|
5513
|
+
console.error(`[Flywheel] Refreshed recency index (${freshRecency.lastMentioned.size} entities)`);
|
|
5514
|
+
}
|
|
5505
5515
|
} catch (e) {
|
|
5506
5516
|
console.error("[Flywheel] Failed to check for stale entities:", e);
|
|
5507
5517
|
}
|
|
@@ -12164,6 +12174,13 @@ function normalizeInput(content, format) {
|
|
|
12164
12174
|
normalized = trimmed;
|
|
12165
12175
|
changes.push("Trimmed excessive blank lines");
|
|
12166
12176
|
}
|
|
12177
|
+
const multiLineWikilink = /\[\[([^\]]*\n[^\]]*)\]\]/g;
|
|
12178
|
+
if (multiLineWikilink.test(normalized)) {
|
|
12179
|
+
normalized = normalized.replace(multiLineWikilink, (_match, inner) => {
|
|
12180
|
+
return "[[" + inner.replace(/\s*\n\s*/g, " ").trim() + "]]";
|
|
12181
|
+
});
|
|
12182
|
+
changes.push("Fixed multi-line wikilinks");
|
|
12183
|
+
}
|
|
12167
12184
|
return {
|
|
12168
12185
|
content: normalized,
|
|
12169
12186
|
normalized: changes.length > 0,
|
|
@@ -15413,9 +15430,11 @@ function registerWikilinkFeedbackTools(server2, getStateDb) {
|
|
|
15413
15430
|
let result;
|
|
15414
15431
|
switch (mode) {
|
|
15415
15432
|
case "report": {
|
|
15433
|
+
console.error(`[Flywheel] wikilink_feedback report: entity="${entity}" correct=${JSON.stringify(correct)} (type: ${typeof correct})`);
|
|
15416
15434
|
if (!entity || correct === void 0) {
|
|
15417
15435
|
return {
|
|
15418
|
-
content: [{ type: "text", text: JSON.stringify({ error: "entity and correct are required for report mode" }) }]
|
|
15436
|
+
content: [{ type: "text", text: JSON.stringify({ error: "entity and correct are required for report mode" }) }],
|
|
15437
|
+
isError: true
|
|
15419
15438
|
};
|
|
15420
15439
|
}
|
|
15421
15440
|
try {
|
|
@@ -15424,7 +15443,8 @@ function registerWikilinkFeedbackTools(server2, getStateDb) {
|
|
|
15424
15443
|
return {
|
|
15425
15444
|
content: [{ type: "text", text: JSON.stringify({
|
|
15426
15445
|
error: `Failed to record feedback: ${e instanceof Error ? e.message : String(e)}`
|
|
15427
|
-
}) }]
|
|
15446
|
+
}) }],
|
|
15447
|
+
isError: true
|
|
15428
15448
|
};
|
|
15429
15449
|
}
|
|
15430
15450
|
const suppressionUpdated = updateSuppressionList(stateDb2) > 0;
|
|
@@ -17083,6 +17103,7 @@ async function main() {
|
|
|
17083
17103
|
}
|
|
17084
17104
|
}
|
|
17085
17105
|
var DEFAULT_ENTITY_EXCLUDE_FOLDERS = ["node_modules", "templates", "attachments", "tmp"];
|
|
17106
|
+
var lastCooccurrenceRebuildAt = 0;
|
|
17086
17107
|
async function updateEntitiesInStateDb() {
|
|
17087
17108
|
if (!stateDb) return;
|
|
17088
17109
|
try {
|
|
@@ -17423,6 +17444,24 @@ async function runPostIndexWork(index) {
|
|
|
17423
17444
|
tracker.end({ error: String(e) });
|
|
17424
17445
|
serverLog("watcher", `Recency: failed: ${e}`);
|
|
17425
17446
|
}
|
|
17447
|
+
tracker.start("cooccurrence", { entity_count: entitiesAfter.length });
|
|
17448
|
+
try {
|
|
17449
|
+
const cooccurrenceAgeMs = lastCooccurrenceRebuildAt > 0 ? Date.now() - lastCooccurrenceRebuildAt : Infinity;
|
|
17450
|
+
if (cooccurrenceAgeMs >= 60 * 60 * 1e3) {
|
|
17451
|
+
const entityNames = entitiesAfter.map((e) => e.name);
|
|
17452
|
+
const cooccurrenceIdx = await mineCooccurrences(vaultPath, entityNames);
|
|
17453
|
+
setCooccurrenceIndex(cooccurrenceIdx);
|
|
17454
|
+
lastCooccurrenceRebuildAt = Date.now();
|
|
17455
|
+
tracker.end({ rebuilt: true, associations: cooccurrenceIdx._metadata.total_associations });
|
|
17456
|
+
serverLog("watcher", `Co-occurrence: rebuilt ${cooccurrenceIdx._metadata.total_associations} associations`);
|
|
17457
|
+
} else {
|
|
17458
|
+
tracker.end({ rebuilt: false, age_ms: cooccurrenceAgeMs });
|
|
17459
|
+
serverLog("watcher", `Co-occurrence: cache valid (${Math.round(cooccurrenceAgeMs / 1e3)}s old)`);
|
|
17460
|
+
}
|
|
17461
|
+
} catch (e) {
|
|
17462
|
+
tracker.end({ error: String(e) });
|
|
17463
|
+
serverLog("watcher", `Co-occurrence: failed: ${e}`);
|
|
17464
|
+
}
|
|
17426
17465
|
if (hasEmbeddingsIndex()) {
|
|
17427
17466
|
tracker.start("note_embeddings", { files: filteredEvents.length });
|
|
17428
17467
|
let embUpdated = 0;
|
|
@@ -17561,6 +17600,7 @@ async function runPostIndexWork(index) {
|
|
|
17561
17600
|
linkDiffs.push({ file: entry.file, ...diff });
|
|
17562
17601
|
}
|
|
17563
17602
|
updateStoredNoteLinks(stateDb, entry.file, currentSet);
|
|
17603
|
+
if (diff.removed.length === 0) continue;
|
|
17564
17604
|
for (const link of currentSet) {
|
|
17565
17605
|
if (!previousSet.has(link)) continue;
|
|
17566
17606
|
upsertHistory.run(entry.file, link);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velvetmonkey/flywheel-memory",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.40",
|
|
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.40",
|
|
56
56
|
"better-sqlite3": "^11.0.0",
|
|
57
57
|
"chokidar": "^4.0.0",
|
|
58
58
|
"gray-matter": "^4.0.3",
|