@velvetmonkey/flywheel-memory 2.0.62 → 2.0.64

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/index.js +32 -11
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -7596,7 +7596,7 @@ function refreshIfStale(vaultPath2, index, excludeTags) {
7596
7596
  }
7597
7597
 
7598
7598
  // src/index.ts
7599
- import { openStateDb, scanVaultEntities as scanVaultEntities3, getSessionId, getAllEntitiesFromDb as getAllEntitiesFromDb3, findEntityMatches as findEntityMatches2, getProtectedZones as getProtectedZones2, rangeOverlapsProtectedZone, detectImplicitEntities as detectImplicitEntities3 } from "@velvetmonkey/vault-core";
7599
+ import { openStateDb, scanVaultEntities as scanVaultEntities3, getSessionId, getAllEntitiesFromDb as getAllEntitiesFromDb3, findEntityMatches as findEntityMatches2, getProtectedZones as getProtectedZones2, rangeOverlapsProtectedZone, detectImplicitEntities as detectImplicitEntities3, loadContentHashes, saveContentHashBatch, renameContentHash } from "@velvetmonkey/vault-core";
7600
7600
 
7601
7601
  // src/tools/read/graph.ts
7602
7602
  import * as fs9 from "fs";
@@ -19048,6 +19048,9 @@ function getWatcherStatus() {
19048
19048
  var PRESETS = {
19049
19049
  // Presets
19050
19050
  minimal: ["search", "structure", "append", "frontmatter", "notes"],
19051
+ writer: ["search", "structure", "append", "frontmatter", "notes", "tasks"],
19052
+ agent: ["search", "structure", "append", "frontmatter", "notes", "memory"],
19053
+ researcher: ["search", "structure", "backlinks", "hubs", "paths"],
19051
19054
  full: [
19052
19055
  "search",
19053
19056
  "backlinks",
@@ -19062,17 +19065,18 @@ var PRESETS = {
19062
19065
  "append",
19063
19066
  "frontmatter",
19064
19067
  "notes",
19068
+ "note-ops",
19065
19069
  "git",
19066
19070
  "policy",
19067
19071
  "memory"
19068
19072
  ],
19069
- agent: ["search", "structure", "append", "frontmatter", "notes", "memory"],
19070
19073
  // Composable bundles
19071
19074
  graph: ["backlinks", "orphans", "hubs", "paths"],
19072
19075
  analysis: ["schema", "wikilinks"],
19073
19076
  tasks: ["tasks"],
19074
19077
  health: ["health"],
19075
- ops: ["git", "policy"]
19078
+ ops: ["git", "policy"],
19079
+ "note-ops": ["note-ops"]
19076
19080
  };
19077
19081
  var ALL_CATEGORIES = [
19078
19082
  "backlinks",
@@ -19088,13 +19092,14 @@ var ALL_CATEGORIES = [
19088
19092
  "append",
19089
19093
  "frontmatter",
19090
19094
  "notes",
19095
+ "note-ops",
19091
19096
  "git",
19092
19097
  "policy",
19093
19098
  "memory"
19094
19099
  ];
19095
19100
  var DEFAULT_PRESET = "full";
19096
19101
  function parseEnabledCategories() {
19097
- const envValue = process.env.FLYWHEEL_TOOLS?.trim();
19102
+ const envValue = (process.env.FLYWHEEL_TOOLS ?? process.env.FLYWHEEL_PRESET)?.trim();
19098
19103
  if (!envValue) {
19099
19104
  return new Set(PRESETS[DEFAULT_PRESET]);
19100
19105
  }
@@ -19165,11 +19170,12 @@ var TOOL_CATEGORY = {
19165
19170
  vault_replace_in_section: "append",
19166
19171
  // frontmatter (absorbed vault_add_frontmatter_field via only_if_missing)
19167
19172
  vault_update_frontmatter: "frontmatter",
19168
- // notes (CRUD)
19173
+ // notes (create only)
19169
19174
  vault_create_note: "notes",
19170
- vault_delete_note: "notes",
19171
- vault_move_note: "notes",
19172
- vault_rename_note: "notes",
19175
+ // note-ops (file management)
19176
+ vault_delete_note: "note-ops",
19177
+ vault_move_note: "note-ops",
19178
+ vault_rename_note: "note-ops",
19173
19179
  // git
19174
19180
  vault_undo_last_mutation: "git",
19175
19181
  // policy
@@ -19193,8 +19199,8 @@ var TOOL_CATEGORY = {
19193
19199
  // health (merge suggestions)
19194
19200
  suggest_entity_merges: "health",
19195
19201
  dismiss_merge_suggestion: "health",
19196
- // notes (entity merge)
19197
- merge_entities: "notes",
19202
+ // note-ops (entity merge)
19203
+ merge_entities: "note-ops",
19198
19204
  // memory (agent working memory)
19199
19205
  memory: "memory",
19200
19206
  recall: "memory",
@@ -19629,6 +19635,13 @@ async function runPostIndexWork(index) {
19629
19635
  if (process.env.FLYWHEEL_WATCH !== "false") {
19630
19636
  const config = parseWatcherConfig();
19631
19637
  const lastContentHashes = /* @__PURE__ */ new Map();
19638
+ if (stateDb) {
19639
+ const persisted = loadContentHashes(stateDb);
19640
+ for (const [p, h] of persisted) lastContentHashes.set(p, h);
19641
+ if (persisted.size > 0) {
19642
+ serverLog("watcher", `Loaded ${persisted.size} persisted content hashes`);
19643
+ }
19644
+ }
19632
19645
  serverLog("watcher", `File watcher enabled (debounce: ${config.debounceMs}ms)`);
19633
19646
  const handleBatch = async (batch) => {
19634
19647
  const vaultPrefixes = /* @__PURE__ */ new Set([
@@ -19674,25 +19687,32 @@ async function runPostIndexWork(index) {
19674
19687
  newPath: normalizeEventPath(r.newPath)
19675
19688
  }));
19676
19689
  const filteredEvents = [];
19690
+ const hashUpserts = [];
19691
+ const hashDeletes = [];
19677
19692
  for (const event of batch.events) {
19678
19693
  if (event.type === "delete") {
19679
19694
  filteredEvents.push(event);
19680
19695
  lastContentHashes.delete(event.path);
19696
+ hashDeletes.push(event.path);
19681
19697
  continue;
19682
19698
  }
19683
19699
  try {
19684
19700
  const content = await fs31.readFile(path32.join(vaultPath, event.path), "utf-8");
19685
- const hash = createHash2("md5").update(content).digest("hex");
19701
+ const hash = createHash2("sha256").update(content).digest("hex").slice(0, 16);
19686
19702
  if (lastContentHashes.get(event.path) === hash) {
19687
19703
  serverLog("watcher", `Hash unchanged, skipping: ${event.path}`);
19688
19704
  continue;
19689
19705
  }
19690
19706
  lastContentHashes.set(event.path, hash);
19707
+ hashUpserts.push({ path: event.path, hash });
19691
19708
  filteredEvents.push(event);
19692
19709
  } catch {
19693
19710
  filteredEvents.push(event);
19694
19711
  }
19695
19712
  }
19713
+ if (stateDb && (hashUpserts.length || hashDeletes.length)) {
19714
+ saveContentHashBatch(stateDb, hashUpserts, hashDeletes);
19715
+ }
19696
19716
  if (batchRenames.length > 0 && stateDb) {
19697
19717
  try {
19698
19718
  const insertMove = stateDb.db.prepare(`
@@ -19723,6 +19743,7 @@ async function runPostIndexWork(index) {
19723
19743
  if (oldHash !== void 0) {
19724
19744
  lastContentHashes.set(rename.newPath, oldHash);
19725
19745
  lastContentHashes.delete(rename.oldPath);
19746
+ renameContentHash(stateDb, rename.oldPath, rename.newPath);
19726
19747
  }
19727
19748
  }
19728
19749
  serverLog("watcher", `Renames: recorded ${batchRenames.length} move(s) in note_moves`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velvetmonkey/flywheel-memory",
3
- "version": "2.0.62",
3
+ "version": "2.0.64",
4
4
  "description": "MCP server that gives Claude full read/write access to your Obsidian vault. Select from 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.62",
55
+ "@velvetmonkey/vault-core": "2.0.64",
56
56
  "better-sqlite3": "^11.0.0",
57
57
  "chokidar": "^4.0.0",
58
58
  "gray-matter": "^4.0.3",