@velvetmonkey/flywheel-memory 2.0.16 → 2.0.18
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 +218 -85
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1426,7 +1426,6 @@ var init_taskHelpers = __esm({
|
|
|
1426
1426
|
// src/index.ts
|
|
1427
1427
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1428
1428
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
1429
|
-
import chokidar2 from "chokidar";
|
|
1430
1429
|
|
|
1431
1430
|
// src/core/read/vault.ts
|
|
1432
1431
|
import * as fs from "fs";
|
|
@@ -6187,9 +6186,84 @@ function getActivitySummary(index, days) {
|
|
|
6187
6186
|
};
|
|
6188
6187
|
}
|
|
6189
6188
|
|
|
6189
|
+
// src/core/shared/indexActivity.ts
|
|
6190
|
+
function recordIndexEvent(stateDb2, event) {
|
|
6191
|
+
stateDb2.db.prepare(
|
|
6192
|
+
`INSERT INTO index_events (timestamp, trigger, duration_ms, success, note_count, files_changed, changed_paths, error)
|
|
6193
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
|
|
6194
|
+
).run(
|
|
6195
|
+
Date.now(),
|
|
6196
|
+
event.trigger,
|
|
6197
|
+
event.duration_ms,
|
|
6198
|
+
event.success !== false ? 1 : 0,
|
|
6199
|
+
event.note_count ?? null,
|
|
6200
|
+
event.files_changed ?? null,
|
|
6201
|
+
event.changed_paths ? JSON.stringify(event.changed_paths) : null,
|
|
6202
|
+
event.error ?? null
|
|
6203
|
+
);
|
|
6204
|
+
}
|
|
6205
|
+
function rowToEvent(row) {
|
|
6206
|
+
return {
|
|
6207
|
+
id: row.id,
|
|
6208
|
+
timestamp: row.timestamp,
|
|
6209
|
+
trigger: row.trigger,
|
|
6210
|
+
duration_ms: row.duration_ms,
|
|
6211
|
+
success: row.success === 1,
|
|
6212
|
+
note_count: row.note_count,
|
|
6213
|
+
files_changed: row.files_changed,
|
|
6214
|
+
changed_paths: row.changed_paths ? JSON.parse(row.changed_paths) : null,
|
|
6215
|
+
error: row.error
|
|
6216
|
+
};
|
|
6217
|
+
}
|
|
6218
|
+
function getRecentIndexEvents(stateDb2, limit = 20) {
|
|
6219
|
+
const rows = stateDb2.db.prepare(
|
|
6220
|
+
"SELECT * FROM index_events ORDER BY timestamp DESC LIMIT ?"
|
|
6221
|
+
).all(limit);
|
|
6222
|
+
return rows.map(rowToEvent);
|
|
6223
|
+
}
|
|
6224
|
+
function getIndexActivitySummary(stateDb2) {
|
|
6225
|
+
const now = Date.now();
|
|
6226
|
+
const todayStart = /* @__PURE__ */ new Date();
|
|
6227
|
+
todayStart.setHours(0, 0, 0, 0);
|
|
6228
|
+
const last24h = now - 24 * 60 * 60 * 1e3;
|
|
6229
|
+
const totalRow = stateDb2.db.prepare(
|
|
6230
|
+
"SELECT COUNT(*) as count FROM index_events"
|
|
6231
|
+
).get();
|
|
6232
|
+
const todayRow = stateDb2.db.prepare(
|
|
6233
|
+
"SELECT COUNT(*) as count FROM index_events WHERE timestamp >= ?"
|
|
6234
|
+
).get(todayStart.getTime());
|
|
6235
|
+
const last24hRow = stateDb2.db.prepare(
|
|
6236
|
+
"SELECT COUNT(*) as count FROM index_events WHERE timestamp >= ?"
|
|
6237
|
+
).get(last24h);
|
|
6238
|
+
const avgRow = stateDb2.db.prepare(
|
|
6239
|
+
"SELECT AVG(duration_ms) as avg_ms FROM index_events WHERE success = 1"
|
|
6240
|
+
).get();
|
|
6241
|
+
const failureRow = stateDb2.db.prepare(
|
|
6242
|
+
"SELECT COUNT(*) as count FROM index_events WHERE success = 0"
|
|
6243
|
+
).get();
|
|
6244
|
+
const lastRow = stateDb2.db.prepare(
|
|
6245
|
+
"SELECT * FROM index_events ORDER BY timestamp DESC LIMIT 1"
|
|
6246
|
+
).get();
|
|
6247
|
+
return {
|
|
6248
|
+
total_rebuilds: totalRow.count,
|
|
6249
|
+
last_rebuild: lastRow ? rowToEvent(lastRow) : null,
|
|
6250
|
+
rebuilds_today: todayRow.count,
|
|
6251
|
+
rebuilds_last_24h: last24hRow.count,
|
|
6252
|
+
avg_duration_ms: Math.round(avgRow.avg_ms ?? 0),
|
|
6253
|
+
failure_count: failureRow.count
|
|
6254
|
+
};
|
|
6255
|
+
}
|
|
6256
|
+
function purgeOldIndexEvents(stateDb2, retentionDays = 90) {
|
|
6257
|
+
const cutoff = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
|
|
6258
|
+
const result = stateDb2.db.prepare(
|
|
6259
|
+
"DELETE FROM index_events WHERE timestamp < ?"
|
|
6260
|
+
).run(cutoff);
|
|
6261
|
+
return result.changes;
|
|
6262
|
+
}
|
|
6263
|
+
|
|
6190
6264
|
// src/tools/read/health.ts
|
|
6191
6265
|
var STALE_THRESHOLD_SECONDS = 300;
|
|
6192
|
-
function registerHealthTools(server2, getIndex, getVaultPath, getConfig = () => ({})) {
|
|
6266
|
+
function registerHealthTools(server2, getIndex, getVaultPath, getConfig = () => ({}), getStateDb = () => null) {
|
|
6193
6267
|
const IndexProgressSchema = z3.object({
|
|
6194
6268
|
parsed: z3.coerce.number().describe("Number of files parsed so far"),
|
|
6195
6269
|
total: z3.coerce.number().describe("Total number of files to parse")
|
|
@@ -6217,6 +6291,12 @@ function registerHealthTools(server2, getIndex, getVaultPath, getConfig = () =>
|
|
|
6217
6291
|
tag_count: z3.coerce.number().describe("Number of unique tags"),
|
|
6218
6292
|
periodic_notes: z3.array(PeriodicNoteInfoSchema).optional().describe("Detected periodic note conventions"),
|
|
6219
6293
|
config: z3.record(z3.unknown()).optional().describe("Current flywheel config (paths, templates, etc.)"),
|
|
6294
|
+
last_rebuild: z3.object({
|
|
6295
|
+
trigger: z3.string(),
|
|
6296
|
+
timestamp: z3.number(),
|
|
6297
|
+
duration_ms: z3.number(),
|
|
6298
|
+
ago_seconds: z3.number()
|
|
6299
|
+
}).optional().describe("Most recent index rebuild event"),
|
|
6220
6300
|
recommendations: z3.array(z3.string()).describe("Suggested actions if any issues detected")
|
|
6221
6301
|
};
|
|
6222
6302
|
server2.registerTool(
|
|
@@ -6285,6 +6365,23 @@ function registerHealthTools(server2, getIndex, getVaultPath, getConfig = () =>
|
|
|
6285
6365
|
}
|
|
6286
6366
|
const config = getConfig();
|
|
6287
6367
|
const configInfo = Object.keys(config).length > 0 ? config : void 0;
|
|
6368
|
+
let lastRebuild;
|
|
6369
|
+
const stateDb2 = getStateDb();
|
|
6370
|
+
if (stateDb2) {
|
|
6371
|
+
try {
|
|
6372
|
+
const events = getRecentIndexEvents(stateDb2, 1);
|
|
6373
|
+
if (events.length > 0) {
|
|
6374
|
+
const event = events[0];
|
|
6375
|
+
lastRebuild = {
|
|
6376
|
+
trigger: event.trigger,
|
|
6377
|
+
timestamp: event.timestamp,
|
|
6378
|
+
duration_ms: event.duration_ms,
|
|
6379
|
+
ago_seconds: Math.floor((Date.now() - event.timestamp) / 1e3)
|
|
6380
|
+
};
|
|
6381
|
+
}
|
|
6382
|
+
} catch {
|
|
6383
|
+
}
|
|
6384
|
+
}
|
|
6288
6385
|
const output = {
|
|
6289
6386
|
status,
|
|
6290
6387
|
vault_accessible: vaultAccessible,
|
|
@@ -6300,6 +6397,7 @@ function registerHealthTools(server2, getIndex, getVaultPath, getConfig = () =>
|
|
|
6300
6397
|
tag_count: tagCount,
|
|
6301
6398
|
periodic_notes: periodicNotes && periodicNotes.length > 0 ? periodicNotes : void 0,
|
|
6302
6399
|
config: configInfo,
|
|
6400
|
+
last_rebuild: lastRebuild,
|
|
6303
6401
|
recommendations
|
|
6304
6402
|
};
|
|
6305
6403
|
return {
|
|
@@ -6737,12 +6835,20 @@ function registerSystemTools(server2, getIndex, setIndex, getVaultPath, setConfi
|
|
|
6737
6835
|
} catch (err) {
|
|
6738
6836
|
console.error("[Flywheel] FTS5 rebuild failed:", err);
|
|
6739
6837
|
}
|
|
6838
|
+
const duration = Date.now() - startTime;
|
|
6839
|
+
if (stateDb2) {
|
|
6840
|
+
recordIndexEvent(stateDb2, {
|
|
6841
|
+
trigger: "manual_refresh",
|
|
6842
|
+
duration_ms: duration,
|
|
6843
|
+
note_count: newIndex.notes.size
|
|
6844
|
+
});
|
|
6845
|
+
}
|
|
6740
6846
|
const output = {
|
|
6741
6847
|
success: true,
|
|
6742
6848
|
notes_count: newIndex.notes.size,
|
|
6743
6849
|
entities_count: newIndex.entities.size,
|
|
6744
6850
|
fts5_notes: fts5Notes,
|
|
6745
|
-
duration_ms:
|
|
6851
|
+
duration_ms: duration
|
|
6746
6852
|
};
|
|
6747
6853
|
return {
|
|
6748
6854
|
content: [
|
|
@@ -6756,12 +6862,22 @@ function registerSystemTools(server2, getIndex, setIndex, getVaultPath, setConfi
|
|
|
6756
6862
|
} catch (err) {
|
|
6757
6863
|
setIndexState("error");
|
|
6758
6864
|
setIndexError(err instanceof Error ? err : new Error(String(err)));
|
|
6865
|
+
const duration = Date.now() - startTime;
|
|
6866
|
+
const stateDb2 = getStateDb?.();
|
|
6867
|
+
if (stateDb2) {
|
|
6868
|
+
recordIndexEvent(stateDb2, {
|
|
6869
|
+
trigger: "manual_refresh",
|
|
6870
|
+
duration_ms: duration,
|
|
6871
|
+
success: false,
|
|
6872
|
+
error: err instanceof Error ? err.message : String(err)
|
|
6873
|
+
});
|
|
6874
|
+
}
|
|
6759
6875
|
const output = {
|
|
6760
6876
|
success: false,
|
|
6761
6877
|
notes_count: 0,
|
|
6762
6878
|
entities_count: 0,
|
|
6763
6879
|
fts5_notes: 0,
|
|
6764
|
-
duration_ms:
|
|
6880
|
+
duration_ms: duration
|
|
6765
6881
|
};
|
|
6766
6882
|
return {
|
|
6767
6883
|
content: [
|
|
@@ -12377,14 +12493,15 @@ function registerMetricsTools(server2, getIndex, getStateDb) {
|
|
|
12377
12493
|
"vault_growth",
|
|
12378
12494
|
{
|
|
12379
12495
|
title: "Vault Growth",
|
|
12380
|
-
description: 'Track vault growth over time. Modes: "current" (live snapshot), "history" (time series), "trends" (deltas vs N days ago). Tracks 11 metrics: note_count, link_count, orphan_count, tag_count, entity_count, avg_links_per_note, link_density, connected_ratio, wikilink_accuracy, wikilink_feedback_volume, wikilink_suppressed_count.',
|
|
12496
|
+
description: 'Track vault growth over time. Modes: "current" (live snapshot), "history" (time series), "trends" (deltas vs N days ago), "index_activity" (rebuild history). Tracks 11 metrics: note_count, link_count, orphan_count, tag_count, entity_count, avg_links_per_note, link_density, connected_ratio, wikilink_accuracy, wikilink_feedback_volume, wikilink_suppressed_count.',
|
|
12381
12497
|
inputSchema: {
|
|
12382
|
-
mode: z21.enum(["current", "history", "trends"]).describe("Query mode: current snapshot, historical time series, or
|
|
12498
|
+
mode: z21.enum(["current", "history", "trends", "index_activity"]).describe("Query mode: current snapshot, historical time series, trend analysis, or index rebuild activity"),
|
|
12383
12499
|
metric: z21.string().optional().describe('Filter to specific metric (e.g., "note_count"). Omit for all metrics.'),
|
|
12384
|
-
days_back: z21.number().optional().describe("Number of days to look back for history/trends (default: 30)")
|
|
12500
|
+
days_back: z21.number().optional().describe("Number of days to look back for history/trends (default: 30)"),
|
|
12501
|
+
limit: z21.number().optional().describe("Number of recent events to return for index_activity mode (default: 20)")
|
|
12385
12502
|
}
|
|
12386
12503
|
},
|
|
12387
|
-
async ({ mode, metric, days_back }) => {
|
|
12504
|
+
async ({ mode, metric, days_back, limit: eventLimit }) => {
|
|
12388
12505
|
const index = getIndex();
|
|
12389
12506
|
const stateDb2 = getStateDb();
|
|
12390
12507
|
const daysBack = days_back ?? 30;
|
|
@@ -12426,6 +12543,20 @@ function registerMetricsTools(server2, getIndex, getStateDb) {
|
|
|
12426
12543
|
};
|
|
12427
12544
|
break;
|
|
12428
12545
|
}
|
|
12546
|
+
case "index_activity": {
|
|
12547
|
+
if (!stateDb2) {
|
|
12548
|
+
return {
|
|
12549
|
+
content: [{ type: "text", text: JSON.stringify({ error: "StateDb not available for index activity queries" }) }]
|
|
12550
|
+
};
|
|
12551
|
+
}
|
|
12552
|
+
const summary = getIndexActivitySummary(stateDb2);
|
|
12553
|
+
const recentEvents = getRecentIndexEvents(stateDb2, eventLimit ?? 20);
|
|
12554
|
+
result = {
|
|
12555
|
+
mode: "index_activity",
|
|
12556
|
+
index_activity: { summary, recent_events: recentEvents }
|
|
12557
|
+
};
|
|
12558
|
+
break;
|
|
12559
|
+
}
|
|
12429
12560
|
}
|
|
12430
12561
|
return {
|
|
12431
12562
|
content: [
|
|
@@ -12709,7 +12840,7 @@ if (_originalRegisterTool) {
|
|
|
12709
12840
|
}
|
|
12710
12841
|
var categoryList = Array.from(enabledCategories).sort().join(", ");
|
|
12711
12842
|
console.error(`[Memory] Tool categories: ${categoryList}`);
|
|
12712
|
-
registerHealthTools(server, () => vaultIndex, () => vaultPath, () => flywheelConfig);
|
|
12843
|
+
registerHealthTools(server, () => vaultIndex, () => vaultPath, () => flywheelConfig, () => stateDb);
|
|
12713
12844
|
registerSystemTools(
|
|
12714
12845
|
server,
|
|
12715
12846
|
() => vaultIndex,
|
|
@@ -12786,6 +12917,13 @@ async function main() {
|
|
|
12786
12917
|
setIndexState("ready");
|
|
12787
12918
|
const duration = Date.now() - startTime;
|
|
12788
12919
|
console.error(`[Memory] Index loaded from cache in ${duration}ms`);
|
|
12920
|
+
if (stateDb) {
|
|
12921
|
+
recordIndexEvent(stateDb, {
|
|
12922
|
+
trigger: "startup_cache",
|
|
12923
|
+
duration_ms: duration,
|
|
12924
|
+
note_count: cachedIndex.notes.size
|
|
12925
|
+
});
|
|
12926
|
+
}
|
|
12789
12927
|
runPostIndexWork(vaultIndex);
|
|
12790
12928
|
} else {
|
|
12791
12929
|
console.error("[Memory] Building vault index...");
|
|
@@ -12794,6 +12932,13 @@ async function main() {
|
|
|
12794
12932
|
setIndexState("ready");
|
|
12795
12933
|
const duration = Date.now() - startTime;
|
|
12796
12934
|
console.error(`[Memory] Vault index ready in ${duration}ms`);
|
|
12935
|
+
if (stateDb) {
|
|
12936
|
+
recordIndexEvent(stateDb, {
|
|
12937
|
+
trigger: "startup_build",
|
|
12938
|
+
duration_ms: duration,
|
|
12939
|
+
note_count: vaultIndex.notes.size
|
|
12940
|
+
});
|
|
12941
|
+
}
|
|
12797
12942
|
if (stateDb) {
|
|
12798
12943
|
try {
|
|
12799
12944
|
saveVaultIndexToCache(stateDb, vaultIndex);
|
|
@@ -12806,6 +12951,15 @@ async function main() {
|
|
|
12806
12951
|
} catch (err) {
|
|
12807
12952
|
setIndexState("error");
|
|
12808
12953
|
setIndexError(err instanceof Error ? err : new Error(String(err)));
|
|
12954
|
+
const duration = Date.now() - startTime;
|
|
12955
|
+
if (stateDb) {
|
|
12956
|
+
recordIndexEvent(stateDb, {
|
|
12957
|
+
trigger: "startup_build",
|
|
12958
|
+
duration_ms: duration,
|
|
12959
|
+
success: false,
|
|
12960
|
+
error: err instanceof Error ? err.message : String(err)
|
|
12961
|
+
});
|
|
12962
|
+
}
|
|
12809
12963
|
console.error("[Memory] Failed to build vault index:", err);
|
|
12810
12964
|
}
|
|
12811
12965
|
}
|
|
@@ -12850,6 +13004,7 @@ async function runPostIndexWork(index) {
|
|
|
12850
13004
|
const metrics = computeMetrics(index, stateDb);
|
|
12851
13005
|
recordMetrics(stateDb, metrics);
|
|
12852
13006
|
purgeOldMetrics(stateDb, 90);
|
|
13007
|
+
purgeOldIndexEvents(stateDb, 90);
|
|
12853
13008
|
console.error("[Memory] Growth metrics recorded");
|
|
12854
13009
|
} catch (err) {
|
|
12855
13010
|
console.error("[Memory] Failed to record metrics:", err);
|
|
@@ -12872,87 +13027,65 @@ async function runPostIndexWork(index) {
|
|
|
12872
13027
|
console.error(`[Memory] Vault: ${flywheelConfig.vault_name}`);
|
|
12873
13028
|
}
|
|
12874
13029
|
if (process.env.FLYWHEEL_WATCH !== "false") {
|
|
12875
|
-
const
|
|
12876
|
-
|
|
12877
|
-
|
|
12878
|
-
|
|
12879
|
-
|
|
12880
|
-
|
|
12881
|
-
|
|
12882
|
-
|
|
12883
|
-
|
|
12884
|
-
|
|
12885
|
-
|
|
12886
|
-
|
|
12887
|
-
|
|
12888
|
-
|
|
12889
|
-
|
|
12890
|
-
|
|
12891
|
-
|
|
12892
|
-
|
|
12893
|
-
|
|
12894
|
-
|
|
12895
|
-
|
|
12896
|
-
|
|
13030
|
+
const config = parseWatcherConfig();
|
|
13031
|
+
console.error(`[Memory] File watcher enabled (debounce: ${config.debounceMs}ms)`);
|
|
13032
|
+
const watcher = createVaultWatcher({
|
|
13033
|
+
vaultPath,
|
|
13034
|
+
config,
|
|
13035
|
+
onBatch: async (batch) => {
|
|
13036
|
+
console.error(`[Memory] Processing ${batch.events.length} file changes`);
|
|
13037
|
+
const batchStart = Date.now();
|
|
13038
|
+
const changedPaths = batch.events.map((e) => e.path);
|
|
13039
|
+
try {
|
|
13040
|
+
vaultIndex = await buildVaultIndex(vaultPath);
|
|
13041
|
+
setIndexState("ready");
|
|
13042
|
+
const duration = Date.now() - batchStart;
|
|
13043
|
+
console.error(`[Memory] Index rebuilt in ${duration}ms`);
|
|
13044
|
+
if (stateDb) {
|
|
13045
|
+
recordIndexEvent(stateDb, {
|
|
13046
|
+
trigger: "watcher",
|
|
13047
|
+
duration_ms: duration,
|
|
13048
|
+
note_count: vaultIndex.notes.size,
|
|
13049
|
+
files_changed: batch.events.length,
|
|
13050
|
+
changed_paths: changedPaths
|
|
13051
|
+
});
|
|
13052
|
+
}
|
|
13053
|
+
await updateEntitiesInStateDb();
|
|
13054
|
+
await exportHubScores(vaultIndex, stateDb);
|
|
13055
|
+
if (stateDb) {
|
|
13056
|
+
try {
|
|
13057
|
+
saveVaultIndexToCache(stateDb, vaultIndex);
|
|
13058
|
+
} catch (err) {
|
|
13059
|
+
console.error("[Memory] Failed to update index cache:", err);
|
|
12897
13060
|
}
|
|
12898
|
-
} catch (err) {
|
|
12899
|
-
setIndexState("error");
|
|
12900
|
-
setIndexError(err instanceof Error ? err : new Error(String(err)));
|
|
12901
|
-
console.error("[Memory] Failed to rebuild index:", err);
|
|
12902
13061
|
}
|
|
12903
|
-
}
|
|
12904
|
-
|
|
12905
|
-
|
|
12906
|
-
|
|
13062
|
+
} catch (err) {
|
|
13063
|
+
setIndexState("error");
|
|
13064
|
+
setIndexError(err instanceof Error ? err : new Error(String(err)));
|
|
13065
|
+
const duration = Date.now() - batchStart;
|
|
13066
|
+
if (stateDb) {
|
|
13067
|
+
recordIndexEvent(stateDb, {
|
|
13068
|
+
trigger: "watcher",
|
|
13069
|
+
duration_ms: duration,
|
|
13070
|
+
success: false,
|
|
13071
|
+
files_changed: batch.events.length,
|
|
13072
|
+
changed_paths: changedPaths,
|
|
13073
|
+
error: err instanceof Error ? err.message : String(err)
|
|
13074
|
+
});
|
|
12907
13075
|
}
|
|
12908
|
-
|
|
12909
|
-
onError: (err) => {
|
|
12910
|
-
console.error("[Memory] Watcher error:", err.message);
|
|
13076
|
+
console.error("[Memory] Failed to rebuild index:", err);
|
|
12911
13077
|
}
|
|
12912
|
-
}
|
|
12913
|
-
|
|
12914
|
-
|
|
12915
|
-
|
|
12916
|
-
console.error(`[Memory] File watcher v1 enabled (debounce: ${debounceMs}ms)`);
|
|
12917
|
-
if (debounceMs >= 6e4) {
|
|
12918
|
-
console.error("[Memory] Warning: Legacy watcher using high debounce (60s). Set FLYWHEEL_WATCH_V2=true for 200ms responsiveness.");
|
|
12919
|
-
}
|
|
12920
|
-
const legacyWatcher = chokidar2.watch(vaultPath, {
|
|
12921
|
-
ignored: /(^|[\/\\])\../,
|
|
12922
|
-
persistent: true,
|
|
12923
|
-
ignoreInitial: true,
|
|
12924
|
-
awaitWriteFinish: {
|
|
12925
|
-
stabilityThreshold: 300,
|
|
12926
|
-
pollInterval: 100
|
|
13078
|
+
},
|
|
13079
|
+
onStateChange: (status) => {
|
|
13080
|
+
if (status.state === "dirty") {
|
|
13081
|
+
console.error("[Memory] Warning: Index may be stale");
|
|
12927
13082
|
}
|
|
12928
|
-
}
|
|
12929
|
-
|
|
12930
|
-
|
|
12931
|
-
|
|
12932
|
-
|
|
12933
|
-
|
|
12934
|
-
console.error("[Memory] Rebuilding index (file changed)");
|
|
12935
|
-
buildVaultIndex(vaultPath).then(async (newIndex) => {
|
|
12936
|
-
vaultIndex = newIndex;
|
|
12937
|
-
setIndexState("ready");
|
|
12938
|
-
console.error("[Memory] Index rebuilt successfully");
|
|
12939
|
-
await updateEntitiesInStateDb();
|
|
12940
|
-
await exportHubScores(newIndex, stateDb);
|
|
12941
|
-
if (stateDb) {
|
|
12942
|
-
try {
|
|
12943
|
-
saveVaultIndexToCache(stateDb, newIndex);
|
|
12944
|
-
} catch (err) {
|
|
12945
|
-
console.error("[Memory] Failed to update index cache:", err);
|
|
12946
|
-
}
|
|
12947
|
-
}
|
|
12948
|
-
}).catch((err) => {
|
|
12949
|
-
setIndexState("error");
|
|
12950
|
-
setIndexError(err instanceof Error ? err : new Error(String(err)));
|
|
12951
|
-
console.error("[Memory] Failed to rebuild index:", err);
|
|
12952
|
-
});
|
|
12953
|
-
}, debounceMs);
|
|
12954
|
-
});
|
|
12955
|
-
}
|
|
13083
|
+
},
|
|
13084
|
+
onError: (err) => {
|
|
13085
|
+
console.error("[Memory] Watcher error:", err.message);
|
|
13086
|
+
}
|
|
13087
|
+
});
|
|
13088
|
+
watcher.start();
|
|
12956
13089
|
}
|
|
12957
13090
|
}
|
|
12958
13091
|
main().catch((error) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velvetmonkey/flywheel-memory",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.18",
|
|
4
4
|
"description": "MCP server that gives Claude full read/write access to your Obsidian vault. 39 tools for search, backlinks, graph queries, and mutations.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
53
|
-
"@velvetmonkey/vault-core": "^2.0.
|
|
53
|
+
"@velvetmonkey/vault-core": "^2.0.18",
|
|
54
54
|
"better-sqlite3": "^11.0.0",
|
|
55
55
|
"chokidar": "^4.0.0",
|
|
56
56
|
"gray-matter": "^4.0.3",
|