@velvetmonkey/flywheel-memory 2.9.1 → 2.11.0

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 +1066 -564
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -273,12 +273,158 @@ var init_vault_scope = __esm({
273
273
  }
274
274
  });
275
275
 
276
- // src/core/read/embeddings.ts
277
- import * as crypto from "crypto";
276
+ // src/core/read/embeddingProvider.ts
278
277
  import * as fs4 from "fs";
279
278
  import * as path3 from "path";
280
279
  import { Worker } from "node:worker_threads";
281
280
  import { fileURLToPath } from "node:url";
281
+ function resolveWorkerPath() {
282
+ const thisFile = typeof __filename !== "undefined" ? __filename : fileURLToPath(import.meta.url);
283
+ const thisDir = path3.dirname(thisFile);
284
+ const workerPath = path3.join(thisDir, "embedding-worker.js");
285
+ if (fs4.existsSync(workerPath)) return workerPath;
286
+ const devPath = path3.resolve(thisDir, "..", "..", "..", "dist", "embedding-worker.js");
287
+ if (fs4.existsSync(devPath)) return devPath;
288
+ throw new Error(
289
+ `Embedding worker not found at ${workerPath}. Run 'npm run build' to generate it.`
290
+ );
291
+ }
292
+ function getEmbeddingProvider(modelId) {
293
+ if (provider && providerModelId !== modelId) {
294
+ provider.shutdown();
295
+ provider = null;
296
+ providerModelId = null;
297
+ }
298
+ if (!provider) {
299
+ provider = new WorkerEmbeddingProvider(modelId);
300
+ providerModelId = modelId;
301
+ }
302
+ return provider;
303
+ }
304
+ var WorkerEmbeddingProvider, provider, providerModelId;
305
+ var init_embeddingProvider = __esm({
306
+ "src/core/read/embeddingProvider.ts"() {
307
+ "use strict";
308
+ WorkerEmbeddingProvider = class {
309
+ constructor(modelId) {
310
+ this.modelId = modelId;
311
+ }
312
+ initPromise = null;
313
+ dims = 0;
314
+ nextRequestId = 0;
315
+ pending = /* @__PURE__ */ new Map();
316
+ ready = false;
317
+ worker = null;
318
+ async init() {
319
+ if (this.ready && this.worker) {
320
+ return { dims: this.dims };
321
+ }
322
+ if (this.initPromise) {
323
+ return this.initPromise;
324
+ }
325
+ this.initPromise = new Promise((resolve4, reject) => {
326
+ try {
327
+ const workerPath = resolveWorkerPath();
328
+ console.error(`[Semantic] Spawning embedding worker: ${workerPath}`);
329
+ this.worker = new Worker(workerPath);
330
+ this.worker.on("message", (msg) => {
331
+ switch (msg.type) {
332
+ case "ready":
333
+ this.ready = true;
334
+ this.dims = msg.dims;
335
+ console.error(`[Semantic] Worker ready (model: ${this.modelId}, dims: ${msg.dims})`);
336
+ resolve4({ dims: msg.dims });
337
+ break;
338
+ case "result": {
339
+ const pending = this.pending.get(msg.id);
340
+ if (pending) {
341
+ this.pending.delete(msg.id);
342
+ pending.resolve(new Float32Array(msg.embedding));
343
+ }
344
+ break;
345
+ }
346
+ case "error": {
347
+ if (msg.fatal) {
348
+ console.error(`[Semantic] Worker fatal error: ${msg.message}`);
349
+ console.error("[Semantic] Semantic search disabled. Keyword search (BM25) remains available.");
350
+ this.shutdown();
351
+ this.initPromise = null;
352
+ reject(new Error(msg.message));
353
+ } else if (msg.id != null) {
354
+ const pending = this.pending.get(msg.id);
355
+ if (pending) {
356
+ this.pending.delete(msg.id);
357
+ pending.reject(new Error(msg.message));
358
+ }
359
+ }
360
+ break;
361
+ }
362
+ }
363
+ });
364
+ this.worker.on("error", (err) => {
365
+ console.error(`[Semantic] Worker error: ${err.message}`);
366
+ this.handleCrash(new Error(`Embedding worker error: ${err.message}`));
367
+ if (!this.ready) {
368
+ this.initPromise = null;
369
+ reject(err);
370
+ }
371
+ });
372
+ this.worker.on("exit", (code) => {
373
+ if (code !== 0 && this.ready) {
374
+ console.error(`[Semantic] Worker exited with code ${code}`);
375
+ this.handleCrash(new Error(`Embedding worker exited with code ${code}`));
376
+ }
377
+ });
378
+ this.worker.postMessage({ type: "init", modelId: this.modelId });
379
+ } catch (err) {
380
+ this.initPromise = null;
381
+ reject(err);
382
+ }
383
+ });
384
+ return this.initPromise;
385
+ }
386
+ async embed(text) {
387
+ await this.init();
388
+ if (!this.worker) {
389
+ throw new Error("Embedding worker not available");
390
+ }
391
+ const id = ++this.nextRequestId;
392
+ return new Promise((resolve4, reject) => {
393
+ this.pending.set(id, { resolve: resolve4, reject });
394
+ this.worker.postMessage({ type: "embed", id, text });
395
+ });
396
+ }
397
+ shutdown() {
398
+ if (this.worker) {
399
+ try {
400
+ this.worker.postMessage({ type: "shutdown" });
401
+ } catch {
402
+ }
403
+ }
404
+ this.worker = null;
405
+ this.ready = false;
406
+ this.initPromise = null;
407
+ this.dims = 0;
408
+ }
409
+ handleCrash(error) {
410
+ for (const [id, pending] of this.pending) {
411
+ pending.reject(error);
412
+ this.pending.delete(id);
413
+ }
414
+ this.worker = null;
415
+ this.ready = false;
416
+ this.initPromise = null;
417
+ }
418
+ };
419
+ provider = null;
420
+ providerModelId = null;
421
+ }
422
+ });
423
+
424
+ // src/core/read/embeddings.ts
425
+ import * as crypto from "crypto";
426
+ import * as fs5 from "fs";
427
+ import * as path4 from "path";
282
428
  function getModelConfig() {
283
429
  const envModel = process.env.EMBEDDING_MODEL?.trim();
284
430
  if (!envModel) return MODEL_REGISTRY[DEFAULT_MODEL];
@@ -330,115 +476,16 @@ function clearEmbeddingsForRebuild() {
330
476
  function setEmbeddingsDatabase(database) {
331
477
  db = database;
332
478
  }
333
- function resolveWorkerPath() {
334
- const thisFile = typeof __filename !== "undefined" ? __filename : fileURLToPath(import.meta.url);
335
- const thisDir = path3.dirname(thisFile);
336
- const workerPath = path3.join(thisDir, "embedding-worker.js");
337
- if (fs4.existsSync(workerPath)) return workerPath;
338
- const devPath = path3.resolve(thisDir, "..", "..", "..", "dist", "embedding-worker.js");
339
- if (fs4.existsSync(devPath)) return devPath;
340
- throw new Error(
341
- `Embedding worker not found at ${workerPath}. Run 'npm run build' to generate it.`
342
- );
343
- }
344
479
  async function initEmbeddings() {
345
- if (workerReady && worker) return;
346
- if (workerInitPromise) return workerInitPromise;
347
- workerInitPromise = new Promise((resolve4, reject) => {
348
- try {
349
- const workerPath = resolveWorkerPath();
350
- console.error(`[Semantic] Spawning embedding worker: ${workerPath}`);
351
- worker = new Worker(workerPath);
352
- worker.on("message", (msg) => {
353
- switch (msg.type) {
354
- case "ready":
355
- workerReady = true;
356
- workerDims = msg.dims;
357
- if (activeModelConfig.dims === 0) {
358
- activeModelConfig.dims = msg.dims;
359
- console.error(`[Semantic] Probed model ${activeModelConfig.id}: ${msg.dims} dims`);
360
- }
361
- console.error(`[Semantic] Worker ready (model: ${activeModelConfig.id}, dims: ${msg.dims})`);
362
- resolve4();
363
- break;
364
- case "result": {
365
- const pending = pendingEmbeds.get(msg.id);
366
- if (pending) {
367
- pendingEmbeds.delete(msg.id);
368
- pending.resolve(new Float32Array(msg.embedding));
369
- }
370
- break;
371
- }
372
- case "error": {
373
- if (msg.fatal) {
374
- console.error(`[Semantic] Worker fatal error: ${msg.message}`);
375
- console.error(`[Semantic] Semantic search disabled. Keyword search (BM25) remains available.`);
376
- terminateWorker();
377
- workerInitPromise = null;
378
- reject(new Error(msg.message));
379
- } else if (msg.id != null) {
380
- const pending = pendingEmbeds.get(msg.id);
381
- if (pending) {
382
- pendingEmbeds.delete(msg.id);
383
- pending.reject(new Error(msg.message));
384
- }
385
- }
386
- break;
387
- }
388
- }
389
- });
390
- worker.on("error", (err) => {
391
- console.error(`[Semantic] Worker error: ${err.message}`);
392
- handleWorkerCrash();
393
- if (!workerReady) {
394
- workerInitPromise = null;
395
- reject(err);
396
- }
397
- });
398
- worker.on("exit", (code) => {
399
- if (code !== 0 && workerReady) {
400
- console.error(`[Semantic] Worker exited with code ${code}`);
401
- handleWorkerCrash();
402
- }
403
- });
404
- worker.postMessage({ type: "init", modelId: activeModelConfig.id });
405
- } catch (err) {
406
- workerInitPromise = null;
407
- reject(err);
408
- }
409
- });
410
- return workerInitPromise;
411
- }
412
- function handleWorkerCrash() {
413
- for (const [id, pending] of pendingEmbeds) {
414
- pending.reject(new Error("Embedding worker crashed"));
415
- pendingEmbeds.delete(id);
416
- }
417
- worker = null;
418
- workerReady = false;
419
- workerInitPromise = null;
420
- }
421
- function terminateWorker() {
422
- if (worker) {
423
- try {
424
- worker.postMessage({ type: "shutdown" });
425
- } catch {
426
- }
427
- worker = null;
480
+ const { dims } = await getEmbeddingProvider(activeModelConfig.id).init();
481
+ if (activeModelConfig.dims === 0) {
482
+ activeModelConfig.dims = dims;
483
+ console.error(`[Semantic] Probed model ${activeModelConfig.id}: ${dims} dims`);
428
484
  }
429
- workerReady = false;
430
- workerInitPromise = null;
431
485
  }
432
486
  async function embedText(text) {
433
487
  await initEmbeddings();
434
- if (!worker) {
435
- throw new Error("Embedding worker not available");
436
- }
437
- const id = ++embedRequestId;
438
- return new Promise((resolve4, reject) => {
439
- pendingEmbeds.set(id, { resolve: resolve4, reject });
440
- worker.postMessage({ type: "embed", id, text });
441
- });
488
+ return getEmbeddingProvider(activeModelConfig.id).embed(text);
442
489
  }
443
490
  async function embedTextCached(text) {
444
491
  const existing = embeddingCache.get(text);
@@ -501,12 +548,12 @@ async function buildEmbeddingsIndex(vaultPath2, onProgress) {
501
548
  for (const file of indexable) {
502
549
  progress.current++;
503
550
  try {
504
- const stats = fs4.statSync(file.absolutePath);
551
+ const stats = fs5.statSync(file.absolutePath);
505
552
  if (stats.size > MAX_FILE_SIZE2) {
506
553
  progress.skipped++;
507
554
  continue;
508
555
  }
509
- const content = fs4.readFileSync(file.absolutePath, "utf-8");
556
+ const content = fs5.readFileSync(file.absolutePath, "utf-8");
510
557
  const hash = contentHash(content);
511
558
  if (existingHashes.get(file.path) === hash) {
512
559
  progress.skipped++;
@@ -540,7 +587,7 @@ async function updateEmbedding(notePath, absolutePath) {
540
587
  const db4 = getDb();
541
588
  if (!db4) return;
542
589
  try {
543
- const content = fs4.readFileSync(absolutePath, "utf-8");
590
+ const content = fs5.readFileSync(absolutePath, "utf-8");
544
591
  const hash = contentHash(content);
545
592
  const existing = db4.prepare("SELECT content_hash FROM note_embeddings WHERE path = ?").get(notePath);
546
593
  if (existing?.content_hash === hash) return;
@@ -817,8 +864,8 @@ function buildEntityEmbeddingText(entity, vaultPath2) {
817
864
  parts.push(entity.category);
818
865
  if (entity.path) {
819
866
  try {
820
- const absPath = path3.join(vaultPath2, entity.path);
821
- const content = fs4.readFileSync(absPath, "utf-8");
867
+ const absPath = path4.join(vaultPath2, entity.path);
868
+ const content = fs5.readFileSync(absPath, "utf-8");
822
869
  parts.push(content.slice(0, 500));
823
870
  } catch {
824
871
  }
@@ -1117,13 +1164,14 @@ function getEntityEmbeddingsCount() {
1117
1164
  return 0;
1118
1165
  }
1119
1166
  }
1120
- var MODEL_REGISTRY, DEFAULT_MODEL, activeModelConfig, MAX_FILE_SIZE2, db, embeddingsBuilding, worker, workerReady, workerDims, workerInitPromise, embedRequestId, pendingEmbeds, embeddingCache, EMBEDDING_CACHE_MAX, entityEmbeddingsMap, inferredCategoriesMap, EMBEDDING_TEXT_VERSION;
1167
+ var MODEL_REGISTRY, DEFAULT_MODEL, activeModelConfig, MAX_FILE_SIZE2, db, embeddingsBuilding, embeddingCache, EMBEDDING_CACHE_MAX, entityEmbeddingsMap, inferredCategoriesMap, EMBEDDING_TEXT_VERSION;
1121
1168
  var init_embeddings = __esm({
1122
1169
  "src/core/read/embeddings.ts"() {
1123
1170
  "use strict";
1124
1171
  init_vault_scope();
1125
1172
  init_vault();
1126
1173
  init_constants();
1174
+ init_embeddingProvider();
1127
1175
  MODEL_REGISTRY = {
1128
1176
  "Xenova/all-MiniLM-L6-v2": { id: "Xenova/all-MiniLM-L6-v2", dims: 384 },
1129
1177
  "Xenova/bge-small-en-v1.5": { id: "Xenova/bge-small-en-v1.5", dims: 384 },
@@ -1135,12 +1183,6 @@ var init_embeddings = __esm({
1135
1183
  MAX_FILE_SIZE2 = 5 * 1024 * 1024;
1136
1184
  db = null;
1137
1185
  embeddingsBuilding = false;
1138
- worker = null;
1139
- workerReady = false;
1140
- workerDims = 0;
1141
- workerInitPromise = null;
1142
- embedRequestId = 0;
1143
- pendingEmbeds = /* @__PURE__ */ new Map();
1144
1186
  embeddingCache = /* @__PURE__ */ new Map();
1145
1187
  EMBEDDING_CACHE_MAX = 500;
1146
1188
  entityEmbeddingsMap = /* @__PURE__ */ new Map();
@@ -1151,7 +1193,7 @@ var init_embeddings = __esm({
1151
1193
 
1152
1194
  // src/core/shared/recency.ts
1153
1195
  import { readdir, readFile, stat } from "fs/promises";
1154
- import path9 from "path";
1196
+ import path10 from "path";
1155
1197
  import {
1156
1198
  getEntityName,
1157
1199
  recordEntityMention,
@@ -1167,9 +1209,9 @@ async function* walkMarkdownFiles(dir, baseDir) {
1167
1209
  try {
1168
1210
  const entries = await readdir(dir, { withFileTypes: true });
1169
1211
  for (const entry of entries) {
1170
- const fullPath = path9.join(dir, entry.name);
1171
- const relativePath = path9.relative(baseDir, fullPath);
1172
- const topFolder = relativePath.split(path9.sep)[0];
1212
+ const fullPath = path10.join(dir, entry.name);
1213
+ const relativePath = path10.relative(baseDir, fullPath);
1214
+ const topFolder = relativePath.split(path10.sep)[0];
1173
1215
  if (SYSTEM_EXCLUDED_DIRS.has(topFolder)) {
1174
1216
  continue;
1175
1217
  }
@@ -1546,7 +1588,7 @@ var init_stemmer = __esm({
1546
1588
 
1547
1589
  // src/core/shared/cooccurrence.ts
1548
1590
  import { readdir as readdir2, readFile as readFile2 } from "fs/promises";
1549
- import path10 from "path";
1591
+ import path11 from "path";
1550
1592
  function noteContainsEntity(content, entityName, contentTokens) {
1551
1593
  const entityTokens = tokenize(entityName);
1552
1594
  if (entityTokens.length === 0) return false;
@@ -1576,9 +1618,9 @@ async function* walkMarkdownFiles2(dir, baseDir) {
1576
1618
  try {
1577
1619
  const entries = await readdir2(dir, { withFileTypes: true });
1578
1620
  for (const entry of entries) {
1579
- const fullPath = path10.join(dir, entry.name);
1580
- const relativePath = path10.relative(baseDir, fullPath);
1581
- const topFolder = relativePath.split(path10.sep)[0];
1621
+ const fullPath = path11.join(dir, entry.name);
1622
+ const relativePath = path11.relative(baseDir, fullPath);
1623
+ const topFolder = relativePath.split(path11.sep)[0];
1582
1624
  if (SYSTEM_EXCLUDED_DIRS.has(topFolder)) {
1583
1625
  continue;
1584
1626
  }
@@ -2019,11 +2061,11 @@ function getAllFeedbackBoosts(stateDb2, folder, now) {
2019
2061
  if (folder !== void 0) {
2020
2062
  folderStatsMap = /* @__PURE__ */ new Map();
2021
2063
  for (const gs of globalStats) {
2022
- const fs34 = getWeightedFolderStats(stateDb2, gs.entity, folder, now);
2023
- if (fs34.rawTotal >= FEEDBACK_BOOST_MIN_SAMPLES) {
2064
+ const fs35 = getWeightedFolderStats(stateDb2, gs.entity, folder, now);
2065
+ if (fs35.rawTotal >= FEEDBACK_BOOST_MIN_SAMPLES) {
2024
2066
  folderStatsMap.set(gs.entity, {
2025
- weightedAccuracy: fs34.weightedAccuracy,
2026
- rawCount: fs34.rawTotal
2067
+ weightedAccuracy: fs35.weightedAccuracy,
2068
+ rawCount: fs35.rawTotal
2027
2069
  });
2028
2070
  }
2029
2071
  }
@@ -2033,10 +2075,10 @@ function getAllFeedbackBoosts(stateDb2, folder, now) {
2033
2075
  if (stat4.rawTotal < FEEDBACK_BOOST_MIN_SAMPLES) continue;
2034
2076
  let accuracy;
2035
2077
  let sampleCount;
2036
- const fs34 = folderStatsMap?.get(stat4.entity);
2037
- if (fs34 && fs34.rawCount >= FEEDBACK_BOOST_MIN_SAMPLES) {
2038
- accuracy = fs34.weightedAccuracy;
2039
- sampleCount = fs34.rawCount;
2078
+ const fs35 = folderStatsMap?.get(stat4.entity);
2079
+ if (fs35 && fs35.rawCount >= FEEDBACK_BOOST_MIN_SAMPLES) {
2080
+ accuracy = fs35.weightedAccuracy;
2081
+ sampleCount = fs35.rawCount;
2040
2082
  } else {
2041
2083
  accuracy = stat4.weightedAccuracy;
2042
2084
  sampleCount = stat4.rawTotal;
@@ -2586,8 +2628,8 @@ var init_corrections = __esm({
2586
2628
 
2587
2629
  // src/core/write/git.ts
2588
2630
  import { simpleGit, CheckRepoActions } from "simple-git";
2589
- import path11 from "path";
2590
- import fs7 from "fs/promises";
2631
+ import path12 from "path";
2632
+ import fs8 from "fs/promises";
2591
2633
  import {
2592
2634
  setWriteState,
2593
2635
  getWriteState,
@@ -2638,9 +2680,9 @@ function clearLastMutationCommit() {
2638
2680
  }
2639
2681
  }
2640
2682
  async function checkGitLock(vaultPath2) {
2641
- const lockPath = path11.join(vaultPath2, ".git/index.lock");
2683
+ const lockPath = path12.join(vaultPath2, ".git/index.lock");
2642
2684
  try {
2643
- const stat4 = await fs7.stat(lockPath);
2685
+ const stat4 = await fs8.stat(lockPath);
2644
2686
  const ageMs = Date.now() - stat4.mtimeMs;
2645
2687
  return {
2646
2688
  locked: true,
@@ -2661,9 +2703,9 @@ async function isGitRepo(vaultPath2) {
2661
2703
  }
2662
2704
  }
2663
2705
  async function checkLockFile(vaultPath2) {
2664
- const lockPath = path11.join(vaultPath2, ".git/index.lock");
2706
+ const lockPath = path12.join(vaultPath2, ".git/index.lock");
2665
2707
  try {
2666
- const stat4 = await fs7.stat(lockPath);
2708
+ const stat4 = await fs8.stat(lockPath);
2667
2709
  const ageMs = Date.now() - stat4.mtimeMs;
2668
2710
  return { stale: ageMs > STALE_LOCK_THRESHOLD_MS, ageMs };
2669
2711
  } catch {
@@ -2711,7 +2753,7 @@ async function commitChange(vaultPath2, filePath, messagePrefix, retryConfig = D
2711
2753
  }
2712
2754
  }
2713
2755
  await git.add(filePath);
2714
- const fileName = path11.basename(filePath);
2756
+ const fileName = path12.basename(filePath);
2715
2757
  const commitMessage = `${messagePrefix} Update ${fileName}`;
2716
2758
  const result = await git.commit(commitMessage);
2717
2759
  if (result.commit) {
@@ -2739,9 +2781,9 @@ async function commitChange(vaultPath2, filePath, messagePrefix, retryConfig = D
2739
2781
  lockAgeMs = lockInfo.ageMs;
2740
2782
  if (lockInfo.stale) {
2741
2783
  staleLockDetected = true;
2742
- const lockPath = path11.join(vaultPath2, ".git/index.lock");
2784
+ const lockPath = path12.join(vaultPath2, ".git/index.lock");
2743
2785
  try {
2744
- await fs7.unlink(lockPath);
2786
+ await fs8.unlink(lockPath);
2745
2787
  serverLog("git", `Removed stale git lock (age: ${lockInfo.ageMs}ms)`, "warn");
2746
2788
  } catch {
2747
2789
  }
@@ -2881,9 +2923,9 @@ ${files.map((f) => `- ${f}`).join("\n")}`;
2881
2923
  lockAgeMs = lockInfo.ageMs;
2882
2924
  if (lockInfo.stale) {
2883
2925
  staleLockDetected = true;
2884
- const lockPath = path11.join(vaultPath2, ".git/index.lock");
2926
+ const lockPath = path12.join(vaultPath2, ".git/index.lock");
2885
2927
  try {
2886
- await fs7.unlink(lockPath);
2928
+ await fs8.unlink(lockPath);
2887
2929
  serverLog("git", `Removed stale git lock (age: ${lockInfo.ageMs}ms)`, "warn");
2888
2930
  } catch {
2889
2931
  }
@@ -2955,6 +2997,9 @@ function computeProspectDecay(lastSeenAt, now) {
2955
2997
  function todayISO() {
2956
2998
  return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2957
2999
  }
3000
+ function normalizeProspectKey(term) {
3001
+ return normalizeFuzzyTerm(term).toLowerCase();
3002
+ }
2958
3003
  function recordProspectSightings(sightings) {
2959
3004
  const stateDb2 = getStateDb3();
2960
3005
  if (!stateDb2 || sightings.length === 0) return;
@@ -3000,6 +3045,88 @@ function recordProspectSightings(sightings) {
3000
3045
  });
3001
3046
  runBatch();
3002
3047
  }
3048
+ function recordProspectFeedback(events) {
3049
+ const stateDb2 = getStateDb3();
3050
+ if (!stateDb2 || events.length === 0) return;
3051
+ const insert = stateDb2.db.prepare(`
3052
+ INSERT INTO prospect_feedback (term, action, entity_path, note_path, reason, created_at)
3053
+ VALUES (?, ?, ?, ?, ?, ?)
3054
+ `);
3055
+ const runBatch = stateDb2.db.transaction(() => {
3056
+ for (const event of events) {
3057
+ insert.run(
3058
+ event.term.toLowerCase(),
3059
+ event.action,
3060
+ event.entityPath ?? null,
3061
+ event.notePath ?? null,
3062
+ event.reason ?? null,
3063
+ event.createdAt ?? Date.now()
3064
+ );
3065
+ }
3066
+ });
3067
+ runBatch();
3068
+ }
3069
+ function getMatchingProspectTerms(candidates) {
3070
+ const stateDb2 = getStateDb3();
3071
+ if (!stateDb2 || candidates.length === 0) return [];
3072
+ const wanted = new Set(
3073
+ candidates.map((value) => value.trim()).filter(Boolean).map((value) => normalizeProspectKey(value))
3074
+ );
3075
+ if (wanted.size === 0) return [];
3076
+ const rows = stateDb2.db.prepare(`
3077
+ SELECT term, display_name
3078
+ FROM prospect_summary
3079
+ WHERE status = 'prospect'
3080
+ `).all();
3081
+ const matched = /* @__PURE__ */ new Set();
3082
+ for (const row of rows) {
3083
+ const rowKey = normalizeProspectKey(row.display_name || row.term);
3084
+ if (wanted.has(rowKey)) matched.add(row.term);
3085
+ }
3086
+ return Array.from(matched);
3087
+ }
3088
+ function resolveProspectsForCreatedEntity(entityPath, title, aliases = []) {
3089
+ const terms = getMatchingProspectTerms([title, ...aliases]);
3090
+ if (terms.length === 0) return [];
3091
+ recordProspectFeedback(
3092
+ terms.map((term) => ({
3093
+ term,
3094
+ action: "create_entity",
3095
+ entityPath,
3096
+ notePath: entityPath
3097
+ }))
3098
+ );
3099
+ refreshProspectSummaries(terms);
3100
+ return terms;
3101
+ }
3102
+ function resolveProspectForAlias(entityPath, alias) {
3103
+ const terms = getMatchingProspectTerms([alias]);
3104
+ if (terms.length === 0) return [];
3105
+ recordProspectFeedback(
3106
+ terms.map((term) => ({
3107
+ term,
3108
+ action: "merge_alias",
3109
+ entityPath,
3110
+ notePath: entityPath
3111
+ }))
3112
+ );
3113
+ refreshProspectSummaries(terms);
3114
+ return terms;
3115
+ }
3116
+ function dismissProspect(term, reason, notePath) {
3117
+ const matched = getMatchingProspectTerms([term]);
3118
+ if (matched.length === 0) return false;
3119
+ recordProspectFeedback(
3120
+ matched.map((matchedTerm) => ({
3121
+ term: matchedTerm,
3122
+ action: "reject",
3123
+ reason,
3124
+ notePath
3125
+ }))
3126
+ );
3127
+ refreshProspectSummaries(matched);
3128
+ return true;
3129
+ }
3003
3130
  function refreshProspectSummaries(terms) {
3004
3131
  const stateDb2 = getStateDb3();
3005
3132
  if (!stateDb2 || terms.length === 0) return;
@@ -3041,18 +3168,37 @@ function refreshProspectSummaries(terms) {
3041
3168
  LIMIT 10
3042
3169
  `);
3043
3170
  const entityExists = stateDb2.db.prepare(`
3044
- SELECT 1 FROM entities
3171
+ SELECT path FROM entities
3045
3172
  WHERE name_lower = ?
3046
3173
  UNION
3047
- SELECT 1 FROM entities
3174
+ SELECT path FROM entities
3048
3175
  WHERE EXISTS (
3049
3176
  SELECT 1 FROM json_each(aliases_json) WHERE LOWER(value) = ?
3050
3177
  )
3051
3178
  LIMIT 1
3052
3179
  `);
3180
+ const latestFeedback = stateDb2.db.prepare(`
3181
+ SELECT action, entity_path, created_at
3182
+ FROM prospect_feedback
3183
+ WHERE term = ?
3184
+ ORDER BY
3185
+ CASE action
3186
+ WHEN 'merge_alias' THEN 3
3187
+ WHEN 'create_entity' THEN 2
3188
+ WHEN 'reject' THEN 1
3189
+ ELSE 0
3190
+ END DESC,
3191
+ created_at DESC
3192
+ LIMIT 1
3193
+ `);
3194
+ const lastFeedbackAt = stateDb2.db.prepare(`
3195
+ SELECT MAX(created_at) AS created_at
3196
+ FROM prospect_feedback
3197
+ WHERE term = ?
3198
+ `);
3053
3199
  const upsertSummary = stateDb2.db.prepare(`
3054
- INSERT INTO prospect_summary (term, display_name, note_count, day_count, total_sightings, backlink_max, cooccurring_entities, best_source, best_confidence, best_score, first_seen_at, last_seen_at, promotion_score, promoted_at, updated_at)
3055
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
3200
+ INSERT INTO prospect_summary (term, display_name, note_count, day_count, total_sightings, backlink_max, cooccurring_entities, best_source, best_confidence, best_score, first_seen_at, last_seen_at, promotion_score, promoted_at, status, resolved_entity_path, last_feedback_at, updated_at)
3201
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
3056
3202
  ON CONFLICT(term) DO UPDATE SET
3057
3203
  display_name = excluded.display_name,
3058
3204
  note_count = excluded.note_count,
@@ -3067,6 +3213,9 @@ function refreshProspectSummaries(terms) {
3067
3213
  last_seen_at = excluded.last_seen_at,
3068
3214
  promotion_score = excluded.promotion_score,
3069
3215
  promoted_at = excluded.promoted_at,
3216
+ status = excluded.status,
3217
+ resolved_entity_path = excluded.resolved_entity_path,
3218
+ last_feedback_at = excluded.last_feedback_at,
3070
3219
  updated_at = excluded.updated_at
3071
3220
  `);
3072
3221
  const runRefresh = stateDb2.db.transaction(() => {
@@ -3078,8 +3227,24 @@ function refreshProspectSummaries(terms) {
3078
3227
  const confRow = bestConfidence.get(term);
3079
3228
  const coocRows = cooccurring.all(term, term);
3080
3229
  const coocEntities = coocRows.map((r) => r.target);
3081
- const exists = entityExists.get(term, term);
3082
- const promotedAt = exists ? now : null;
3230
+ const existingEntity = entityExists.get(term, term);
3231
+ const feedback = latestFeedback.get(term);
3232
+ const feedbackTimeRow = lastFeedbackAt.get(term);
3233
+ const promotedAt = existingEntity ? now : null;
3234
+ let status = "prospect";
3235
+ let resolvedEntityPath = null;
3236
+ if (feedback?.action === "merge_alias") {
3237
+ status = "merged";
3238
+ resolvedEntityPath = feedback.entity_path ?? null;
3239
+ } else if (feedback?.action === "create_entity") {
3240
+ status = "entity_created";
3241
+ resolvedEntityPath = feedback.entity_path ?? null;
3242
+ } else if (feedback?.action === "reject") {
3243
+ status = "rejected";
3244
+ } else if (existingEntity?.path) {
3245
+ status = "entity_created";
3246
+ resolvedEntityPath = existingEntity.path;
3247
+ }
3083
3248
  const promoScore = computePromotionScore({
3084
3249
  noteCount: agg.note_count,
3085
3250
  dayCount: agg.day_count,
@@ -3103,6 +3268,9 @@ function refreshProspectSummaries(terms) {
3103
3268
  agg.last_seen_at,
3104
3269
  promoScore,
3105
3270
  promotedAt,
3271
+ status,
3272
+ resolvedEntityPath,
3273
+ feedbackTimeRow?.created_at ?? null,
3106
3274
  now
3107
3275
  );
3108
3276
  }
@@ -3127,6 +3295,7 @@ function getProspectBoostMap() {
3127
3295
  SELECT term, promotion_score, last_seen_at
3128
3296
  FROM prospect_summary
3129
3297
  WHERE promotion_score > 0
3298
+ AND status = 'prospect'
3130
3299
  `).all();
3131
3300
  const now = Date.now();
3132
3301
  const map = /* @__PURE__ */ new Map();
@@ -3142,7 +3311,7 @@ function getProspectBoostMap() {
3142
3311
  return /* @__PURE__ */ new Map();
3143
3312
  }
3144
3313
  }
3145
- function getPromotionCandidates(limit = 50) {
3314
+ function getPromotionCandidates(limit = 50, statusFilter = "prospect") {
3146
3315
  const stateDb2 = getStateDb3();
3147
3316
  if (!stateDb2) return [];
3148
3317
  try {
@@ -3150,15 +3319,21 @@ function getPromotionCandidates(limit = 50) {
3150
3319
  SELECT ps.*
3151
3320
  FROM prospect_summary ps
3152
3321
  WHERE ps.promotion_score > 0
3153
- AND NOT EXISTS (
3154
- SELECT 1 FROM entities WHERE name_lower = ps.term
3155
- )
3156
- AND NOT EXISTS (
3157
- SELECT 1 FROM entities e, json_each(e.aliases_json) j
3158
- WHERE LOWER(j.value) = ps.term
3322
+ AND (? = 'all' OR ps.status = ?)
3323
+ AND (
3324
+ ps.status != 'prospect'
3325
+ OR (
3326
+ NOT EXISTS (
3327
+ SELECT 1 FROM entities WHERE name_lower = ps.term
3328
+ )
3329
+ AND NOT EXISTS (
3330
+ SELECT 1 FROM entities e, json_each(e.aliases_json) j
3331
+ WHERE LOWER(j.value) = ps.term
3332
+ )
3333
+ )
3159
3334
  )
3160
3335
  ORDER BY ps.promotion_score DESC
3161
- `).all();
3336
+ `).all(statusFilter, statusFilter);
3162
3337
  const now = Date.now();
3163
3338
  const candidates = [];
3164
3339
  for (const row of rows) {
@@ -3167,6 +3342,8 @@ function getPromotionCandidates(limit = 50) {
3167
3342
  candidates.push({
3168
3343
  term: row.term,
3169
3344
  displayName: row.display_name,
3345
+ status: row.status,
3346
+ resolvedEntityPath: row.resolved_entity_path,
3170
3347
  promotionScore: row.promotion_score,
3171
3348
  effectiveScore: Math.round(effective * 10) / 10,
3172
3349
  promotionReady: effective >= PROMOTION_THRESHOLD,
@@ -3178,7 +3355,8 @@ function getPromotionCandidates(limit = 50) {
3178
3355
  bestConfidence: row.best_confidence,
3179
3356
  bestScore: row.best_score,
3180
3357
  firstSeenAt: row.first_seen_at,
3181
- lastSeenAt: row.last_seen_at
3358
+ lastSeenAt: row.last_seen_at,
3359
+ lastFeedbackAt: row.last_feedback_at
3182
3360
  });
3183
3361
  if (candidates.length >= limit) break;
3184
3362
  }
@@ -3227,6 +3405,7 @@ var init_prospects = __esm({
3227
3405
  "src/core/shared/prospects.ts"() {
3228
3406
  "use strict";
3229
3407
  init_vault_scope();
3408
+ init_levenshtein();
3230
3409
  PROSPECT_DECAY_HALF_LIFE_DAYS = 60;
3231
3410
  PROSPECT_DECAY_LAMBDA = Math.LN2 / PROSPECT_DECAY_HALF_LIFE_DAYS;
3232
3411
  STALE_AGE_MS = 210 * 24 * 60 * 60 * 1e3;
@@ -3566,8 +3745,8 @@ import {
3566
3745
  IMPLICIT_EXCLUDE_WORDS,
3567
3746
  COMMON_ENGLISH_WORDS
3568
3747
  } from "@velvetmonkey/vault-core";
3569
- import path12 from "path";
3570
- import * as fs8 from "fs/promises";
3748
+ import path13 from "path";
3749
+ import * as fs9 from "fs/promises";
3571
3750
  function setWriteStateDb(stateDb2) {
3572
3751
  moduleStateDb5 = stateDb2;
3573
3752
  setGitStateDb(stateDb2);
@@ -4694,9 +4873,9 @@ async function applyProactiveSuggestions(filePath, vaultPath2, suggestions, conf
4694
4873
  if (candidates.length === 0) {
4695
4874
  return { applied: [], skipped: [] };
4696
4875
  }
4697
- const fullPath = path12.join(vaultPath2, filePath);
4876
+ const fullPath = path13.join(vaultPath2, filePath);
4698
4877
  try {
4699
- const stat4 = await fs8.stat(fullPath);
4878
+ const stat4 = await fs9.stat(fullPath);
4700
4879
  if (Date.now() - stat4.mtimeMs < 3e4) {
4701
4880
  return { applied: [], skipped: candidates.map((c) => c.entity) };
4702
4881
  }
@@ -4705,7 +4884,7 @@ async function applyProactiveSuggestions(filePath, vaultPath2, suggestions, conf
4705
4884
  }
4706
4885
  let content;
4707
4886
  try {
4708
- content = await fs8.readFile(fullPath, "utf-8");
4887
+ content = await fs9.readFile(fullPath, "utf-8");
4709
4888
  } catch {
4710
4889
  return { applied: [], skipped: candidates.map((c) => c.entity) };
4711
4890
  }
@@ -4738,7 +4917,7 @@ async function applyProactiveSuggestions(filePath, vaultPath2, suggestions, conf
4738
4917
  return { applied: [], skipped: candidates.map((c) => c.entity) };
4739
4918
  }
4740
4919
  try {
4741
- await fs8.writeFile(fullPath, result.content, "utf-8");
4920
+ await fs9.writeFile(fullPath, result.content, "utf-8");
4742
4921
  } catch {
4743
4922
  return { applied: [], skipped: candidates.map((c) => c.entity) };
4744
4923
  }
@@ -4972,7 +5151,7 @@ __export(proactiveQueue_exports, {
4972
5151
  enqueueProactiveSuggestions: () => enqueueProactiveSuggestions,
4973
5152
  expireStaleEntries: () => expireStaleEntries
4974
5153
  });
4975
- import * as path13 from "path";
5154
+ import * as path14 from "path";
4976
5155
  import { statSync as statSync3 } from "fs";
4977
5156
  function enqueueProactiveSuggestions(stateDb2, entries) {
4978
5157
  if (entries.length === 0) return 0;
@@ -5044,7 +5223,7 @@ async function drainProactiveQueue(stateDb2, vaultPath2, config2, applyFn) {
5044
5223
  `SELECT COUNT(*) as cnt FROM wikilink_applications WHERE note_path = ? AND applied_at >= ? AND source = 'proactive'`
5045
5224
  );
5046
5225
  for (const [filePath, suggestions] of byFile) {
5047
- const fullPath = path13.join(vaultPath2, filePath);
5226
+ const fullPath = path14.join(vaultPath2, filePath);
5048
5227
  try {
5049
5228
  const mtime = statSync3(fullPath).mtimeMs;
5050
5229
  if (Date.now() - mtime < MTIME_GUARD_MS) {
@@ -5127,16 +5306,16 @@ var init_tool_embeddings_generated = __esm({
5127
5306
  model: "Xenova/all-MiniLM-L6-v2",
5128
5307
  dims: 384,
5129
5308
  version: 1,
5130
- generatedAt: "2026-04-12T00:48:32.483Z",
5131
- sourceHash: "3cef1ea2e0d037e6",
5309
+ generatedAt: "2026-04-12T22:35:09.128Z",
5310
+ sourceHash: "4787251246ff6139",
5132
5311
  tools: [
5133
5312
  { name: "correct", category: "corrections", tier: 2, descriptionHash: "ab104cbbf9d936e7", embedding: [-0.112137, 0.05077, 0.026377, 0.010174, -0.059357, 0.026808, -0.014668, -0.030909, 0.033262, 0.027611, 0.027976, 0.036543, 227e-6, -0.032873, 0.017395, 0.041123, -219e-5, 0.110179, 0.028379, -0.018504, 6275e-6, 0.070822, 0.0397, 3946e-6, 0.013957, 0.023896, -0.104276, 2763e-6, -0.014054, -0.122577, -0.015989, 0.079155, 0.027459, 0.044122, -0.023387, 0.090762, -0.021924, -0.017856, 0.051318, -0.045432, -9773e-6, -0.022173, -0.053484, -0.041077, 213e-6, -0.03298, -0.059949, -0.032224, -0.090868, 0.061656, 0.015128, -0.063887, -0.043796, 0.059185, -0.016482, 0.094751, 0.033966, 0.075673, -0.02664, -0.036574, 0.108109, -0.040591, -0.060051, -0.043626, -0.030352, 0.026759, 0.053429, -0.068346, 0.052479, -0.034162, 0.052643, -0.011244, 0.011792, -0.015615, -4771e-6, -1779e-6, -0.025966, 0.03719, -0.031432, -0.093345, -0.0162, -0.065183, 0.010272, 0.051686, 0.063362, -0.027996, -0.043456, -0.045347, 0.034818, 0.080175, -0.025879, -0.094627, 0.141497, -5965e-6, -0.065652, 0.031484, -6416e-6, -8356e-6, 0.069022, 0.060329, 0.058135, 0.106371, -0.034696, 0.010363, 0.079416, -0.010569, -9815e-6, 0.013082, -0.04944, -0.053058, -614e-6, 0.025107, 0.045675, -0.026209, 0.028465, -0.037018, -0.016706, 0.011322, -0.053478, 0.049009, 0.072959, -0.018558, -0.017536, 0.015453, -0.056476, -0.025292, -853e-6, 0, 0.109517, 0.051035, -436e-5, -0.02546, 0.053702, 0.012196, -0.092574, -0.067859, -0.082448, -0.030584, 0.04953, 5629e-6, 0.018349, 0.036023, -0.048056, 0.022057, -8418e-6, 0.093832, 0.020071, 0.060862, 0.018577, 0.046417, -0.022997, -0.010351, 0.028345, 0.073876, -445e-6, -0.014539, -0.027922, -0.016345, 0.02612, -0.048091, 0.067337, 0.029427, 0.042862, 0.02865, 0.037074, -0.067455, -0.039382, -0.083748, 0.014111, 0.041082, -0.044054, -0.088079, -0.022421, -0.026242, 1517e-6, 0.029601, 0.083941, -7021e-6, 0.042373, 0.076519, -0.038581, -0.023357, 1342e-6, 4167e-6, 0.014898, 0.026353, 4946e-6, 0.075959, 0.121664, -6181e-6, -0.04119, 188e-6, -0.05305, 0.056259, -0.014163, -0.082006, 0.033895, -3682e-6, -0.067722, 6538e-6, 0.030868, 0.050463, -5444e-6, -0.090016, -0.078164, -0.049525, 0.012905, 182e-5, -0.055408, -0.059239, -0.06449, 0.095689, -0.028328, -0.075978, 8404e-6, -0.073829, -0.039537, 0.014228, 4733e-6, -6572e-6, -0.023809, 0.02693, 0.053276, -0, 0.043507, -0.026395, -0.059847, 0.074179, -0.057412, -0.026139, 0.027878, 0.079916, 0.068508, 5595e-6, 4638e-6, -0.038802, -0.077282, -0.020645, -466e-6, -0.035289, -0.048797, -0.027662, -0.011941, 0.038905, 0.052053, -0.019324, -0.015524, 0.115244, 0.052004, 0.022335, 9845e-6, -0.043505, 0.032588, -0.057991, 0.014567, 4846e-6, -0.054494, -0.026246, 0.05298, -0.087103, 0.053247, -8393e-6, -0.078638, 9214e-6, 0.065006, 0.05517, -0.03903, 0.09994, 0.04905, -0.018042, -0.048194, 0.078942, -3651e-6, -0.035746, 0.03899, -0.058707, -0.019853, -0.017654, 0.048571, 0.028416, 0.026525, -0.093748, -0.026548, 0.03167, -0.052844, 0.060918, -0.052816, 0.029207, 0.042988, -1484e-6, -0.045086, -0.030614, -0.019668, 699e-5, 0.035397, -0.02612, -0.018835, -0.107687, 0.147089, -0.099558, -0.066147, -0.036173, -0.044325, -0.037926, -0.016089, -0.020625, 0.080158, 0.083126, -0.035453, -0.012411, -0.018514, 0.06544, -0.0458, 0.016839, -0.034864, -0.020352, 0.016488, -0.014599, -0.071506, -0, -0.170263, 0.022366, -0.019692, -9536e-6, 0.057014, 6094e-6, -0.027565, 0.095143, -0.029668, -0.056879, -1233e-6, 9667e-6, -0.043449, -0.102301, 0.013517, -0.034099, 0.034423, 0.053725, -0.069814, 0.018209, -0.069986, 0.058077, -0.019755, -0.056135, 673e-5, 4859e-6, 0.013008, 0.092358, 0.022798, -2356e-6, 0.044878, -963e-5, 0.08368, 0.036551, -6654e-6, -0.057746, 0.104987, -0.026351, 0.060275, 0.022709, 0.02862, 0.036379, -0.046548, 0.07899, -0.023751, -0.032051, 0.013826, -0.071854, 0.011729, -0.125561, 0.010702, -61e-6, -0.074215, 0.029655, -0.039268, 0.102985, 0.100883, -0.048536, 0.038982, -0.036561, 0.157337, -0.026732, 0.042879, -0.055083] },
5134
5313
  { name: "discover_tools", category: "search", tier: 1, descriptionHash: "aa8995ef7f47401b", embedding: [-0.075188, -0.021086, -0.070189, 0.027863, -0.011663, -0.111824, -0.030346, -0.055104, -0.028948, -964e-5, 0.048634, -0.057464, 0.033817, 7175e-6, 0.011836, 0.053405, -0.013156, -0.036403, 0.089025, -0.065241, 5382e-6, 0.037918, -5621e-6, -0.040135, 0.019724, -0.022742, -0.055146, -0.04527, 0.02007, -9524e-6, -0.016252, 0.057074, -4075e-6, 505e-6, 0.084357, 0.105241, 0.05814, 0.016512, -0.02048, -0.089392, -0.017279, -0.059956, -0.042557, -0.020422, -0.013626, -0.053287, -0.116333, -0.027996, -0.010748, 3943e-6, -0.046903, -0.094901, -0.06335, 0.072725, 0.058132, 0.109191, 7471e-6, -0.012742, -0.025956, -0.022849, 0.067187, -983e-6, -0.048119, 0.016697, -0.041044, 0.044199, 0.021653, -0.044895, 0.081919, -0.116255, 0.015069, -9135e-6, -0.039679, 0.027543, 0.106306, 0.056589, 0.032697, 0.038454, -0.035896, -0.151718, -0.069043, 0.051894, -0.029377, 0.069531, -0.023954, 0.071038, -0.014322, -0.028599, 0.076246, 0.016156, 0.020133, -0.134726, -0.073939, -0.071862, -0.018366, 0.013815, 7942e-6, -0.03676, 0.034956, -0.010209, -0.077494, -9537e-6, 0.029254, -0.084394, -0.044125, 0.099604, -0.063872, -0.014194, 0.061705, 0.017144, -0.021457, 1541e-6, 0.076249, -0.033957, 0.053548, 0.035583, -0.067036, -0.020214, -0.05177, 0.071649, 0.052922, 0.109373, 0.044848, -0.055537, -0.018694, 0.098885, -0.056785, -0, 0.105679, -0.019862, 2447e-6, 0.062664, -3153e-6, 0.03486, 0.047175, 0.018801, -0.059901, 0.02577, -0.057711, 0.059793, -0.061608, -7361e-6, 0.028895, 0.046272, 0.042275, 0.057409, 0.035205, -0.040239, -5299e-6, -0.014404, -0.029234, 0.043057, 0.101209, 0.053609, -0.0104, -3749e-6, 5548e-6, 0.025031, -0.06258, -0.024213, 0.034139, 0.067818, -0.018895, 0.079705, -0.010918, -0.026168, -0.028529, -0.01576, 0.023614, -0.019583, -0.054301, -0.089354, 0.020601, -0.080503, -0.067058, 0.028848, 0.072858, -0.012721, -0.016256, 7214e-6, 0.073557, 6098e-6, -0.011199, -213e-5, -0.01642, 0.033319, 0.053211, 0.038781, 0.033251, 0.018787, -0.070695, 0.089868, 0.011783, 3361e-6, 0.016143, -0.046838, 8084e-6, 0.089449, -0.043313, 0.061697, -0.040691, 0.012123, 0.024459, -0.148406, -0.037517, -0.057303, 0.024418, -7207e-6, -0.019377, -0.05232, -0.046205, 0.058728, 5983e-6, 0.013952, 0.021432, -0.042616, -0.043659, -0.068847, -0.091945, 9479e-6, -0.061069, 0.032148, 9958e-6, -0, 0.040652, -0.068116, 0.072305, 0.035184, -0.020632, -0.057712, -0.02841, -0.082632, -0.01321, 0.019844, 0.090441, 0.035095, -0.044615, -0.129175, 0.114251, 0.070678, -0.063627, -0.100181, 0.025629, 0.109847, -0.035361, 1383e-6, -0.115486, 0.04072, 0.041929, -0.067248, 8969e-6, -2463e-6, 0.018072, 135e-6, 9092e-6, 0.080653, -0.035027, 495e-5, -0.045352, 0.017452, 0.09904, -0.027698, -527e-6, -0.025174, 3514e-6, 0.049152, -0.099115, 7461e-6, -7823e-6, 0.040005, -0.014621, 0.05924, -0.024107, -0.047808, 0.085614, 0.017335, -0.010463, -0.049807, 2247e-6, 0.064009, 0.042356, 0.018684, -0.040498, -0.020599, 0.036185, -0.010663, -0.043319, 0.083483, -7926e-6, -6604e-6, -0.023185, 0.024318, -0.090426, -0.045626, 0.0199, 0.02269, 0.040662, -0.096964, 0.028033, -0.036186, -0.087325, -0.038926, -0.023116, 0.02771, 0.019014, -1276e-6, 0.118484, 0.010463, -0.033128, 7546e-6, -0.015151, 0.083676, -0.035601, -3541e-6, -0.089467, -0.032535, -0.070525, 0.024172, 0.02375, -0, -0.021465, 0.044607, 0.014306, -0.047116, 0.075083, 0.085343, -0.012816, 0.157587, -0.034197, 1913e-6, -0.029213, -0.019289, -0.014942, 0.041905, 0.029948, -0.013572, 0.025128, 9812e-6, -0.059942, -0.056379, 5458e-6, -252e-5, 0.057553, 3015e-6, 7678e-6, -0.072857, -0.057614, 0.030144, 0.038096, 3422e-6, -992e-5, -0.052856, 0.067301, -7253e-6, 0.093171, 0.057181, 0.024557, 3957e-6, 0.015116, 0.049431, 7994e-6, 0.033472, -5896e-6, -0.035395, -0.084564, -0.018945, 0.027141, 0.028566, 0.020801, -0.028642, -258e-5, -0.023189, -7276e-6, 1472e-6, 377e-6, 0.105597, 0.040329, -0.052133, 0.055025, -0.054046, 0.021824, -0.046932, 0.064667, -2851e-6] },
5135
5314
  { name: "doctor", category: "diagnostics", tier: 1, descriptionHash: "323b22c45b7357a0", embedding: [8136e-6, 0.012652, -0.104053, -0.012698, -0.020335, -0.074709, 0.022254, 0.084598, -0.054423, -0.045362, -3323e-6, 393e-6, 0.011297, 2735e-6, -0.027277, -0.012705, 1631e-6, 0.013887, 0.013833, -0.045375, 0.019835, 0.081895, -0.04618, 0.035734, -0.060544, -0.018431, -0.127578, -0.028479, -0.044941, -0.039594, -384e-6, -2425e-6, 0.036848, 0.076963, 0.022879, 0.048686, 0.088946, 781e-6, -0.054264, -0.044612, 0.015734, -0.079771, -0.043929, 0.013549, 0.030191, -0.045489, -0.119089, -0.053716, -0.04456, 0.067454, -0.057806, -0.057265, 316e-6, 0.121579, 0.011271, 0.05804, 477e-5, -0.031105, -0.097391, -0.061847, -0.036711, 176e-6, -0.032982, 0.057692, 0.034182, 0.053259, 0.032602, -9093e-6, 0.086273, -0.081044, -0.07594, -0.068649, -0.010132, 0.037269, -8189e-6, 0.029522, -0.016749, -0.043189, 1326e-6, -0.110331, -0.052518, 0.051387, -0.015152, 0.061301, -5324e-6, 0.085205, -0.019257, -0.026214, -49e-4, 9382e-6, 0.03915, -0.080184, 0.014607, -0.010532, -348e-6, 0.014564, -0.064922, -0.078807, 0.058181, 0.016433, -0.046079, 5318e-6, 0.076108, 6728e-6, 3499e-6, -0.047199, -0.013175, 0.016525, 0.013801, 5085e-6, 5752e-6, 0.042692, 0.053901, -0.056473, 0.098547, 0.018388, -0.102192, 0.032608, -0.048075, 0.091995, 0.072244, -0.012618, 0.0413, -0.041725, 0.054021, 0.011412, -3073e-6, -0, 0.079493, 0.014237, 0.049427, 0.06834, 0.059033, 0.05144, 0.014408, -0.04276, 0.015375, 0.011979, 0.022073, 0.120143, -0.010709, -0.024758, -0.021697, 0.049621, 4077e-6, 0.105483, -9952e-6, 0.041259, 0.02338, -0.015017, -0.010624, 0.023728, 0.102889, 744e-5, -0.037233, 0.013603, -0.033702, 799e-5, 5733e-6, -0.06343, -9938e-6, -0.071456, 0.048186, 9645e-6, 0.017757, -2797e-6, -0.021119, -0.065155, -0.060029, -0.060184, 0.018777, -0.011857, 0.010794, -0.07595, -0.090741, -2596e-6, 0.01942, 0.016046, 0.019233, -0.019173, 0.032646, -0.031759, 0.046188, -0.032001, 0.029469, -0.024869, -0.031216, 0.074847, 0.064354, -6935e-6, -0.056857, -0.020156, -0.059865, -0.043686, -0.030008, -0.089058, 0.043647, 0.041228, -0.070896, 0.037355, 4331e-6, 0.058013, 0.021254, -0.032409, -0.058646, -0.031653, -0.053518, -0.017684, -0.054452, 2916e-6, -0.050519, 0.150255, 8186e-6, 0.021956, -8975e-6, -0.045364, -0.087999, -0.051391, -0.108334, 0.031466, 7418e-6, 0.019992, -2294e-6, -0, -84e-5, -1124e-6, -0.028518, 0.041323, -0.028531, -0.02041, 7087e-6, -0.022711, 0.031301, 0.019491, 0.058479, 0.04317, -0.084726, -0.036933, 0.016874, 0.039338, -0.09775, -0.128744, 3347e-6, 0.097726, -0.017081, 0.045822, -0.074403, 0.076138, -0.050555, 0.055966, -0.030228, -0.014547, 0.054807, -0.075309, 0.053818, 0.028171, 1849e-6, 0.029274, -0.046137, -0.058202, 0.045929, -0.052037, -0.021068, 8679e-6, 0.114068, 0.031265, -0.035864, -0.036406, -0.059043, 0.029492, 0.036846, 0.012242, 3433e-6, -0.045454, 0.039008, -0.026932, -8463e-6, 0.07396, -0.013812, 0.062471, -0.048673, -0.035366, -0.131441, -0.034066, 0.047647, 0.033703, -0.06332, 0.073051, -0.054582, -0.061743, 0.098632, 0.018907, -0.074109, 664e-5, -0.011785, -0.055462, 0.036835, -0.053971, 0.068999, -0.028482, -0.102404, -0.09826, -0.063134, 0.065532, -0.030944, -0.070604, -0.028021, 0.067256, 0.027959, -0.04778, 0.070257, 1416e-6, 0.024908, -0.014259, -0.043247, -1922e-6, -0.095786, 0.017281, -0.010689, -0, -0.051685, 7184e-6, 0.049666, -0.031695, 0.023869, -0.015568, -0.017808, 0.06918, -7775e-6, 0.048827, 7195e-6, -0.027944, -0.114327, -0.100461, 0.11559, -0.020618, -0.052646, 0.081425, -0.068174, -0.052436, -0.034294, -561e-6, -0.013413, -0.039849, -3429e-6, -882e-6, 0.067595, 0.055667, 0.030007, 0.029895, 0.030387, 0.060059, 0.098835, -0.015598, 7647e-6, 0.065764, 0.063223, 1657e-6, 0.086573, 0.098405, 6676e-6, -2128e-6, 0.041294, 0.054462, -0.045867, -0.032182, -5717e-6, 0.047038, 0.057546, -0.088133, -2008e-6, -9601e-6, 0.045612, 0.083221, -0.036275, 0.087487, 0.086664, -0.049959, 0.046976, 0.034599, 0.095982, -0.021363, 0.069936, -0.01591] },
5136
5315
  { name: "edit_section", category: "write", tier: 1, descriptionHash: "8e0c997860daa732", embedding: [-0.067052, 0.048307, 0.015174, 0.067059, 0.027596, -0.052268, -0.071763, -0.016635, 0.023139, 0.019763, 0.021243, 0.053329, 0.077049, -0.038907, 0.047175, 0.033776, -0.06156, 0.062083, -0.017618, -0.018534, 0.054384, 0.096259, 0.066491, 0.045905, -2441e-6, -0.045738, -0.109804, 0.0359, -0.028463, -0.077512, 0.039082, 7961e-6, 0.051298, 0.024218, 0.053931, 0.08958, -798e-5, -5804e-6, 0.058097, -0.05296, 2235e-6, -0.0817, -0.082882, 0.068258, 4411e-6, -0.028889, -0.037087, -0.080344, -0.028016, 0.089782, -6375e-6, -0.123597, -0.040801, 0.093916, -0.083001, 0.072957, -0.017947, 0.016541, 2439e-6, -0.059709, 0.144232, 0.053963, -4015e-6, -0.045265, -0.010297, 0.023336, 0.061649, 0.050405, 0.011611, -0.0503, 0.061583, -0.02326, 0.026058, 0.017051, 0.026413, -0.02805, -0.071218, -6884e-6, -0.090258, -0.049108, 0.031765, 0.016722, -5343e-6, -0.010928, 0.033908, 0.043257, 2963e-6, -0.096023, 0.017447, 0.034006, 0.036735, -0.143404, 0.103961, -0.089369, -0.029156, 0.020612, -3701e-6, -0.082816, 0.028181, 0.025791, -0.020477, 1954e-6, 0.012171, 0.024567, 0.019771, 4542e-6, -0.011138, 0.073229, -0.056839, -0.029588, 3286e-6, -0.011874, -0.011458, -0.073342, -0.035939, -0.033083, 0.033741, 0.029137, -0.031901, 0.084325, 0.134047, -3984e-6, 4964e-6, 0.058164, -0.109967, -0.080984, -0.055905, 0, 0.092217, 0.063646, -0.100505, 0.06954, 0.019004, -0.021002, -0.018353, -0.034803, -0.062732, -0.046656, 0.042325, -0.063882, 0.013378, -4759e-6, -9881e-6, 0.010279, -0.011301, 0.086284, 0.010003, -3139e-6, -0.035402, 0.071308, -0.049256, -0.102604, 0.043115, 0.043318, -0.036904, -0.027319, -0.02966, -0.013341, 5451e-6, -8296e-6, 0.030978, 0.030911, 1773e-6, -0.019134, 0.023559, -0.046612, -0.043057, -0.03183, 0.033217, 2208e-6, 0.044079, -0.041489, 2237e-6, 0.045476, 0.028155, 0.068179, 0.017865, -0.098845, 0.044667, 0.081164, -0.032552, -0.032692, -0.021051, -0.043075, -1155e-6, -0.045039, 4792e-6, 0.020424, 0.09897, 8135e-6, -0.07348, 0.080432, -0.063947, -0.034491, -0.010039, -0.016932, 0.032387, -0.010912, -0.093681, 6393e-6, -0.042092, 0.058883, -0.04643, -0.113692, -0.104739, -0.021103, -0.033485, -0.011788, -9746e-6, -0.070301, -0.025267, 0.058342, 0.067454, 0.024718, 0.036855, -0.057702, -4955e-6, -0.113337, 0.028752, -0.042897, 0.03358, -0.061752, 0.100702, -0, 0.088136, -0.067319, -0.037074, 0.069494, -0.077527, 0.02395, -0.018071, 0.036678, 2396e-6, 3391e-6, -0.041165, 0.048665, -0.051129, -0.016925, -0.010118, -0.013078, -0.074828, -0.034036, -0.029894, 0.045862, 0.02358, -0.030888, 0.025567, 0.052181, 0.025056, -0.020087, -158e-6, 0.05592, 0.064273, -0.018629, -0.052678, 0.03067, -5597e-6, -0.024412, 0.01147, -641e-5, 0.036802, -0.07137, -0.026161, -1637e-6, 0.142442, -0.034615, 0.023111, 258e-5, -0.024848, 8382e-6, -4387e-6, 0.075396, -0.054066, -0.04846, 0.014834, -0.029765, -0.070955, -0.086352, 0.101422, 0.073069, -0.022721, 0.023387, -801e-6, -0.054793, 0.027974, 0.137145, -0.014716, 0.048945, 0.045883, -0.034078, -0.033381, 0.010678, -0.104538, -0.018514, 0.01488, -0.039602, 0.031921, -0.113138, 0.060907, -0.042833, 0.033138, -0.03025, -2764e-6, -0.027634, -0.03662, -4341e-6, -0.01968, 0.019597, 2712e-6, 0.017167, -0.019994, 0.095157, -0.05552, -0.035796, -0.030043, 263e-6, 0.106622, 0.026061, -0.05899, -0, 0.01673, 0.042963, -0.07519, -0.024475, 0.016026, 929e-6, -1818e-6, 0.061545, 0.023024, 0.013325, 0.022661, 0.027136, -0.052607, -0.077814, -0.079877, 0.028668, -0.028953, 0.063253, -0.049663, -0.028917, -0.046846, 0.096291, -331e-6, -0.072747, 0.028645, 0.03225, 0.020906, 0.06931, 0.081096, -0.024922, 0.044655, -0.056187, -9857e-6, 0.077085, 0.015907, 0.018662, 0.089081, -0.010739, 0.018846, 0.074224, 0.062288, -0.04758, -7368e-6, 0.058292, -0.010243, -0.014694, -1364e-6, -0.02006, 0.047091, -0.043469, 1525e-6, 0.034477, 7767e-6, -0.021154, -0.027786, 0.029545, 0.131995, 7411e-6, 0.014928, -0.018281, 0.086814, -0.022969, 0.087812, 9203e-6] },
5137
- { name: "entity", category: "note-ops", tier: 2, descriptionHash: "6f355127e2d93312", embedding: [-0.100629, -0.019147, -0.012268, 8454e-6, -0.041642, -0.022595, 0.022528, 0.031232, 0.043697, 4148e-6, 0.048717, -0.040364, 0.025579, -9384e-6, 0.077962, 0.135187, -0.034628, 0.068281, 0.041824, -0.06776, 0.050005, 0.056646, 0.029473, -0.026219, -9628e-6, -0.048486, -0.084752, -864e-5, -0.044524, -0.065356, 0.076176, 0.086837, -0.021603, 0.070353, 0.037528, 0.102601, -1281e-6, 0.030282, 0.049994, -0.043168, -7503e-6, -7144e-6, -0.066369, -0.059741, -0.060009, -0.042956, -0.084508, 3223e-6, -0.035479, 0.03919, -0.034094, -0.081764, -0.034246, 0.036477, -0.018496, 0.087434, -0.077353, 0.014175, -0.080933, -0.040206, 0.034672, -25e-4, -4609e-6, -0.051354, -0.052456, 0.036026, 0.058453, 0.039455, 0.047886, -0.031408, 0.088103, -0.021086, -0.082108, -0.02201, -0.01935, -0.020383, -0.041727, 0.020292, -0.123944, -0.069517, -0.078441, 0.015468, -0.017305, -0.048208, 0.02302, 0.037177, -0.018822, -0.061427, -0.016562, 0.018883, -0.046454, -0.088637, 0.108576, -0.040239, 0.038366, 0.08183, 0.060814, -0.052198, 0.03699, 0.073554, -0.045235, 0.094083, -0.011956, 9771e-6, 0.058968, 2982e-6, -0.01876, -0.027112, -0.016229, -0.025948, 8924e-6, 0.050227, 8632e-6, -0.026207, 0.043229, -0.019268, -0.020583, 1108e-6, 0.030515, -0.020086, 0.121816, 0.023778, -0.02008, 0.016491, -0.060705, 0.019534, -0.076719, 0, 0.092888, 0.0833, 0.015084, 0.017026, -0.010961, 0.015634, -0.057442, 0.040796, -0.036807, 9892e-6, 8859e-6, -0.016085, 0.035898, -0.019105, -0.070554, -0.01701, 0.013778, 0.126596, 0.017814, 0.043126, -0.016213, 0.120106, -0.039166, 0.018202, 0.030385, 0.048716, -0.029254, -0.017425, 1322e-6, -9135e-6, -9846e-6, -0.014903, 0.050475, 0.086552, 0.036696, 0.092282, -0.012152, -0.051567, -0.055415, -0.084785, 0.04577, 0.042443, 1882e-6, -0.072828, -0.04888, 0.011407, 0.026114, 0.027615, 0.12219, 0.0429, 4437e-6, -684e-6, -7656e-6, 0.085937, -0.03026, -0.081487, -0.034849, -2124e-6, 7658e-6, 0.029509, 0.01088, 319e-5, -0.085866, 0.025678, -0.034432, -0.010218, -0.040119, -8124e-6, 0.126853, -0.032289, 0.030447, 0.070177, -0.020779, -0.01338, -6954e-6, -0.123532, -0.016189, -0.033243, 0.036244, 0.037478, 0.011411, -0.087901, -0.071999, 0.050142, 9191e-6, 0.020481, 0.019449, -0.091421, -0.055874, -8599e-6, -0.084735, 0.050152, -6471e-6, 0.011489, 0.057276, -0, 0.082606, -6195e-6, -0.012493, 0.02044, -0.017842, 0.010904, 0.058058, -6064e-6, -0.082318, -0.013658, -0.06603, -0.016067, 0.035833, -0.077605, 0.019371, -0.071972, -0.023667, -0.01149, 0.021055, 0.06103, -0.02893, 0.013027, 0.0207, 0.082176, 0.06235, 0.011402, -5057e-6, -0.061155, 0.011427, -0.087414, 0.083986, -7917e-6, -0.068873, -0.085021, 0.027911, -0.090392, -0.016361, 2083e-6, -0.049074, -0.013122, 0.02764, 0.023639, -0.026668, 0.037592, 0.015583, -0.046653, -5489e-6, 0.06456, -4707e-6, -0.065271, 0.024832, -0.061204, -0.07221, -0.072748, 0.028508, 1374e-6, 0.082447, -0.049678, 9389e-6, -0.014546, 0.019181, 0.086544, 114e-5, 0.046031, 0.033237, -0.124293, -0.013722, 9733e-6, -0.057916, -1262e-6, -0.010563, -0.031844, 0.018659, -0.095989, 0.087798, -0.096582, -0.047346, -0.122894, 9304e-6, -0.051909, -0.057697, -0.038628, 0.042723, 0.018828, -0.046077, -0.051778, 7643e-6, 0.103698, -0.049812, 0.088104, -0.016873, -0.042169, 0.035742, 0.052216, -0.064252, -0, -0.059741, 0.09134, -0.030521, -0.017591, -0.025831, -0.069275, -1805e-6, 0.047714, 0.026374, -0.015537, 0.011005, -0.011809, -0.110933, -0.013291, 0.081842, -0.064416, 0.010109, 0.043389, -0.063112, 444e-6, -0.083475, 85e-6, -0.030052, -0.061645, 0.011825, 0.024882, 0.021731, 0.079545, 0.060196, 0.035125, -8516e-6, 0.026794, 0.023016, 0.019673, 0.010372, -6088e-6, 0.053429, -0.011274, 0.02674, 0.055798, 8515e-6, 0.011313, -0.03572, 0.076518, 0.036774, -0.011111, 0.023585, -0.053034, 0.050328, -0.031771, -0.019461, 2813e-6, 3779e-6, -0.012392, -0.021355, 0.072229, 0.110348, 0.030041, 0.070951, -0.050574, 0.131781, -0.113341, 0.014638, 0.058075] },
5316
+ { name: "entity", category: "note-ops", tier: 2, descriptionHash: "fc7968d14b8c9cab", embedding: [-0.074349, -0.030711, -4673e-6, 0.014717, 0.016205, -0.039608, 0.021641, 0.023785, 0.014913, -0.011524, 0.060717, -0.039357, 0.013297, -4344e-6, 0.05836, 0.101867, -0.04183, 0.10595, 0.044607, -0.015519, 0.024446, 0.073093, -4335e-6, -0.021167, 8419e-6, -0.099374, -0.081139, 0.015894, -0.066548, -0.096353, 0.055687, 0.134062, -7137e-6, 0.073362, 0.032144, 0.061337, -0.026326, 0.04838, 0.037707, -0.045823, -0.011087, -0.067804, -0.056536, -0.030159, -0.057211, -0.05053, -0.051258, -0.029718, -0.01872, 0.031035, -0.028443, -0.109819, -0.026341, 0.074417, -0.05862, 0.068507, -0.056374, 0.013294, -0.058399, -0.04427, 6184e-6, 0.016332, -0.02226, -0.016271, -0.037241, 0.022785, 0.063241, 0.033494, 0.051421, -0.08406, 0.075491, -0.027314, -0.117858, -2328e-6, 0.010446, -821e-5, -772e-5, 0.024936, -0.042996, -0.075486, -0.081466, 0.034634, -0.015721, -0.057664, -1425e-6, 0.040765, 6163e-6, -0.049531, 0.034535, 0.027097, -0.033255, -0.113266, 0.113385, -3497e-6, 2225e-6, 0.029856, 0.053917, -0.097292, 0.011401, 0.072309, -0.065279, 0.078804, -0.064662, -0.020436, -0.01586, -0.030065, 1e-5, -0.02242, 0.027148, -0.021899, -2489e-6, 0.036677, -0.022297, -0.060509, 0.031537, 0.011305, -0.065819, 0.041585, 0.04277, -0.089205, 0.081537, 0.043829, 8431e-6, -0.038149, -0.084868, 0.019989, -0.077351, 0, 0.072938, 0.07783, -0.016321, 0.013197, 0.014578, 3365e-6, -0.029743, 0.041672, -0.066253, 708e-6, -7259e-6, 0.04384, 0.02702, -0.017667, -0.047038, -0.042624, 0.059663, 0.16348, 0.056527, 0.021449, 9796e-6, 0.132062, -0.016521, 0.018898, 0.046219, 0.026494, -0.037787, -1333e-6, 0.012356, 0.0304, -0.017244, -7358e-6, 0.02361, 0.066725, 0.055691, 0.068757, -0.020913, -0.07959, -0.019111, -0.056279, 441e-6, 0.027094, -0.03443, -0.039197, 0.028451, -0.05634, 0.053026, 3143e-6, 0.097281, 0.049942, -2061e-6, -0.022903, -6358e-6, 0.05247, -0.045488, -0.076316, -0.043571, -0.017934, 2056e-6, -0.013093, 0.017602, -2454e-6, -0.119375, -0.017161, -0.037515, -0.015248, -0.037564, -0.035183, 0.10312, -1734e-6, 0.012156, 0.075233, -0.015103, -0.014867, -7548e-6, -0.106772, -0.010453, 0.020751, 0.065799, 0.017364, 1713e-6, -0.073032, -0.098151, 0.048889, 0.038104, 0.041838, 0.054251, -0.070533, -0.067247, -0.030549, -0.090314, 0.042169, -0.022402, 0.038134, 0.080058, -0, 0.072156, -0.028521, -0.040202, 0.027863, -0.023641, -0.024939, 0.043483, -0.027534, -0.086423, -0.044268, -0.062423, -2552e-6, 0.013815, -0.058316, -6794e-6, -0.058177, -0.034242, -0.020941, -0.039637, 0.087961, -0.015674, -725e-5, 2886e-6, 0.06314, 0.06, 6294e-6, 8963e-6, -0.03842, 8355e-6, -0.073809, 0.071558, -812e-5, -0.069666, -0.075252, 0.015169, -0.061867, 3546e-6, -0.050793, -0.066527, 8e-6, 0.03084, 0.019838, -0.011502, 0.020877, -874e-6, -0.024372, 5663e-6, 0.057321, 0.031993, -0.05237, 0.011831, -0.013311, -0.066601, -0.047359, 0.01335, 0.016531, 0.072481, 0.01181, 0.020594, -0.028156, 0.067552, 0.102041, 0.035974, 0.075115, 0.051617, -0.117679, -0.017597, 0.052714, -0.101744, -0.023201, 0.023351, -7892e-6, 0.03825, -0.099066, 0.048381, -0.118559, -0.018954, -0.109564, 0.015335, -0.014241, -0.016968, -0.0125, 0.026907, -0.015773, -0.011793, -0.042037, 5008e-6, 0.099264, -108e-5, 0.035198, -5905e-6, -0.067192, 0.011385, 0.07176, -0.054807, -0, -0.01612, 0.098306, 2e-5, -0.011442, 0.030306, -0.050975, -0.028135, 0.074353, 0.020353, -0.042162, 0.022544, -0.011764, -0.106717, -0.017467, 0.134766, -0.050684, -3099e-6, 0.053383, -0.06475, 475e-6, -0.07621, 3452e-6, -0.022456, -0.056419, -524e-6, 0.028282, 0.014936, 0.074807, 0.080093, 2737e-6, 0.021908, 0.013577, 0.023381, 0.016646, 0.027662, 0.080965, 0.034267, -6876e-6, 0.035, 0.079081, 0.013812, -0.018612, 878e-5, 0.095351, 0.018059, 2524e-6, 0.016052, -0.061828, 0.030652, -0.043824, -0.032389, -8527e-6, 8395e-6, 0.040602, -0.0146, 0.07797, 0.057081, 618e-6, 0.026012, -0.017675, 0.145267, -0.125366, 7407e-6, 0.069939] },
5138
5317
  { name: "find_notes", category: "read", tier: 2, descriptionHash: "e43ef3fc29d690a1", embedding: [-0.054341, 0.039439, -0.044432, 0.022322, 0.011014, 0.021297, -4058e-6, 0.063912, 6699e-6, -0.020245, 0.036915, 0.014972, 0.02641, -0.0168, 0.054404, 0.068953, 0.044485, 0.014181, 0.064311, -0.026328, 0.077049, 0.078528, 0.043754, 0.011862, 6072e-6, 0.065804, -0.144039, -0.017154, 4967e-6, -1893e-6, 0.018293, 0.105838, 0.074875, 0.064933, 9055e-6, 0.056938, 9252e-6, 0.015548, 8381e-6, -0.039663, -0.056536, 0.035168, -0.03837, -8193e-6, 0.01818, -0.057859, -0.036215, -0.068611, -4045e-6, 0.031883, -0.112803, 4856e-6, -0.098483, 0.039872, 0.061848, 0.074749, -6271e-6, -0.029598, -0.064662, -0.058485, 0.081913, -0.06918, -9205e-6, -0.041496, 0.014628, -0.027251, 0.05546, -0.013967, 0.05891, -0.114635, 0.083853, 0.018713, 0.035283, 0.036248, 0.018283, -1241e-6, 0.011769, -0.046454, -0.080704, -0.105532, -0.096056, 0.035184, 0.033308, 0.028251, 0.015954, -0.050287, 0.023437, -0.061715, 201e-6, 0.044144, 0.088367, -0.102717, -0.022125, -0.028262, -0.012286, 0.033757, 8688e-6, -0.022029, 0.081943, 0.018609, 0.072085, 0.090256, 0.013671, -6267e-6, -0.026406, 0.049545, 934e-5, 0.030417, -0.016597, -0.100792, -0.018438, 0.011967, 0.02029, -0.048835, -647e-5, -0.107246, 0.026166, -0.03588, 0.038517, 0.098497, 0.066761, 8518e-6, -0.013316, -0.011762, -0.072731, 0.028334, -0.091472, 0, 0.048616, 0.012847, 0.027144, 1156e-6, -0.025398, -0.016007, 0.032083, 0.065254, -0.070518, -0.036161, 0.035027, 0.056406, -0.028495, 0.032387, 0.02176, 8554e-6, -0.025108, 0.074236, 0.032739, -0.022668, 0.028385, -0.010285, 0.048268, -0.03827, 0.050248, 0.019086, -0.043955, -0.068474, -0.02828, 0.012578, -0.034184, -0.049215, 0.026051, -0.038005, 0.013429, 0.063066, -0.044237, 0.029965, 996e-6, -0.129581, -0.026558, 6055e-6, 0.01535, -0.066075, -0.042532, -1706e-6, -0.105433, 0.06226, 0.085967, 0.010674, 0.014807, -9169e-6, -0.048066, 0.045601, 0.054746, 0.031343, 0.056235, 0.0533, -0.030893, -1126e-6, 0.022036, 6203e-6, -0.013592, 0.035852, -0.042473, 7124e-6, 2208e-6, -0.033978, 0.075161, 0.054846, -4754e-6, 0.0502, 0.055544, 0.048583, 0.015212, -0.086446, -0.050873, -0.109523, 0.029365, -0.04682, -0.056148, -0.020004, 7237e-6, 0.081601, -0.036359, 0.028221, 0.036311, -0.156106, -0.010089, -0.046791, -0.11062, 0.02759, -0.068914, -0.038736, -0.050262, -0, 0.035006, -0.035668, -0.019049, -0.014392, -5142e-6, 0.017456, -0.037488, -0.012334, 0.037256, 0.072443, 7493e-6, 3859e-6, -0.039783, -0.033929, 0.022894, 0.026035, -0.018817, -0.0455, 0.024698, 0.022968, -0.085025, 0.024032, -0.065655, 0.086953, 0.035452, -0.0146, -0.044447, -0.069359, 0.016187, -0.042209, 8918e-6, -0.056148, -0.039114, -0.029694, -0.086095, -0.016938, 0.015871, -0.079043, -0.082079, 0.114878, 0.016947, 0.103945, 0.026252, -0.047287, -0.035133, -0.034462, -0.040436, 0.082758, -0.016521, -0.032669, 0.126392, -0.055838, -0.033721, -0.017031, -0.021902, 0.05615, -0.013186, 0.012233, -0.096453, -0.038843, -3245e-6, 0.0643, -0.092457, 0.061311, 0.015543, -0.089837, -0.010332, -0.042464, -0.103932, 5331e-6, -0.010902, 6017e-6, 0.053773, -0.02847, 0.063789, 0.058411, -0.049378, -0.036728, -0.034957, -0.04661, -1056e-6, -0.020962, 0.075972, 0.075697, -0.022339, -0.014775, -9826e-6, 0.086344, -0.038529, 1179e-6, -0.017339, -0.090336, 0.035132, 0.036094, 0.031364, -0, -0.123306, -0.056555, -0.064158, -2092e-6, -0.012719, 0.033651, 0.028565, 0.071721, -0.017412, 0.044538, 0.050581, -0.060295, -0.113453, -0.018418, -0.029911, 538e-5, 0.093897, 0.014913, -0.048809, -0.033582, 0.019178, 0.055919, -0.033986, -1684e-6, 0.034307, 0.017134, -0.03497, 0.082927, 0.011102, 0.014656, 0.04996, 0.049819, 0.014126, -7041e-6, 0.067124, 0.042589, 0.053929, -5299e-6, -0.051256, 0.121051, 0.067496, 0.039915, -0.069309, 0.045262, 0.046579, -0.033982, -0.031061, 0.02494, 0.022027, -0.042985, -0.033733, -0.029843, -0.051682, -1858e-6, -0.059954, 0.07073, 0.056452, 0.042733, 0.049113, -0.097473, 0.142043, 0.027087, 0.037172, 0.047505] },
5139
- { name: "graph", category: "graph", tier: 2, descriptionHash: "703eac0e78047993", embedding: [-0.047542, -0.017091, -0.057158, 5487e-6, -6488e-6, -0.022231, -0.070787, -0.022759, 0.025792, 0.028633, 0.0364, 0.03961, 0.054147, 873e-5, 0.017381, 0.094917, -0.019964, 0.040847, 0.058493, -0.068506, -342e-6, -0.020037, 0.043323, 4325e-6, 0.029512, -0.023735, -0.089916, -0.018763, 0.013641, -0.04191, 0.026041, 0.040601, -0.020553, 0.010557, 0.042208, 0.181715, 7074e-6, 5712e-6, 0.023646, 4338e-6, 432e-5, 0.037711, 0.018819, -0.0243, -0.022201, -0.027663, -0.145709, -6562e-6, -0.075342, 0.063097, -9672e-6, -0.041302, -0.080248, 0.014835, 0.034296, 0.098916, -0.053608, -0.025434, -0.036178, -0.027006, 0.158196, -0.016922, -0.060067, -0.046861, 0.028707, 0.065021, 0.046107, 0.083937, 0.014439, 0.022066, 0.081683, -0.05237, -0.075361, 0.01369, 0.027317, 0.067257, -0.022498, 0.034327, -0.067976, -0.165633, -0.020947, -5539e-6, 0.014138, 0.028045, 0.02539, 0.047332, -0.024606, -0.094931, 9e-5, 0.026627, -0.018597, -1563e-6, 0.040593, -0.033558, 0.016097, 0.026942, 778e-5, -4264e-6, 5343e-6, 0.058767, -0.024846, 0.048911, 0.073937, -5878e-6, 0.055448, 0.068468, -0.020825, 0.054737, 0.011784, 0.02343, -0.010527, 0.024216, -7067e-6, -0.032795, -0.010725, -0.062793, -0.015045, -4192e-6, 0.033306, 0.038224, 0.071737, 0.023681, 0.076475, -0.05277, -0.066174, -0.071716, -0.080636, 0, 0.073546, 0.027484, 0.041152, -0.03904, 0.027834, -0.035344, -0.084845, -0.044584, -0.075003, 0.025835, -0.052757, 0.068486, 0.019467, -142e-6, 0.018284, -0.027203, 0.048632, 0.051248, -0.015613, -0.071219, -0.011806, 0.031777, -0.014001, 0.029061, 0.079655, 8503e-6, 0.01328, -0.028395, -0.010885, 309e-5, -0.01482, 0.043175, 0.060452, 0.019172, -3105e-6, 0.053891, -8291e-6, -0.071199, -0.026106, -0.071493, -3447e-6, -8334e-6, 0.032179, -0.070364, -0.070039, 9005e-6, 0.022682, -0.037311, -0.02163, 0.029654, -0.036171, 4922e-6, -0.025761, 0.069603, -0.017735, -0.103676, 0.010034, 0.057583, 0.030451, 0.093369, 0.068097, -9214e-6, 0.015565, 0.043513, -0.04114, 0.023114, -0.102831, -0.021443, 0.111552, 0.049429, -0.056711, 0.074538, 5024e-6, 0.021321, -0.021582, -0.082287, -0.098337, -0.096037, -0.027566, 0.012162, -0.095489, -0.122899, -0.020544, 0.044765, -5484e-6, -0.017506, 0.011568, -0.101228, -0.054133, -0.035595, -0.029581, 0.013098, 0.011979, 0.01931, 0.036979, -0, 0.0419, 0.066204, 0.104679, 0.011695, 0.044598, -0.017038, 0.039061, -0.075911, 963e-6, 0.123669, -0.042132, -9745e-6, 7335e-6, -0.053677, 0.077622, -0.023368, 0.033319, -0.075056, -0.018775, 0.037757, 0.016194, 0.015606, -0.059052, 0.047877, 0.136025, 0.031192, 0.015582, -0.108001, 0.028538, -0.011087, -0.039511, -0.031294, -0.063943, -0.049795, -0.019816, 0.028729, -0.019791, 0.02333, -0.03528, -0.067343, 0.065956, -1257e-6, -0.06698, -59e-4, 0.029897, 0.034886, -0.065417, 0.03844, -0.146799, -0.071358, 0.031553, 0.031839, 0.033336, -0.061572, 5449e-6, 678e-6, 0.038638, 0.021067, -0.02855, -0.011252, 4541e-6, -8188e-6, -0.053493, 0.041529, 6198e-6, -0.074688, -0.017892, -0.037559, -0.114721, 0.037904, 0.032661, 0.039917, -5092e-6, -0.065467, 0.083618, -0.053572, -0.043618, -0.040466, 0.011861, -0.035734, -0.058813, 0.033318, 0.074165, 0.072268, 592e-6, 0.020913, -43e-5, 0.082002, -0.024938, 0.065375, -0.03162, -0.031838, -0.021516, 0.026818, -0.054022, -0, -0.103672, 0.06087, -0.02238, -0.03284, 0.04106, 0.02235, 0.08225, 0.144348, 1933e-6, 0.106603, 0.069362, 0.02221, -0.074261, 0.016653, -0.037969, -0.068225, -0.010494, -255e-5, -0.058586, -411e-5, -0.070177, 0.014684, -0.02587, 0.06587, -0.013759, -0.075817, -0.013767, 0.06431, 0.01628, -3982e-6, -8164e-6, -0.019936, 0.024202, -7332e-6, -0.055074, 0.079617, 0.036323, 0.041899, -0.029698, 0.088464, -0.021895, 0.018835, -0.010198, 0.060221, 0.034901, 6104e-6, -0.019134, 0.02922, -466e-6, -0.099927, -0.045055, -0.077526, -0.068817, -0.071031, 5925e-6, 0.014568, 0.04785, -5194e-6, 0.061949, -7945e-6, 0.087316, -0.069593, -2345e-6, -0.053444] },
5318
+ { name: "graph", category: "graph", tier: 2, descriptionHash: "1b79c0ca03886cbd", embedding: [-0.035909, -8846e-6, -0.041507, -4788e-6, 0.032173, -0.065733, -0.096299, 0.023865, -5473e-6, 0.041158, 0.066489, 0.02576, 0.015557, 0.030437, 0.040624, 0.063476, -0.031096, 0.02673, -4251e-6, -0.072202, 0.028127, -0.013806, 0.016571, -485e-6, 0.048246, -0.043761, -0.067387, -0.016971, 0.035629, -0.069259, -0.033511, 0.033872, -0.013958, 0.055208, 0.013192, 0.134415, 0.031984, -0.014654, 0.024033, -7977e-6, 0.023797, 0.02113, 6925e-6, 0.016055, -2678e-6, 8251e-6, -0.158198, -0.015489, -0.078854, 0.047337, -0.054456, -0.019368, -0.093306, 0.037513, 0.048442, 0.093579, -0.077433, -0.085391, 1507e-6, 0.0361, 0.106361, -0.014488, -0.067992, -518e-5, 0.019918, 0.055019, 0.051241, 0.063897, 0.026877, -0.011902, 0.032036, -0.051093, -0.116894, 0.03736, 0.024688, 0.09436, -0.010614, 0.020526, -0.082658, -0.153377, -0.017834, 0.050199, -0.015689, 0.079668, 2802e-6, 0.017534, -647e-6, -0.024686, -0.017222, 0.047876, -0.03712, 0.011261, 0.049175, -0.015074, -0.025875, 0.049774, 0.050972, -0.040303, -993e-5, 0.024068, 0.017379, 0.029883, 0.07355, -0.043429, -3096e-6, 0.037051, -8769e-6, 0.033582, 0.037079, 0.032086, -0.048391, 0.064836, -0.01385, -0.068058, -0.018794, -0.04012, -0.041947, 1945e-6, 0.034552, 0.052581, 0.056469, 5902e-6, 0.089737, -0.04318, -0.06051, -0.073695, -0.070785, 0, 0.056419, -0.011847, 567e-5, -0.017629, 0.018553, 0.012356, -0.066543, -0.068152, -0.091452, -113e-5, -0.092888, 0.104693, -0.024249, 0.07725, 0.044893, 2658e-6, 0.075136, 0.0447, 0.027947, -0.081548, -155e-6, -3673e-6, 0.012653, 0.040394, 0.10984, 0.01713, -0.022906, -0.046898, -3747e-6, 0.014631, -0.01398, 0.028551, 0.057564, 0.042347, 0.018958, 0.055598, -8864e-6, -0.101964, -0.030339, -0.075357, -0.052891, 662e-5, -0.013085, -0.05675, -9617e-6, -0.020113, -0.024186, -0.045889, -0.015118, 8751e-6, -0.057937, 0.014473, -2387e-6, 0.056074, -0.040174, -0.072804, 0.033112, 5334e-6, 0.026634, 0.096673, 0.029418, 7971e-6, -0.022942, 0.021743, -5642e-6, 0.017654, -0.139056, -0.047749, 0.027206, 0.096436, -0.042175, 0.06749, -0.016763, 0.012173, -0.022599, -0.07406, -0.082232, -0.107685, -0.021949, 0.015389, -0.106065, -0.117851, -0.078646, 557e-5, 355e-6, -0.021651, 0.034759, -0.072601, -0.042125, -0.016595, -0.012008, -0.012026, 0.036182, 1756e-6, 0.017921, -0, -3726e-6, 0.057055, 0.075166, 0.042236, 0.019585, -0.033961, 0.031402, -0.046679, -0.024065, 0.095275, -0.025657, -7449e-6, 0.02645, -0.068149, 0.057246, -0.030347, 0.025119, -0.051593, -0.018231, 0.074431, 0.025042, 0.041597, -0.068957, 0.053691, 0.114658, 0.052031, -0.011683, -0.053284, -0.014647, -348e-6, -0.047916, -0.012494, -0.029503, -0.063356, -934e-5, 0.023811, 0.070161, 9065e-6, -0.013438, -0.08371, 0.03976, 3717e-6, -0.06143, 0.011024, 0.034923, 0.074841, -0.078253, 0.075583, -0.099467, -0.021035, 0.031164, 0.050478, 0.040432, -0.080587, 0.025723, -0.033508, 0.018159, 0.050579, -0.06037, -0.033205, 4755e-6, -0.052926, -0.025845, 0.018374, -4346e-6, -0.03559, 0.011767, -0.011414, -0.125719, 0.038514, 0.051124, 0.069008, -0.015001, -0.061625, 0.062973, -0.067971, -0.071943, -0.020063, 0.018023, -8429e-6, -0.02391, 0.06376, 0.075836, 0.063692, 0.036226, 2423e-6, -0.012509, 0.109564, 0.021036, 0.02948, -0.059277, 0.01145, -0.082244, 0.05629, 0.015731, -0, -0.103531, 1861e-6, 0.01781, -0.036761, 0.044794, 0.054737, 0.082738, 0.130013, 0.013382, 0.088058, 0.083813, 0.055207, -0.116237, -0.011257, 4223e-6, -0.05385, -4549e-6, 0.013901, -0.031821, -0.039662, -0.082183, 0.027529, -0.021048, 0.074416, -0.013113, -0.102264, 8101e-6, 0.071966, 0.011139, -0.058671, 7962e-6, -0.043302, 0.070593, -1162e-6, -0.063857, 0.084633, 0.022543, 0.031713, -0.036442, 0.046021, 3134e-6, 0.034636, -0.030223, 0.036736, 0.012025, 0.012226, -0.022447, 0.018082, -3682e-6, -0.080533, -0.039335, -0.082823, -0.05142, -0.017032, 657e-6, 0.012916, -5871e-6, -0.036762, 0.07996, 0.010178, 0.103885, -0.067465, 9337e-6, -0.03209] },
5140
5319
  { name: "init_semantic", category: "search", tier: 2, descriptionHash: "33cdfeef485b49c6", embedding: [-0.025452, -0.048845, -0.011618, 0.023209, -0.024364, 0.03137, -0.053247, -0.042608, -0.051363, -0.036246, 0.011666, -0.082152, 0.056721, -3851e-6, 0.042404, 0.11714, 0.091872, -2772e-6, 0.010569, -0.027861, 0.058213, 0.036962, 0.042226, -0.037348, -0.043087, -6366e-6, -0.083984, -0.041254, 0.058968, -0.014554, 0.081354, 0.118492, -0.024363, 0.128628, -0.022981, 0.039297, -0.043987, -0.04519, -359e-6, -0.093715, -0.035612, 0.024908, -0.043093, 0.013066, 0.041861, 4982e-6, -0.101195, -0.062399, -0.03433, 0.026001, -0.119525, -2e-5, -0.046593, -6613e-6, 0.058065, 0.051141, -0.044697, 0.044936, -0.01502, -0.096312, 0.01898, -0.077467, 0.033712, -7687e-6, -0.021349, -0.025106, 0.045974, -0.023106, 0.073984, -0.050748, 0.052893, -0.014656, -0.045655, -0.015265, 3907e-6, 0.066162, 5096e-6, 0.011062, -0.029671, -0.135103, -0.064705, -0.03225, 0.04815, 0.03963, 0.057509, -0.052253, 0.039816, -0.093817, -8e-6, 0.031132, 0.084445, -0.099612, -0.02881, 8035e-6, 0.045018, -0.016475, 0.027816, 0.015622, 0.091962, 9961e-6, -0.014911, 0.056744, 0.024435, 0.026216, -0.053843, -0.019819, -0.014845, -0.010925, 0.046932, -0.103588, 33e-6, 0.014263, 0.087409, -0.035952, 1046e-6, -515e-5, 0.025704, -0.072284, 0.118985, 0.060917, 0.031497, 0.072897, -0.043803, -0.042411, -0.109211, 0.03381, -0.042281, 0, 0.080843, -0.013474, 8398e-6, 0.057869, -0.011194, 0.037514, 0.039225, 0.088839, -0.11312, -0.059102, -0.070631, 0.031955, -0.019724, 0.075456, 0.020453, -0.050863, -0.068314, -681e-6, -7973e-6, -7078e-6, 0.050153, 0.029361, -0.046185, -0.036473, 0.015387, 0.028065, 0.056587, -0.094002, -0.010984, 0.019087, -0.069289, -0.027765, -0.059082, 0.025227, 0.011601, -5e-4, -0.029371, 0.048577, -0.090619, -0.123844, -0.027863, 0.028224, 535e-6, -0.129364, -0.057459, 6837e-6, -0.042504, 0.018358, 0.066213, -0.016728, 0.046329, 0.059504, -0.014251, 5446e-6, 0.092261, 0.033873, 0.043768, 0.044972, 0.018907, 0.010377, 1453e-6, -0.012784, 4795e-6, 0.076529, -0.031376, 0.061178, 0.041996, -0.01385, 0.089266, 0.025233, 0.057706, 0.017261, 0.029684, -0.062645, -8791e-6, -0.110273, -0.03159, -0.104761, -0.041266, 0.033456, -0.053093, -0.028247, 5277e-6, -0.010504, 0.01649, -0.016958, 0.021029, -0.144161, 0.042318, -0.017862, 0.014535, -0.064415, -0.031891, 5534e-6, -3548e-6, -0, 0.028299, -0.048146, 0.035547, 0.046838, -0.055222, -0.033674, 0.047132, 0.05698, -6422e-6, 0.070455, 0.040918, -0.017008, 0.031049, -0.010847, -0.041375, 0.059624, -0.037186, -0.015125, 0.03265, 0.11463, -0.020689, 0.058846, -0.086132, 0.109765, 0.038341, 0.074075, 0.031486, -0.030692, -0.020264, -0.093453, 0.030645, -0.08451, -0.111201, -0.031115, -0.076444, 318e-5, 1952e-6, -0.02752, -0.11334, 0.044092, 1005e-6, 0.073434, -0.082935, 0.044757, 0.030054, -0.025717, -0.081733, 0.034689, 0.023261, -0.057735, 0.024434, -8957e-6, 0.040186, -0.026614, -6759e-6, -0.082044, 0.022979, 0.038621, -0.129556, 0.026753, 0.041397, 1654e-6, 0.037205, -0.011891, -1465e-6, -99e-5, -0.026155, 0.039496, -0.046137, -7432e-6, -0.039458, 0.021466, 0.039666, 0.04149, 0.067237, 0.015889, 928e-6, -0.051473, 4571e-6, -0.054656, -0.064496, -0.016879, 0.064129, 0.088521, -0.034872, -0.010411, -6583e-6, 0.064146, -0.029104, 0.015446, 9899e-6, -0.030396, -0.020139, 0.080347, 0.015771, -0, -0.073344, -4747e-6, -0.049687, 0.017255, -3607e-6, -0.029109, 0.037577, 0.063634, -0.052339, 8628e-6, 0.025821, -0.011665, -0.06861, 0.046917, 0.015224, 3369e-6, 0.018254, -4173e-6, -0.026802, -0.04863, -0.010136, 0.065597, 3896e-6, 0.037951, 0.018301, 592e-6, 0.039073, 0.0473, 0.117625, 0.036979, -0.052532, 0.046389, -0.058179, -0.017938, 0.024611, 0.067018, 0.068666, -0.018001, -0.027935, 0.039049, 0.061025, -0.026152, -0.029787, -0.030583, 0.072493, 0.033637, -0.10382, -0.027076, 0.058482, 0.012085, -0.025303, -0.021042, -0.052113, 0.075843, 3589e-6, 0.047474, 5525e-6, 3801e-6, 0.10101, -0.05594, 0.057585, -0.06871, 0.072151, 0.013319] },
5141
5320
  { name: "insights", category: "temporal", tier: 2, descriptionHash: "855ab4926f7a6801", embedding: [-0.063295, -8142e-6, -0.038172, 0.03532, 0.040686, -0.016714, -0.056257, -3287e-6, 0.015134, -0.013824, 3625e-6, 0.044585, -7921e-6, 0.031275, -0.031442, 0.044995, -0.051089, -0.029658, -4379e-6, -0.087946, 5864e-6, 0.029223, 0.050495, -7364e-6, -0.010813, 0.04681, -0.086689, -0.042294, -0.017436, -0.029906, 0.015441, 0.105912, 0.05493, 6903e-6, 0.039625, 0.112582, -0.013149, 0.016343, 0.038377, -0.038804, -0.0403, -0.05024, -0.017444, 0.014813, 0.011559, -0.086677, -0.09845, -0.070249, -0.098581, 0.075896, -0.097783, -0.061588, -0.042206, 0.029136, 8246e-6, 0.081454, -0.020084, 0.040595, -0.056448, -0.059379, 0.112695, -0.025232, -0.014015, -9531e-6, -0.012755, 0.080807, 0.019995, 0.031223, 0.061335, -0.051002, 0.010578, -0.018452, -0.06323, -0.018173, 0.029556, 0.022824, -6672e-6, -0.05807, -1342e-6, -0.169312, -0.022267, -0.035658, -0.022863, 0.026652, 0.041582, -0.056788, 0.015566, -0.053985, 0.010757, 0.019046, 0.051278, -0.058026, 0.074028, -0.017678, 0.04572, 945e-6, -83e-4, -0.04841, 0.024786, 0.069194, -8031e-6, 0.079203, -0.020793, 9091e-6, 0.067237, -3414e-6, 6468e-6, 0.011636, -0.013383, 0.027493, -0.018058, 5521e-6, 0.042896, -0.047974, 0.077419, -0.021558, -0.070058, 0.071013, 0.017298, 0.117801, 0.11145, 7351e-6, -1886e-6, -0.043286, -0.037469, 1474e-6, -0.024378, 0, 0.017595, -0.040932, -0.066118, 0.042636, -0.014735, -0.049733, 4119e-6, -0.031842, -0.068389, -0.018239, 0.017547, 0.071217, -0.052611, 0.029461, 0.019291, -6557e-6, -0.046121, 0.124387, 0.057962, -0.016263, 0.031911, 2563e-6, 0.017743, -0.06372, 0.131525, -0.017698, 0.029113, -6087e-6, -0.081771, -8083e-6, 3806e-6, 5042e-6, 11e-4, 8354e-6, 0.036325, 6888e-6, 0.035691, -0.060973, 0.050427, -0.058276, -0.016176, 0.01707, -0.013841, -0.07685, 0.013712, -134e-6, 0.040153, 7312e-6, 0.038825, 0.014188, -0.033648, 0.034613, -0.021067, -0.041681, -0.040003, -0.026887, 0.021195, -0.016114, -8157e-6, -0.019636, 0.111264, 0.02374, -0.047121, -0.032056, -0.06558, 0.078405, -0.036886, 9887e-6, 0.068641, 0.05437, -786e-5, 0.027193, -732e-5, -9859e-6, -0.017397, -0.086631, -0.01224, -0.015872, 0.016682, -0.031038, -0.033485, -0.075074, -0.075209, 0.040362, -3e-5, 0.015816, 0.048215, -0.056939, -0.033508, -5876e-6, -0.096742, -7803e-6, -124e-5, 5309e-6, 0.014088, -0, 0.019582, -0.037564, -0.060406, 0.081961, 0.054123, 0.024889, -0.090945, 0.035492, 0.015563, 0.062908, -2693e-6, 882e-5, -0.036524, -0.045377, 0.028222, -9982e-6, -7162e-6, -0.095401, -0.018318, 0.108199, 0.046605, -0.031605, -0.120001, 0.049391, 0.051344, 0.052646, 9646e-6, -0.027193, 0.019156, -0.027546, -0.016975, -0.058494, -0.033116, 7577e-6, -0.027853, -0.018491, 0.100959, -0.180773, -0.093329, 0.022668, 0.093884, 0.038685, -0.037316, -2991e-6, -0.031772, 0.05988, -0.0272, 0.086657, -0.087114, -0.092333, 0.105338, 2276e-6, -0.013072, -0.056543, -0.01029, 0.060305, 0.022462, -0.033421, -0.066583, 0.045748, 0.024946, 0.059303, -0.067325, -0.015552, 0.020745, -0.023447, 2772e-6, -351e-6, -0.151103, 0.025064, 0.079183, -484e-5, -0.027406, -0.090547, 0.038329, -0.026243, -0.081134, -0.067797, -0.014319, -0.086898, -0.045973, -2054e-6, 0.049931, 0.059267, 1532e-6, 0.085472, -0.033852, 0.050924, -2367e-6, 0.028192, -0.045562, -0.08446, -0.062257, 0.012305, -0.026982, -0, -0.027423, 0.090977, 2768e-6, 0.011862, 0.075439, -0.037147, -0.01372, 0.094814, 0.054414, 0.019731, 0.09544, -0.043872, -0.073898, -0.035133, 0.031111, -0.023116, -0.019305, 0.033497, -0.040037, -0.016253, 0.051564, 0.077346, 4027e-6, -0.103212, -0.016498, -26e-5, 7975e-6, 0.128707, 0.038103, -6535e-6, 0.019882, 0.031399, 0.058017, -0.075234, 0.03305, 0.033512, 0.06787, -0.037298, -7957e-6, 0.068908, -0.025023, 0.066633, -0.050597, 0.074426, -716e-5, -0.01675, -0.06884, -0.03286, 0.027107, -0.031027, -0.014358, -0.03356, -0.024072, 0.067223, 0.065775, 0.068417, 0.079966, -0.010847, 171e-6, 0.026273, 0.169434, -0.050325, 0.011726, 0.013154] },
5142
5321
  { name: "link", category: "wikilinks", tier: 2, descriptionHash: "f5991633e71ac0e6", embedding: [-0.105211, -0.051175, -0.014955, 0.070203, 0.094131, 0.013247, 2462e-6, 0.061895, 3523e-6, 0.038099, 262e-6, 9244e-6, 0.018201, 0.036586, -0.026886, 0.121965, -0.023067, 0.038931, 0.040324, -0.045367, 0.055688, 0.048809, 0.067382, -0.012725, 0.025349, -0.139325, -0.134768, 0.034046, -0.023531, -0.077858, 0.014222, 0.076492, -0.089917, -0.048617, -0.011276, 0.050469, -0.028663, -0.026588, 0.040878, -0.01898, 0.025442, 5891e-6, -0.039509, 0.035192, -0.039439, 0.049857, -0.018329, -0.065998, -0.113633, 0.117079, -0.137705, -0.029588, 0.032657, -0.011592, 0.027898, 0.018984, -0.129855, -5585e-6, 0.01063, -0.074039, 0.067858, -0.032616, -0.077555, -0.041351, 2928e-6, 0.02392, -0.013358, 0.078737, -0.034541, -0.025256, 7842e-6, -0.054307, -247e-5, 0.017511, 0.030964, -8747e-6, -0.047385, 0.016456, -0.057913, -0.093447, -4794e-6, 0.011713, 0.049448, -1893e-6, 0.055055, 0.060197, 8172e-6, -0.017526, -0.014227, 0.043367, 0.03618, -0.086497, 0.112268, -0.031951, -0.022605, 0.03589, -0.011521, -0.04353, -3027e-6, 0.072896, 0.022479, 0.038038, 0.049187, -0.029073, -0.031375, -0.032972, 0.051462, 0.115384, 7451e-6, 0.021359, -0.059937, -9478e-6, -0.085658, -0.084651, -0.014569, -0.040287, -4465e-6, -1215e-6, 0.089086, -8498e-6, 0.065111, 0.031575, 0.042459, 0.013246, -0.063517, -0.013246, -0.031999, 0, 0.115188, 0.101182, -0.034179, -0.015912, 0.017986, -4269e-6, -0.078143, -0.049314, -0.097431, -0.026028, -0.052334, 0.080905, -0.011248, 0.012377, -0.024596, 0.022708, 3039e-6, 0.083423, -0.046848, -0.062428, 0.011718, 0.084491, -0.01987, 156e-6, 0.0555, 3028e-6, -134e-5, -0.013151, -0.040286, 0.017924, 0.0278, 114e-6, 0.016917, 0.049588, 0.070486, 0.019654, -0.057675, -0.066234, -0.018768, -0.065281, 0.011376, -4547e-6, -0.052151, -0.011786, -0.017052, 0.029821, 0.026028, -0.027522, 0.028279, -0.015119, 7861e-6, 0.014754, 0.020151, 0.012127, 0.019077, -4529e-6, -0.098239, 0.052583, 0.02076, 0.010897, 0.045988, -3608e-6, -0.022366, -0.074248, -0.066018, 0.055597, -0.059601, 0.034221, 0.044492, -0.038879, -719e-5, 0.015953, 0.032836, 0.023192, -0.038382, -0.055607, -0.115347, -0.136553, -0.028439, 9282e-6, -0.080226, -0.169079, -0.055861, 0.036114, 0.067252, -0.023551, 0.035797, -0.058662, -0.024751, -0.024102, 0.010495, 0.020854, -0.019832, 0.056418, -5782e-6, -0, 0.075746, -2897e-6, 0.030092, 0.034463, -9709e-6, 0.025326, 2244e-6, 0.013144, 0.078235, -355e-6, 0.06344, -0.06993, -0.063164, 0.017734, 0.012112, -7685e-6, 2749e-6, -0.044044, 4284e-6, 0.085672, 0.043681, 0.015488, -0.017667, 0.06259, 0.016398, 0.01253, 0.126432, -0.022014, 0.039742, -9333e-6, -0.02521, 0.01218, -0.063496, -0.01253, 0.017962, 0.029351, -0.019498, -4882e-6, -0.02802, -7356e-6, 0.149432, -0.018531, -0.035931, 1085e-6, -0.019631, -924e-5, -0.079662, 0.01923, -0.070051, -0.064508, 0.048826, 0.010655, -0.017871, -0.081734, -0.034362, 0.059971, 0.017234, 0.025876, -0.086982, -101e-5, -6568e-6, 0.044154, -0.058022, 0.061645, 0.070019, -0.094105, -0.021322, 0.011796, -0.040228, -0.015751, 0.025438, -774e-5, 8335e-6, -0.099734, 0.071584, -0.053004, 0.026579, -0.034326, 0.037723, -0.074485, -0.024437, 0.031958, 0.077181, 6378e-6, 0.036474, -1893e-6, -0.037769, 0.083712, -0.023617, -3828e-6, 0.040877, -0.087152, 0.03894, 0.137603, -0.084336, -0, 5716e-6, 0.083963, -698e-5, 0.021144, 0.016048, 0.026998, -3916e-6, 0.050464, -0.034483, 0.031494, 0.030571, 0.021726, -0.12123, -0.045023, 0.085973, -0.071658, -0.031606, 0.061912, -0.02822, -0.031827, -0.047078, -9682e-6, 0.01124, 0.025411, 9235e-6, 4972e-6, -0.035519, 0.042622, 0.015422, -0.026236, -8137e-6, 0.013488, -0.066525, -0.049611, -729e-5, 0.068035, -7959e-6, -0.05708, 476e-5, -0.0244, 0.066389, 0.024302, -0.026597, 0.062248, 0.036823, 0.040825, 0.02206, -0.097542, 0.049637, -0.097868, 0.015866, -0.040273, 0.046721, 0.014174, -0.013605, 0.095691, 0.04449, 0.016153, -0.036602, -0.0348, 0.150135, -0.026655, 5699e-6, 0.041633] },
@@ -5157,17 +5336,17 @@ var init_tool_embeddings_generated = __esm({
5157
5336
  });
5158
5337
 
5159
5338
  // src/core/write/path-security.ts
5160
- import fs16 from "fs/promises";
5161
- import path20 from "path";
5339
+ import fs17 from "fs/promises";
5340
+ import path21 from "path";
5162
5341
  function isSensitivePath(filePath) {
5163
5342
  const normalizedPath = filePath.replace(/\\/g, "/");
5164
5343
  return SENSITIVE_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath));
5165
5344
  }
5166
5345
  function isWithinDirectory(child, parent, allowEqual = false) {
5167
- const rel = path20.relative(path20.resolve(parent), path20.resolve(child));
5346
+ const rel = path21.relative(path21.resolve(parent), path21.resolve(child));
5168
5347
  if (rel === "") return allowEqual;
5169
- const firstSeg = rel.split(path20.sep)[0];
5170
- return firstSeg !== ".." && !path20.isAbsolute(rel);
5348
+ const firstSeg = rel.split(path21.sep)[0];
5349
+ return firstSeg !== ".." && !path21.isAbsolute(rel);
5171
5350
  }
5172
5351
  function validatePath(vaultPath2, notePath) {
5173
5352
  if (notePath.startsWith("/")) {
@@ -5179,11 +5358,11 @@ function validatePath(vaultPath2, notePath) {
5179
5358
  if (notePath.startsWith("\\")) {
5180
5359
  return false;
5181
5360
  }
5182
- return isWithinDirectory(path20.resolve(vaultPath2, notePath), vaultPath2);
5361
+ return isWithinDirectory(path21.resolve(vaultPath2, notePath), vaultPath2);
5183
5362
  }
5184
5363
  function sanitizeNotePath(notePath) {
5185
- const dir = path20.dirname(notePath);
5186
- let filename = path20.basename(notePath);
5364
+ const dir = path21.dirname(notePath);
5365
+ let filename = path21.basename(notePath);
5187
5366
  const ext = filename.endsWith(".md") ? ".md" : "";
5188
5367
  let stem2 = ext ? filename.slice(0, -ext.length) : filename;
5189
5368
  stem2 = stem2.replace(/\s+/g, "-");
@@ -5192,7 +5371,7 @@ function sanitizeNotePath(notePath) {
5192
5371
  stem2 = stem2.replace(/-{2,}/g, "-");
5193
5372
  stem2 = stem2.replace(/^-+|-+$/g, "");
5194
5373
  filename = stem2 + (ext || ".md");
5195
- return dir === "." ? filename : path20.join(dir, filename).replace(/\\/g, "/");
5374
+ return dir === "." ? filename : path21.join(dir, filename).replace(/\\/g, "/");
5196
5375
  }
5197
5376
  async function validatePathSecure(vaultPath2, notePath) {
5198
5377
  if (notePath.startsWith("/")) {
@@ -5213,14 +5392,14 @@ async function validatePathSecure(vaultPath2, notePath) {
5213
5392
  reason: "Absolute paths not allowed"
5214
5393
  };
5215
5394
  }
5216
- const firstSeg = path20.normalize(notePath).split(path20.sep).filter(Boolean)[0];
5395
+ const firstSeg = path21.normalize(notePath).split(path21.sep).filter(Boolean)[0];
5217
5396
  if (firstSeg === "..") {
5218
5397
  return {
5219
5398
  valid: false,
5220
5399
  reason: "Path traversal not allowed"
5221
5400
  };
5222
5401
  }
5223
- if (!isWithinDirectory(path20.resolve(vaultPath2, notePath), vaultPath2)) {
5402
+ if (!isWithinDirectory(path21.resolve(vaultPath2, notePath), vaultPath2)) {
5224
5403
  return {
5225
5404
  valid: false,
5226
5405
  reason: "Path traversal not allowed"
@@ -5233,18 +5412,18 @@ async function validatePathSecure(vaultPath2, notePath) {
5233
5412
  };
5234
5413
  }
5235
5414
  try {
5236
- const fullPath = path20.join(vaultPath2, notePath);
5415
+ const fullPath = path21.join(vaultPath2, notePath);
5237
5416
  try {
5238
- await fs16.access(fullPath);
5239
- const realPath = await fs16.realpath(fullPath);
5240
- const realVaultPath = await fs16.realpath(vaultPath2);
5417
+ await fs17.access(fullPath);
5418
+ const realPath = await fs17.realpath(fullPath);
5419
+ const realVaultPath = await fs17.realpath(vaultPath2);
5241
5420
  if (!isWithinDirectory(realPath, realVaultPath)) {
5242
5421
  return {
5243
5422
  valid: false,
5244
5423
  reason: "Symlink target is outside vault"
5245
5424
  };
5246
5425
  }
5247
- const relativePath = path20.relative(realVaultPath, realPath);
5426
+ const relativePath = path21.relative(realVaultPath, realPath);
5248
5427
  if (isSensitivePath(relativePath)) {
5249
5428
  return {
5250
5429
  valid: false,
@@ -5252,11 +5431,11 @@ async function validatePathSecure(vaultPath2, notePath) {
5252
5431
  };
5253
5432
  }
5254
5433
  } catch {
5255
- const parentDir = path20.dirname(fullPath);
5434
+ const parentDir = path21.dirname(fullPath);
5256
5435
  try {
5257
- await fs16.access(parentDir);
5258
- const realParentPath = await fs16.realpath(parentDir);
5259
- const realVaultPath = await fs16.realpath(vaultPath2);
5436
+ await fs17.access(parentDir);
5437
+ const realParentPath = await fs17.realpath(parentDir);
5438
+ const realVaultPath = await fs17.realpath(vaultPath2);
5260
5439
  if (!isWithinDirectory(realParentPath, realVaultPath, true)) {
5261
5440
  return {
5262
5441
  valid: false,
@@ -6053,8 +6232,8 @@ var init_content_mutation = __esm({
6053
6232
  });
6054
6233
 
6055
6234
  // src/core/write/file-io.ts
6056
- import fs17 from "fs/promises";
6057
- import path21 from "path";
6235
+ import fs18 from "fs/promises";
6236
+ import path22 from "path";
6058
6237
  import matter2 from "gray-matter";
6059
6238
  import { createHash as createHash2 } from "node:crypto";
6060
6239
  function computeContentHash(rawContent) {
@@ -6065,10 +6244,10 @@ async function readVaultFile(vaultPath2, notePath) {
6065
6244
  if (!validation.valid) {
6066
6245
  throw new Error(`Invalid path: ${validation.reason}`);
6067
6246
  }
6068
- const fullPath = path21.join(vaultPath2, notePath);
6247
+ const fullPath = path22.join(vaultPath2, notePath);
6069
6248
  const [rawContent, stat4] = await Promise.all([
6070
- fs17.readFile(fullPath, "utf-8"),
6071
- fs17.stat(fullPath)
6249
+ fs18.readFile(fullPath, "utf-8"),
6250
+ fs18.stat(fullPath)
6072
6251
  ]);
6073
6252
  const contentHash2 = computeContentHash(rawContent);
6074
6253
  const lineEnding = detectLineEnding(rawContent);
@@ -6120,9 +6299,9 @@ async function writeVaultFile(vaultPath2, notePath, content, frontmatter, lineEn
6120
6299
  if (!validation.valid) {
6121
6300
  throw new Error(`Invalid path: ${validation.reason}`);
6122
6301
  }
6123
- const fullPath = path21.join(vaultPath2, notePath);
6302
+ const fullPath = path22.join(vaultPath2, notePath);
6124
6303
  if (expectedHash) {
6125
- const currentRaw = await fs17.readFile(fullPath, "utf-8");
6304
+ const currentRaw = await fs18.readFile(fullPath, "utf-8");
6126
6305
  const currentHash = computeContentHash(currentRaw);
6127
6306
  if (currentHash !== expectedHash) {
6128
6307
  throw new WriteConflictError(notePath);
@@ -6131,7 +6310,7 @@ async function writeVaultFile(vaultPath2, notePath, content, frontmatter, lineEn
6131
6310
  let output = matter2.stringify(content, frontmatter);
6132
6311
  output = normalizeTrailingNewline(output);
6133
6312
  output = convertLineEndings(output, lineEnding);
6134
- await fs17.writeFile(fullPath, output, "utf-8");
6313
+ await fs18.writeFile(fullPath, output, "utf-8");
6135
6314
  }
6136
6315
  var WriteConflictError;
6137
6316
  var init_file_io = __esm({
@@ -6188,8 +6367,8 @@ function createContext(variables = {}) {
6188
6367
  steps: {}
6189
6368
  };
6190
6369
  }
6191
- function resolvePath(obj, path39) {
6192
- const parts = path39.split(".");
6370
+ function resolvePath(obj, path40) {
6371
+ const parts = path40.split(".");
6193
6372
  let current = obj;
6194
6373
  for (const part of parts) {
6195
6374
  if (current === void 0 || current === null) {
@@ -6646,8 +6825,8 @@ __export(conditions_exports, {
6646
6825
  evaluateCondition: () => evaluateCondition,
6647
6826
  shouldStepExecute: () => shouldStepExecute
6648
6827
  });
6649
- import fs25 from "fs/promises";
6650
- import path29 from "path";
6828
+ import fs26 from "fs/promises";
6829
+ import path30 from "path";
6651
6830
  async function evaluateCondition(condition, vaultPath2, context) {
6652
6831
  const interpolatedPath = condition.path ? interpolate(condition.path, context) : void 0;
6653
6832
  const interpolatedSection = condition.section ? interpolate(condition.section, context) : void 0;
@@ -6700,9 +6879,9 @@ async function evaluateCondition(condition, vaultPath2, context) {
6700
6879
  }
6701
6880
  }
6702
6881
  async function evaluateFileExists(vaultPath2, notePath, expectExists) {
6703
- const fullPath = path29.join(vaultPath2, notePath);
6882
+ const fullPath = path30.join(vaultPath2, notePath);
6704
6883
  try {
6705
- await fs25.access(fullPath);
6884
+ await fs26.access(fullPath);
6706
6885
  return {
6707
6886
  met: expectExists,
6708
6887
  reason: expectExists ? `File exists: ${notePath}` : `File exists (expected not to): ${notePath}`
@@ -6715,9 +6894,9 @@ async function evaluateFileExists(vaultPath2, notePath, expectExists) {
6715
6894
  }
6716
6895
  }
6717
6896
  async function evaluateSectionExists(vaultPath2, notePath, sectionName, expectExists) {
6718
- const fullPath = path29.join(vaultPath2, notePath);
6897
+ const fullPath = path30.join(vaultPath2, notePath);
6719
6898
  try {
6720
- await fs25.access(fullPath);
6899
+ await fs26.access(fullPath);
6721
6900
  } catch {
6722
6901
  return {
6723
6902
  met: !expectExists,
@@ -6746,9 +6925,9 @@ async function evaluateSectionExists(vaultPath2, notePath, sectionName, expectEx
6746
6925
  }
6747
6926
  }
6748
6927
  async function evaluateFrontmatterExists(vaultPath2, notePath, fieldName, expectExists) {
6749
- const fullPath = path29.join(vaultPath2, notePath);
6928
+ const fullPath = path30.join(vaultPath2, notePath);
6750
6929
  try {
6751
- await fs25.access(fullPath);
6930
+ await fs26.access(fullPath);
6752
6931
  } catch {
6753
6932
  return {
6754
6933
  met: !expectExists,
@@ -6777,9 +6956,9 @@ async function evaluateFrontmatterExists(vaultPath2, notePath, fieldName, expect
6777
6956
  }
6778
6957
  }
6779
6958
  async function evaluateFrontmatterEquals(vaultPath2, notePath, fieldName, expectedValue) {
6780
- const fullPath = path29.join(vaultPath2, notePath);
6959
+ const fullPath = path30.join(vaultPath2, notePath);
6781
6960
  try {
6782
- await fs25.access(fullPath);
6961
+ await fs26.access(fullPath);
6783
6962
  } catch {
6784
6963
  return {
6785
6964
  met: false,
@@ -6921,10 +7100,10 @@ var init_taskHelpers = __esm({
6921
7100
  });
6922
7101
 
6923
7102
  // src/index.ts
6924
- import * as path38 from "path";
7103
+ import * as path39 from "path";
6925
7104
  import { readFileSync as readFileSync6, realpathSync, existsSync as existsSync4 } from "fs";
6926
7105
  import { fileURLToPath as fileURLToPath4 } from "url";
6927
- import { dirname as dirname8, join as join19 } from "path";
7106
+ import { dirname as dirname8, join as join20 } from "path";
6928
7107
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6929
7108
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6930
7109
  import { performance } from "node:perf_hooks";
@@ -7216,8 +7395,8 @@ function updateIndexProgress(parsed, total) {
7216
7395
  function normalizeTarget(target) {
7217
7396
  return target.toLowerCase().replace(/\.md$/, "");
7218
7397
  }
7219
- function normalizeNotePath(path39) {
7220
- return path39.toLowerCase().replace(/\.md$/, "");
7398
+ function normalizeNotePath(path40) {
7399
+ return path40.toLowerCase().replace(/\.md$/, "");
7221
7400
  }
7222
7401
  async function buildVaultIndex(vaultPath2, options = {}) {
7223
7402
  const { timeoutMs = DEFAULT_TIMEOUT_MS, onProgress } = options;
@@ -7375,7 +7554,7 @@ function findSimilarEntity(index, target) {
7375
7554
  }
7376
7555
  const maxDist = normalizedLen <= 10 ? 1 : 2;
7377
7556
  let bestMatch;
7378
- for (const [entity, path39] of index.entities) {
7557
+ for (const [entity, path40] of index.entities) {
7379
7558
  const lenDiff = Math.abs(entity.length - normalizedLen);
7380
7559
  if (lenDiff > maxDist) {
7381
7560
  continue;
@@ -7383,7 +7562,7 @@ function findSimilarEntity(index, target) {
7383
7562
  const dist = levenshteinDistance(normalized, entity);
7384
7563
  if (dist > 0 && dist <= maxDist) {
7385
7564
  if (!bestMatch || dist < bestMatch.distance) {
7386
- bestMatch = { path: path39, entity, distance: dist };
7565
+ bestMatch = { path: path40, entity, distance: dist };
7387
7566
  if (dist === 1) {
7388
7567
  return bestMatch;
7389
7568
  }
@@ -7498,8 +7677,8 @@ function saveVaultIndexToCache(stateDb2, index) {
7498
7677
  init_vault();
7499
7678
 
7500
7679
  // src/core/read/config.ts
7501
- import * as fs5 from "fs";
7502
- import * as path4 from "path";
7680
+ import * as fs6 from "fs";
7681
+ import * as path5 from "path";
7503
7682
  import {
7504
7683
  loadFlywheelConfigFromDb,
7505
7684
  saveFlywheelConfigToDb
@@ -7569,7 +7748,7 @@ var FOLDER_PATTERNS = {
7569
7748
  function extractFolders(index) {
7570
7749
  const folders = /* @__PURE__ */ new Set();
7571
7750
  for (const notePath of index.notes.keys()) {
7572
- const dir = path4.dirname(notePath);
7751
+ const dir = path5.dirname(notePath);
7573
7752
  if (dir && dir !== ".") {
7574
7753
  const parts = dir.split(/[/\\]/);
7575
7754
  for (let i = 1; i <= parts.length; i++) {
@@ -7586,7 +7765,7 @@ function extractFolders(index) {
7586
7765
  function findMatchingFolder(folders, patterns) {
7587
7766
  const lowerPatterns = patterns.map((p) => p.toLowerCase());
7588
7767
  for (const folder of folders) {
7589
- const folderName = path4.basename(folder).toLowerCase();
7768
+ const folderName = path5.basename(folder).toLowerCase();
7590
7769
  if (lowerPatterns.includes(folderName)) {
7591
7770
  return folder;
7592
7771
  }
@@ -7599,7 +7778,7 @@ function inferConfig(index, vaultPath2) {
7599
7778
  paths: {}
7600
7779
  };
7601
7780
  if (vaultPath2) {
7602
- inferred.vault_name = path4.basename(vaultPath2);
7781
+ inferred.vault_name = path5.basename(vaultPath2);
7603
7782
  }
7604
7783
  const folders = extractFolders(index);
7605
7784
  const detectedPath = findMatchingFolder(folders, FOLDER_PATTERNS.daily_notes);
@@ -7637,9 +7816,9 @@ var TEMPLATE_PATTERNS = {
7637
7816
  };
7638
7817
  function scanTemplatesFolder(vaultPath2, templatesFolder) {
7639
7818
  const templates = {};
7640
- const absFolder = path4.join(vaultPath2, templatesFolder);
7819
+ const absFolder = path5.join(vaultPath2, templatesFolder);
7641
7820
  try {
7642
- const files = fs5.readdirSync(absFolder);
7821
+ const files = fs6.readdirSync(absFolder);
7643
7822
  for (const file of files) {
7644
7823
  for (const [type, pattern] of Object.entries(TEMPLATE_PATTERNS)) {
7645
7824
  if (pattern.test(file) && !templates[type]) {
@@ -7677,19 +7856,19 @@ function saveConfig(stateDb2, inferred, existing) {
7677
7856
  }
7678
7857
 
7679
7858
  // src/core/read/vaultRoot.ts
7680
- import * as fs6 from "fs";
7681
- import * as path5 from "path";
7859
+ import * as fs7 from "fs";
7860
+ import * as path6 from "path";
7682
7861
  var VAULT_MARKERS = [".obsidian", ".flywheel", ".claude"];
7683
7862
  function findVaultRoot(startPath) {
7684
- let current = path5.resolve(startPath || process.cwd());
7863
+ let current = path6.resolve(startPath || process.cwd());
7685
7864
  while (true) {
7686
7865
  for (const marker of VAULT_MARKERS) {
7687
- const markerPath = path5.join(current, marker);
7688
- if (fs6.existsSync(markerPath) && fs6.statSync(markerPath).isDirectory()) {
7866
+ const markerPath = path6.join(current, marker);
7867
+ if (fs7.existsSync(markerPath) && fs7.statSync(markerPath).isDirectory()) {
7689
7868
  return current;
7690
7869
  }
7691
7870
  }
7692
- const parent = path5.dirname(current);
7871
+ const parent = path6.dirname(current);
7693
7872
  if (parent === current) {
7694
7873
  return startPath || process.cwd();
7695
7874
  }
@@ -7701,10 +7880,10 @@ function findVaultRoot(startPath) {
7701
7880
  import chokidar from "chokidar";
7702
7881
 
7703
7882
  // src/core/read/watch/eventQueue.ts
7704
- import * as path7 from "path";
7883
+ import * as path8 from "path";
7705
7884
 
7706
7885
  // src/core/read/watch/pathFilter.ts
7707
- import path6 from "path";
7886
+ import path7 from "path";
7708
7887
  var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
7709
7888
  ".git",
7710
7889
  ".obsidian",
@@ -7803,7 +7982,7 @@ function isIgnoredDirectory(segment) {
7803
7982
  return IGNORED_DIRECTORIES.has(segment);
7804
7983
  }
7805
7984
  function hasIgnoredExtension(filePath) {
7806
- const ext = path6.extname(filePath).toLowerCase();
7985
+ const ext = path7.extname(filePath).toLowerCase();
7807
7986
  return IGNORED_EXTENSIONS.has(ext);
7808
7987
  }
7809
7988
  function matchesIgnoredPattern(filename) {
@@ -7820,7 +7999,7 @@ function normalizePath(filePath, caseInsensitive) {
7820
7999
  function getRelativePath(vaultPath2, filePath) {
7821
8000
  const normalizedVault = normalizePath(vaultPath2);
7822
8001
  const normalizedFile = normalizePath(filePath);
7823
- const relative = path6.posix.relative(normalizedVault, normalizedFile);
8002
+ const relative = path7.posix.relative(normalizedVault, normalizedFile);
7824
8003
  return relative;
7825
8004
  }
7826
8005
  function shouldWatch(filePath, vaultPath2) {
@@ -7894,7 +8073,7 @@ function coalesceEvents(events) {
7894
8073
  var RENAME_PROXIMITY_MS = 5e3;
7895
8074
  var COMMON_STEMS = /* @__PURE__ */ new Set(["readme", "index", "todo", "changelog", "license", "notes"]);
7896
8075
  function fileStem(p) {
7897
- return path7.basename(p).replace(/\.[^.]+$/, "");
8076
+ return path8.basename(p).replace(/\.[^.]+$/, "");
7898
8077
  }
7899
8078
  function detectRenames(events) {
7900
8079
  const deletes = events.filter((e) => e.type === "delete");
@@ -7905,13 +8084,13 @@ function detectRenames(events) {
7905
8084
  const renames = [];
7906
8085
  for (const del of deletes) {
7907
8086
  const stem2 = fileStem(del.path);
7908
- const delDir = path7.dirname(del.path);
8087
+ const delDir = path8.dirname(del.path);
7909
8088
  const delTimestamp = del.originalEvents.length > 0 ? Math.max(...del.originalEvents.map((e) => e.timestamp)) : 0;
7910
8089
  const allCandidates = upserts.filter(
7911
8090
  (u) => !usedUpserts.has(u.path) && fileStem(u.path) === stem2
7912
8091
  );
7913
8092
  if (allCandidates.length === 0) continue;
7914
- const sameDirCandidates = allCandidates.filter((c) => path7.dirname(c.path) === delDir);
8093
+ const sameDirCandidates = allCandidates.filter((c) => path8.dirname(c.path) === delDir);
7915
8094
  const candidates = sameDirCandidates.length > 0 ? sameDirCandidates : COMMON_STEMS.has(stem2.toLowerCase()) ? [] : allCandidates;
7916
8095
  if (candidates.length === 0) continue;
7917
8096
  let bestCandidate = null;
@@ -7955,30 +8134,30 @@ var EventQueue = class {
7955
8134
  * Add a new event to the queue
7956
8135
  */
7957
8136
  push(type, rawPath) {
7958
- const path39 = normalizePath(rawPath);
8137
+ const path40 = normalizePath(rawPath);
7959
8138
  const now = Date.now();
7960
8139
  const event = {
7961
8140
  type,
7962
- path: path39,
8141
+ path: path40,
7963
8142
  timestamp: now
7964
8143
  };
7965
- let pending = this.pending.get(path39);
8144
+ let pending = this.pending.get(path40);
7966
8145
  if (!pending) {
7967
8146
  pending = {
7968
8147
  events: [],
7969
8148
  timer: null,
7970
8149
  lastEvent: now
7971
8150
  };
7972
- this.pending.set(path39, pending);
8151
+ this.pending.set(path40, pending);
7973
8152
  }
7974
8153
  pending.events.push(event);
7975
8154
  pending.lastEvent = now;
7976
- console.error(`[flywheel] QUEUE: pushed ${type} for ${path39}, pending=${this.pending.size}`);
8155
+ console.error(`[flywheel] QUEUE: pushed ${type} for ${path40}, pending=${this.pending.size}`);
7977
8156
  if (pending.timer) {
7978
8157
  clearTimeout(pending.timer);
7979
8158
  }
7980
8159
  pending.timer = setTimeout(() => {
7981
- this.flushPath(path39);
8160
+ this.flushPath(path40);
7982
8161
  }, this.config.debounceMs);
7983
8162
  if (this.pending.size >= this.config.batchSize) {
7984
8163
  this.flush();
@@ -7999,10 +8178,10 @@ var EventQueue = class {
7999
8178
  /**
8000
8179
  * Flush a single path's events
8001
8180
  */
8002
- flushPath(path39) {
8003
- const pending = this.pending.get(path39);
8181
+ flushPath(path40) {
8182
+ const pending = this.pending.get(path40);
8004
8183
  if (!pending || pending.events.length === 0) return;
8005
- console.error(`[flywheel] QUEUE: flushing ${path39}, events=${pending.events.length}`);
8184
+ console.error(`[flywheel] QUEUE: flushing ${path40}, events=${pending.events.length}`);
8006
8185
  if (pending.timer) {
8007
8186
  clearTimeout(pending.timer);
8008
8187
  pending.timer = null;
@@ -8011,7 +8190,7 @@ var EventQueue = class {
8011
8190
  if (coalescedType) {
8012
8191
  const coalesced = {
8013
8192
  type: coalescedType,
8014
- path: path39,
8193
+ path: path40,
8015
8194
  originalEvents: [...pending.events]
8016
8195
  };
8017
8196
  this.onBatch({
@@ -8020,7 +8199,7 @@ var EventQueue = class {
8020
8199
  timestamp: Date.now()
8021
8200
  });
8022
8201
  }
8023
- this.pending.delete(path39);
8202
+ this.pending.delete(path40);
8024
8203
  }
8025
8204
  /**
8026
8205
  * Flush all pending events
@@ -8032,7 +8211,7 @@ var EventQueue = class {
8032
8211
  }
8033
8212
  if (this.pending.size === 0) return;
8034
8213
  const events = [];
8035
- for (const [path39, pending] of this.pending) {
8214
+ for (const [path40, pending] of this.pending) {
8036
8215
  if (pending.timer) {
8037
8216
  clearTimeout(pending.timer);
8038
8217
  }
@@ -8040,7 +8219,7 @@ var EventQueue = class {
8040
8219
  if (coalescedType) {
8041
8220
  events.push({
8042
8221
  type: coalescedType,
8043
- path: path39,
8222
+ path: path40,
8044
8223
  originalEvents: [...pending.events]
8045
8224
  });
8046
8225
  }
@@ -8118,7 +8297,7 @@ function parseWatcherConfig() {
8118
8297
  }
8119
8298
 
8120
8299
  // src/core/read/watch/incrementalIndex.ts
8121
- import path8 from "path";
8300
+ import path9 from "path";
8122
8301
  function normalizeTarget2(target) {
8123
8302
  return target.toLowerCase().replace(/\.md$/, "");
8124
8303
  }
@@ -8255,9 +8434,9 @@ async function upsertNote(index, vaultPath2, notePath) {
8255
8434
  if (existed) {
8256
8435
  releasedKeys = removeNoteFromIndex(index, notePath);
8257
8436
  }
8258
- const fullPath = path8.join(vaultPath2, notePath);
8259
- const fs34 = await import("fs/promises");
8260
- const stats = await fs34.stat(fullPath);
8437
+ const fullPath = path9.join(vaultPath2, notePath);
8438
+ const fs35 = await import("fs/promises");
8439
+ const stats = await fs35.stat(fullPath);
8261
8440
  const vaultFile = {
8262
8441
  path: notePath,
8263
8442
  absolutePath: fullPath,
@@ -8454,31 +8633,31 @@ function createVaultWatcher(options) {
8454
8633
  usePolling: config2.usePolling,
8455
8634
  interval: config2.usePolling ? config2.pollInterval : void 0
8456
8635
  });
8457
- watcher.on("add", (path39) => {
8458
- console.error(`[flywheel] RAW EVENT: add ${path39}`);
8459
- if (shouldWatch(path39, vaultPath2)) {
8460
- console.error(`[flywheel] ACCEPTED: add ${path39}`);
8461
- eventQueue.push("add", path39);
8636
+ watcher.on("add", (path40) => {
8637
+ console.error(`[flywheel] RAW EVENT: add ${path40}`);
8638
+ if (shouldWatch(path40, vaultPath2)) {
8639
+ console.error(`[flywheel] ACCEPTED: add ${path40}`);
8640
+ eventQueue.push("add", path40);
8462
8641
  } else {
8463
- console.error(`[flywheel] FILTERED: add ${path39}`);
8642
+ console.error(`[flywheel] FILTERED: add ${path40}`);
8464
8643
  }
8465
8644
  });
8466
- watcher.on("change", (path39) => {
8467
- console.error(`[flywheel] RAW EVENT: change ${path39}`);
8468
- if (shouldWatch(path39, vaultPath2)) {
8469
- console.error(`[flywheel] ACCEPTED: change ${path39}`);
8470
- eventQueue.push("change", path39);
8645
+ watcher.on("change", (path40) => {
8646
+ console.error(`[flywheel] RAW EVENT: change ${path40}`);
8647
+ if (shouldWatch(path40, vaultPath2)) {
8648
+ console.error(`[flywheel] ACCEPTED: change ${path40}`);
8649
+ eventQueue.push("change", path40);
8471
8650
  } else {
8472
- console.error(`[flywheel] FILTERED: change ${path39}`);
8651
+ console.error(`[flywheel] FILTERED: change ${path40}`);
8473
8652
  }
8474
8653
  });
8475
- watcher.on("unlink", (path39) => {
8476
- console.error(`[flywheel] RAW EVENT: unlink ${path39}`);
8477
- if (shouldWatch(path39, vaultPath2)) {
8478
- console.error(`[flywheel] ACCEPTED: unlink ${path39}`);
8479
- eventQueue.push("unlink", path39);
8654
+ watcher.on("unlink", (path40) => {
8655
+ console.error(`[flywheel] RAW EVENT: unlink ${path40}`);
8656
+ if (shouldWatch(path40, vaultPath2)) {
8657
+ console.error(`[flywheel] ACCEPTED: unlink ${path40}`);
8658
+ eventQueue.push("unlink", path40);
8480
8659
  } else {
8481
- console.error(`[flywheel] FILTERED: unlink ${path39}`);
8660
+ console.error(`[flywheel] FILTERED: unlink ${path40}`);
8482
8661
  }
8483
8662
  });
8484
8663
  watcher.on("ready", () => {
@@ -8510,8 +8689,8 @@ function createVaultWatcher(options) {
8510
8689
  }
8511
8690
 
8512
8691
  // src/core/read/watch/pipeline.ts
8513
- import * as path16 from "node:path";
8514
- import * as fs11 from "node:fs/promises";
8692
+ import * as path17 from "node:path";
8693
+ import * as fs12 from "node:fs/promises";
8515
8694
  import {
8516
8695
  getAllEntitiesFromDb,
8517
8696
  findEntityMatches,
@@ -8971,7 +9150,7 @@ init_vault();
8971
9150
  init_serverLog();
8972
9151
  init_constants();
8973
9152
  init_vault_scope();
8974
- import * as fs9 from "fs";
9153
+ import * as fs10 from "fs";
8975
9154
  var MAX_INDEX_FILE_SIZE = 5 * 1024 * 1024;
8976
9155
  var STALE_THRESHOLD_MS = 60 * 60 * 1e3;
8977
9156
  function splitFrontmatter(raw) {
@@ -9030,11 +9209,11 @@ async function buildFTS5Index(vaultPath2) {
9030
9209
  const rows = [];
9031
9210
  for (const file of indexableFiles) {
9032
9211
  try {
9033
- const stats = fs9.statSync(file.absolutePath);
9212
+ const stats = fs10.statSync(file.absolutePath);
9034
9213
  if (stats.size > MAX_INDEX_FILE_SIZE) {
9035
9214
  continue;
9036
9215
  }
9037
- const raw = fs9.readFileSync(file.absolutePath, "utf-8");
9216
+ const raw = fs10.readFileSync(file.absolutePath, "utf-8");
9038
9217
  const { frontmatter, body } = splitFrontmatter(raw);
9039
9218
  const title = file.path.replace(/\.md$/, "").split("/").pop() || file.path;
9040
9219
  rows.push([file.path, title, frontmatter, body]);
@@ -9114,9 +9293,9 @@ function updateFTS5Incremental(vaultPath2, changed, deleted) {
9114
9293
  if (!shouldIndexFile2(p)) continue;
9115
9294
  const absPath = `${vaultPath2}/${p}`.replace(/\\/g, "/");
9116
9295
  try {
9117
- const stats = fs9.statSync(absPath);
9296
+ const stats = fs10.statSync(absPath);
9118
9297
  if (stats.size > MAX_INDEX_FILE_SIZE) continue;
9119
- const raw = fs9.readFileSync(absPath, "utf-8");
9298
+ const raw = fs10.readFileSync(absPath, "utf-8");
9120
9299
  const { frontmatter, body } = splitFrontmatter(raw);
9121
9300
  const title = p.replace(/\.md$/, "").split("/").pop() || p;
9122
9301
  del.run(p);
@@ -9230,11 +9409,11 @@ init_prospects();
9230
9409
  init_embeddings();
9231
9410
 
9232
9411
  // src/core/read/taskCache.ts
9233
- import * as path15 from "path";
9412
+ import * as path16 from "path";
9234
9413
 
9235
9414
  // src/tools/read/tasks.ts
9236
- import * as fs10 from "fs";
9237
- import * as path14 from "path";
9415
+ import * as fs11 from "fs";
9416
+ import * as path15 from "path";
9238
9417
  var TASK_REGEX = /^(\s*)- \[([ xX\-])\]\s+(.+)$/;
9239
9418
  var TAG_REGEX2 = /#([a-zA-Z][a-zA-Z0-9_/-]*)/g;
9240
9419
  var DATE_REGEX = /\b(\d{4}-\d{2}-\d{2}|\d{1,2}\/\d{1,2}\/\d{2,4})\b/;
@@ -9260,7 +9439,7 @@ function extractDueDate(text) {
9260
9439
  async function extractTasksFromNote(notePath, absolutePath) {
9261
9440
  let content;
9262
9441
  try {
9263
- content = await fs10.promises.readFile(absolutePath, "utf-8");
9442
+ content = await fs11.promises.readFile(absolutePath, "utf-8");
9264
9443
  } catch {
9265
9444
  return [];
9266
9445
  }
@@ -9303,7 +9482,7 @@ async function getAllTasks(index, vaultPath2, options = {}) {
9303
9482
  const allTasks = [];
9304
9483
  for (const note of index.notes.values()) {
9305
9484
  if (folder && !note.path.startsWith(folder)) continue;
9306
- const absolutePath = path14.join(vaultPath2, note.path);
9485
+ const absolutePath = path15.join(vaultPath2, note.path);
9307
9486
  const tasks = await extractTasksFromNote(note.path, absolutePath);
9308
9487
  allTasks.push(...tasks);
9309
9488
  }
@@ -9347,7 +9526,7 @@ async function getAllTasks(index, vaultPath2, options = {}) {
9347
9526
  async function getTasksFromNote(index, notePath, vaultPath2, excludeTags = []) {
9348
9527
  const note = index.notes.get(notePath);
9349
9528
  if (!note) return null;
9350
- const absolutePath = path14.join(vaultPath2, notePath);
9529
+ const absolutePath = path15.join(vaultPath2, notePath);
9351
9530
  let tasks = await extractTasksFromNote(notePath, absolutePath);
9352
9531
  if (excludeTags.length > 0) {
9353
9532
  tasks = tasks.filter(
@@ -9418,7 +9597,7 @@ async function buildTaskCache(vaultPath2, index, excludeTags) {
9418
9597
  }
9419
9598
  const allRows = [];
9420
9599
  for (const notePath of notePaths) {
9421
- const absolutePath = path15.join(vaultPath2, notePath);
9600
+ const absolutePath = path16.join(vaultPath2, notePath);
9422
9601
  const tasks = await extractTasksFromNote(notePath, absolutePath);
9423
9602
  for (const task of tasks) {
9424
9603
  if (excludeTags?.length && excludeTags.some((t) => task.tags.includes(t))) {
@@ -9461,7 +9640,7 @@ async function updateTaskCacheForFile(vaultPath2, relativePath) {
9461
9640
  const db4 = getDb3();
9462
9641
  if (!db4) return;
9463
9642
  db4.prepare("DELETE FROM tasks WHERE path = ?").run(relativePath);
9464
- const absolutePath = path15.join(vaultPath2, relativePath);
9643
+ const absolutePath = path16.join(vaultPath2, relativePath);
9465
9644
  const tasks = await extractTasksFromNote(relativePath, absolutePath);
9466
9645
  if (tasks.length > 0) {
9467
9646
  const insertStmt = db4.prepare(`
@@ -10076,7 +10255,7 @@ var PipelineRunner = class {
10076
10255
  removeEmbedding(event.path);
10077
10256
  embRemoved++;
10078
10257
  } else if (event.path.endsWith(".md")) {
10079
- const absPath = path16.join(p.vp, event.path);
10258
+ const absPath = path17.join(p.vp, event.path);
10080
10259
  await updateEmbedding(event.path, absPath);
10081
10260
  embUpdated++;
10082
10261
  }
@@ -10322,7 +10501,7 @@ var PipelineRunner = class {
10322
10501
  for (const event of p.events) {
10323
10502
  if (event.type === "delete" || !event.path.endsWith(".md")) continue;
10324
10503
  try {
10325
- const content = await fs11.readFile(path16.join(p.vp, event.path), "utf-8");
10504
+ const content = await fs12.readFile(path17.join(p.vp, event.path), "utf-8");
10326
10505
  const zones = getProtectedZones(content);
10327
10506
  const linked = new Set(
10328
10507
  (this.forwardLinkResults.find((r) => r.file === event.path)?.resolved ?? []).map((n) => n.toLowerCase())
@@ -10367,7 +10546,7 @@ var PipelineRunner = class {
10367
10546
  for (const event of p.events) {
10368
10547
  if (event.type === "delete" || !event.path.endsWith(".md")) continue;
10369
10548
  try {
10370
- const content = await fs11.readFile(path16.join(p.vp, event.path), "utf-8");
10549
+ const content = await fs12.readFile(path17.join(p.vp, event.path), "utf-8");
10371
10550
  const removed = processImplicitFeedback(p.sd, event.path, content);
10372
10551
  for (const entity of removed) feedbackResults.push({ entity, file: event.path });
10373
10552
  } catch {
@@ -10466,7 +10645,7 @@ var PipelineRunner = class {
10466
10645
  for (const event of p.events) {
10467
10646
  if (event.type === "delete" || !event.path.endsWith(".md")) continue;
10468
10647
  try {
10469
- const content = await fs11.readFile(path16.join(p.vp, event.path), "utf-8");
10648
+ const content = await fs12.readFile(path17.join(p.vp, event.path), "utf-8");
10470
10649
  const zones = getProtectedZones(content);
10471
10650
  const linkedSet = new Set(
10472
10651
  (this.forwardLinkResults.find((r) => r.file === event.path)?.resolved ?? []).concat(this.forwardLinkResults.find((r) => r.file === event.path)?.dead ?? []).map((n) => n.toLowerCase())
@@ -10534,7 +10713,7 @@ var PipelineRunner = class {
10534
10713
  for (const event of p.events) {
10535
10714
  if (event.type === "delete" || !event.path.endsWith(".md")) continue;
10536
10715
  try {
10537
- const rawContent = await fs11.readFile(path16.join(p.vp, event.path), "utf-8");
10716
+ const rawContent = await fs12.readFile(path17.join(p.vp, event.path), "utf-8");
10538
10717
  const content = rawContent.replace(/ → \[\[.*$/gm, "");
10539
10718
  const result = await suggestRelatedLinks(content, {
10540
10719
  maxSuggestions: 5,
@@ -10950,7 +11129,7 @@ function getToolEffectivenessScores(stateDb2, minObservations = 15) {
10950
11129
  }
10951
11130
 
10952
11131
  // src/core/read/integrity.ts
10953
- import * as path17 from "node:path";
11132
+ import * as path18 from "node:path";
10954
11133
  import { existsSync as existsSync3 } from "node:fs";
10955
11134
  import { Worker as Worker2 } from "node:worker_threads";
10956
11135
  import { fileURLToPath as fileURLToPath2 } from "node:url";
@@ -10965,18 +11144,18 @@ var INTEGRITY_METADATA_KEYS = {
10965
11144
  };
10966
11145
  function resolveWorkerSpec() {
10967
11146
  const thisFile = fileURLToPath2(import.meta.url);
10968
- const thisDir = path17.dirname(thisFile);
10969
- const prodPath = path17.join(thisDir, "integrity-worker.js");
11147
+ const thisDir = path18.dirname(thisFile);
11148
+ const prodPath = path18.join(thisDir, "integrity-worker.js");
10970
11149
  if (existsSync3(prodPath)) return { filename: prodPath };
10971
- const distPath = path17.resolve(thisDir, "..", "..", "..", "dist", "integrity-worker.js");
11150
+ const distPath = path18.resolve(thisDir, "..", "..", "..", "dist", "integrity-worker.js");
10972
11151
  if (existsSync3(distPath)) return { filename: distPath };
10973
- const srcPath = path17.join(thisDir, "integrity-worker.ts");
11152
+ const srcPath = path18.join(thisDir, "integrity-worker.ts");
10974
11153
  return { filename: srcPath, execArgv: ["--import", "tsx"] };
10975
11154
  }
10976
11155
  async function runIntegrityWorker(message, timeoutMs = INTEGRITY_CHECK_TIMEOUT_MS) {
10977
11156
  const workerSpec = resolveWorkerSpec();
10978
11157
  return new Promise((resolve4) => {
10979
- const worker2 = new Worker2(workerSpec.filename, {
11158
+ const worker = new Worker2(workerSpec.filename, {
10980
11159
  execArgv: workerSpec.execArgv
10981
11160
  });
10982
11161
  let settled = false;
@@ -10984,7 +11163,7 @@ async function runIntegrityWorker(message, timeoutMs = INTEGRITY_CHECK_TIMEOUT_M
10984
11163
  if (settled) return;
10985
11164
  settled = true;
10986
11165
  clearTimeout(timer2);
10987
- void worker2.terminate().catch(() => {
11166
+ void worker.terminate().catch(() => {
10988
11167
  });
10989
11168
  resolve4(result);
10990
11169
  };
@@ -10996,8 +11175,8 @@ async function runIntegrityWorker(message, timeoutMs = INTEGRITY_CHECK_TIMEOUT_M
10996
11175
  backupCreated: false
10997
11176
  });
10998
11177
  }, timeoutMs);
10999
- worker2.once("message", (result) => finish(result));
11000
- worker2.once("error", (err) => {
11178
+ worker.once("message", (result) => finish(result));
11179
+ worker.once("error", (err) => {
11001
11180
  finish({
11002
11181
  status: "error",
11003
11182
  detail: err.message,
@@ -11005,7 +11184,7 @@ async function runIntegrityWorker(message, timeoutMs = INTEGRITY_CHECK_TIMEOUT_M
11005
11184
  backupCreated: false
11006
11185
  });
11007
11186
  });
11008
- worker2.once("exit", (code) => {
11187
+ worker.once("exit", (code) => {
11009
11188
  if (settled || code === 0) return;
11010
11189
  finish({
11011
11190
  status: "error",
@@ -11014,12 +11193,12 @@ async function runIntegrityWorker(message, timeoutMs = INTEGRITY_CHECK_TIMEOUT_M
11014
11193
  backupCreated: false
11015
11194
  });
11016
11195
  });
11017
- worker2.postMessage(message);
11196
+ worker.postMessage(message);
11018
11197
  });
11019
11198
  }
11020
11199
 
11021
11200
  // src/index.ts
11022
- import { openStateDb, scanVaultEntities as scanVaultEntities4, getAllEntitiesFromDb as getAllEntitiesFromDb6, loadContentHashes, saveContentHashBatch, renameContentHash } from "@velvetmonkey/vault-core";
11201
+ import { openStateDb, scanVaultEntities as scanVaultEntities4, getAllEntitiesFromDb as getAllEntitiesFromDb7, loadContentHashes, saveContentHashBatch, renameContentHash } from "@velvetmonkey/vault-core";
11023
11202
 
11024
11203
  // src/core/write/memory.ts
11025
11204
  init_wikilinkFeedback();
@@ -12028,7 +12207,7 @@ init_recency();
12028
12207
  init_prospects();
12029
12208
  init_cooccurrence();
12030
12209
  init_retrievalCooccurrence();
12031
- import * as fs33 from "node:fs/promises";
12210
+ import * as fs34 from "node:fs/promises";
12032
12211
  import { createHash as createHash3 } from "node:crypto";
12033
12212
 
12034
12213
  // src/vault-registry.ts
@@ -12098,7 +12277,6 @@ init_vault_scope();
12098
12277
  // src/config.ts
12099
12278
  init_embeddings();
12100
12279
  init_serverLog();
12101
- var INITIAL_TIER_OVERRIDE = "auto";
12102
12280
  var ALL_CATEGORIES = [
12103
12281
  "search",
12104
12282
  "read",
@@ -12329,7 +12507,7 @@ var ACTION_PARAM_MAP = {
12329
12507
  policy: ["list", "validate", "preview", "execute", "author", "revise"],
12330
12508
  correct: ["record", "list", "resolve", "undo"],
12331
12509
  link: ["suggest", "feedback", "unlinked", "validate", "stubs", "dashboard", "unsuppress", "timeline", "layer_timeseries", "snapshot_diff"],
12332
- graph: ["analyse", "backlinks", "forward_links", "strong_connections", "path", "neighbors", "strength", "cooccurrence_gaps"],
12510
+ graph: ["analyse", "backlinks", "forward_links", "strong_connections", "path", "neighbors", "strength", "cooccurrence_gaps", "export"],
12333
12511
  schema: ["overview", "field_values", "conventions", "folders", "rename_field", "rename_tag", "migrate", "validate"],
12334
12512
  insights: ["evolution", "staleness", "context", "note_intelligence", "growth"],
12335
12513
  doctor: ["health", "diagnosis", "stats", "pipeline", "config", "log"]
@@ -12547,8 +12725,8 @@ Temporal tools analyze *patterns and changes* over time \u2014 use them for "wha
12547
12725
  }
12548
12726
 
12549
12727
  // src/tool-registry.ts
12550
- import * as path37 from "path";
12551
- import { dirname as dirname6, join as join17 } from "path";
12728
+ import * as path38 from "path";
12729
+ import { dirname as dirname6, join as join18 } from "path";
12552
12730
  import { statSync as statSync5, readFileSync as readFileSync5 } from "fs";
12553
12731
  import { fileURLToPath as fileURLToPath3 } from "url";
12554
12732
  import { z as z25 } from "zod";
@@ -12583,8 +12761,8 @@ import {
12583
12761
  } from "@velvetmonkey/vault-core";
12584
12762
 
12585
12763
  // src/core/read/similarity.ts
12586
- import * as fs12 from "fs";
12587
- import * as path18 from "path";
12764
+ import * as fs13 from "fs";
12765
+ import * as path19 from "path";
12588
12766
  init_embeddings();
12589
12767
 
12590
12768
  // src/core/read/mmr.ts
@@ -12654,10 +12832,10 @@ function extractKeyTerms(content, maxTerms = 15) {
12654
12832
  }
12655
12833
  function findSimilarNotes(db4, vaultPath2, index, sourcePath, options = {}) {
12656
12834
  const limit = options.limit ?? 10;
12657
- const absPath = path18.join(vaultPath2, sourcePath);
12835
+ const absPath = path19.join(vaultPath2, sourcePath);
12658
12836
  let content;
12659
12837
  try {
12660
- content = fs12.readFileSync(absPath, "utf-8");
12838
+ content = fs13.readFileSync(absPath, "utf-8");
12661
12839
  } catch {
12662
12840
  return [];
12663
12841
  }
@@ -13099,13 +13277,13 @@ function multiHopBackfill(primaryResults, index, stateDb2, config2 = {}) {
13099
13277
  candidates.sort((a, b) => b.score - a.score);
13100
13278
  return candidates.slice(0, cfg.maxBackfill).map((c) => c.result);
13101
13279
  }
13102
- function scoreCandidate(path39, index, stateDb2) {
13103
- const note = index.notes.get(path39);
13280
+ function scoreCandidate(path40, index, stateDb2) {
13281
+ const note = index.notes.get(path40);
13104
13282
  const decay = recencyDecay(note?.modified);
13105
13283
  let hubScore = 1;
13106
13284
  if (stateDb2) {
13107
13285
  try {
13108
- const title = note?.title ?? path39.replace(/\.md$/, "").split("/").pop() ?? "";
13286
+ const title = note?.title ?? path40.replace(/\.md$/, "").split("/").pop() ?? "";
13109
13287
  const entity = getEntityByName3(stateDb2, title);
13110
13288
  if (entity) hubScore = entity.hubScore ?? 1;
13111
13289
  } catch {
@@ -13173,7 +13351,7 @@ init_edgeWeights();
13173
13351
  // src/core/read/snippets.ts
13174
13352
  init_embeddings();
13175
13353
  init_stemmer();
13176
- import * as fs13 from "fs";
13354
+ import * as fs14 from "fs";
13177
13355
  function stripFrontmatter(content) {
13178
13356
  const match = content.match(/^---[\s\S]*?---\n([\s\S]*)$/);
13179
13357
  return match ? match[1] : content;
@@ -13252,7 +13430,7 @@ async function extractBestSnippets(filePath, queryEmbedding, queryTokens, option
13252
13430
  const maxChunkChars = options?.maxChunkChars ?? 800;
13253
13431
  let content;
13254
13432
  try {
13255
- content = fs13.readFileSync(filePath, "utf-8");
13433
+ content = fs14.readFileSync(filePath, "utf-8");
13256
13434
  } catch {
13257
13435
  return [];
13258
13436
  }
@@ -13341,8 +13519,8 @@ function extractDates(text) {
13341
13519
  init_stemmer();
13342
13520
 
13343
13521
  // src/tools/read/structure.ts
13344
- import * as fs14 from "fs";
13345
- import * as path19 from "path";
13522
+ import * as fs15 from "fs";
13523
+ import * as path20 from "path";
13346
13524
  var HEADING_REGEX2 = /^(#{1,6})\s+(.+)$/;
13347
13525
  function extractHeadings2(content) {
13348
13526
  const lines = content.replace(/\r\n/g, "\n").split("\n");
@@ -13396,10 +13574,10 @@ function buildSections(headings, totalLines) {
13396
13574
  async function getNoteStructure(index, notePath, vaultPath2) {
13397
13575
  const note = index.notes.get(notePath);
13398
13576
  if (!note) return null;
13399
- const absolutePath = path19.join(vaultPath2, notePath);
13577
+ const absolutePath = path20.join(vaultPath2, notePath);
13400
13578
  let content;
13401
13579
  try {
13402
- content = await fs14.promises.readFile(absolutePath, "utf-8");
13580
+ content = await fs15.promises.readFile(absolutePath, "utf-8");
13403
13581
  } catch {
13404
13582
  return null;
13405
13583
  }
@@ -13420,10 +13598,10 @@ async function getNoteStructure(index, notePath, vaultPath2) {
13420
13598
  async function getSectionContent(index, notePath, headingText, vaultPath2, includeSubheadings = true) {
13421
13599
  const note = index.notes.get(notePath);
13422
13600
  if (!note) return null;
13423
- const absolutePath = path19.join(vaultPath2, notePath);
13601
+ const absolutePath = path20.join(vaultPath2, notePath);
13424
13602
  let content;
13425
13603
  try {
13426
- content = await fs14.promises.readFile(absolutePath, "utf-8");
13604
+ content = await fs15.promises.readFile(absolutePath, "utf-8");
13427
13605
  } catch {
13428
13606
  return null;
13429
13607
  }
@@ -13463,10 +13641,10 @@ async function findSections(index, headingPattern, vaultPath2, folder) {
13463
13641
  const results = [];
13464
13642
  for (const note of index.notes.values()) {
13465
13643
  if (folder && !note.path.startsWith(folder)) continue;
13466
- const absolutePath = path19.join(vaultPath2, note.path);
13644
+ const absolutePath = path20.join(vaultPath2, note.path);
13467
13645
  let content;
13468
13646
  try {
13469
- content = await fs14.promises.readFile(absolutePath, "utf-8");
13647
+ content = await fs15.promises.readFile(absolutePath, "utf-8");
13470
13648
  } catch {
13471
13649
  continue;
13472
13650
  }
@@ -13635,11 +13813,11 @@ function applyEntityBridging(results, stateDb2, maxBridgesPerResult = 5) {
13635
13813
  const linkMap = /* @__PURE__ */ new Map();
13636
13814
  try {
13637
13815
  const paths = results.map((r) => r.path).filter(Boolean);
13638
- for (const path39 of paths) {
13816
+ for (const path40 of paths) {
13639
13817
  const rows = stateDb2.db.prepare(
13640
13818
  "SELECT target FROM note_links WHERE note_path = ?"
13641
- ).all(path39);
13642
- linkMap.set(path39, new Set(rows.map((r) => r.target)));
13819
+ ).all(path40);
13820
+ linkMap.set(path40, new Set(rows.map((r) => r.target)));
13643
13821
  }
13644
13822
  } catch {
13645
13823
  return;
@@ -14131,7 +14309,7 @@ function registerQueryTools(server2, getIndex, getVaultPath, getStateDb4) {
14131
14309
  init_vault_scope();
14132
14310
 
14133
14311
  // src/tools/read/health.ts
14134
- import * as fs15 from "fs";
14312
+ import * as fs16 from "fs";
14135
14313
  import { z as z3 } from "zod";
14136
14314
 
14137
14315
  // src/tools/read/periodic.ts
@@ -14594,7 +14772,7 @@ function registerHealthTools(server2, getIndex, getVaultPath, getConfig2 = () =>
14594
14772
  const indexErrorObj = getIndexError();
14595
14773
  let vaultAccessible = false;
14596
14774
  try {
14597
- fs15.accessSync(vaultPath2, fs15.constants.R_OK);
14775
+ fs16.accessSync(vaultPath2, fs16.constants.R_OK);
14598
14776
  vaultAccessible = true;
14599
14777
  } catch {
14600
14778
  vaultAccessible = false;
@@ -14927,8 +15105,8 @@ function registerHealthTools(server2, getIndex, getVaultPath, getConfig2 = () =>
14927
15105
  daily_counts: z3.record(z3.number())
14928
15106
  }).describe("Activity summary for the last 7 days")
14929
15107
  };
14930
- function isPeriodicNote2(path39) {
14931
- const filename = path39.split("/").pop() || "";
15108
+ function isPeriodicNote2(path40) {
15109
+ const filename = path40.split("/").pop() || "";
14932
15110
  const nameWithoutExt = filename.replace(/\.md$/, "");
14933
15111
  const patterns = [
14934
15112
  /^\d{4}-\d{2}-\d{2}$/,
@@ -14943,7 +15121,7 @@ function registerHealthTools(server2, getIndex, getVaultPath, getConfig2 = () =>
14943
15121
  // YYYY (yearly)
14944
15122
  ];
14945
15123
  const periodicFolders = ["daily", "weekly", "monthly", "quarterly", "yearly", "journal", "journals"];
14946
- const folder = path39.split("/")[0]?.toLowerCase() || "";
15124
+ const folder = path40.split("/")[0]?.toLowerCase() || "";
14947
15125
  return patterns.some((p) => p.test(nameWithoutExt)) || periodicFolders.includes(folder);
14948
15126
  }
14949
15127
  async function runVaultStats() {
@@ -15068,7 +15246,7 @@ function registerHealthTools(server2, getIndex, getVaultPath, getConfig2 = () =>
15068
15246
  const diagWatcherStatus = getWatcherStatus2();
15069
15247
  checks.push({ name: "schema_version", status: "ok", detail: `Schema version ${SCHEMA_VERSION}` });
15070
15248
  try {
15071
- fs15.accessSync(diagVaultPath, fs15.constants.R_OK | fs15.constants.W_OK);
15249
+ fs16.accessSync(diagVaultPath, fs16.constants.R_OK | fs16.constants.W_OK);
15072
15250
  checks.push({ name: "vault_access", status: "ok", detail: `Vault readable and writable at ${diagVaultPath}` });
15073
15251
  } catch {
15074
15252
  checks.push({ name: "vault_access", status: "error", detail: `Vault not accessible at ${diagVaultPath}`, fix: "Check PROJECT_PATH environment variable and directory permissions" });
@@ -15275,6 +15453,17 @@ function registerHealthTools(server2, getIndex, getVaultPath, getConfig2 = () =>
15275
15453
  saveFlywheelConfigToDb3(stateDb2, updated);
15276
15454
  const reloaded = loadConfig(stateDb2);
15277
15455
  if (doctorSetConfig) doctorSetConfig(reloaded);
15456
+ if (key === "tool_tier_override") {
15457
+ return {
15458
+ content: [{
15459
+ type: "text",
15460
+ text: JSON.stringify({
15461
+ config: reloaded,
15462
+ warning: "tool_tier_override is deprecated and has no runtime effect. Use agent, power, or full presets instead."
15463
+ }, null, 2)
15464
+ }]
15465
+ };
15466
+ }
15278
15467
  return { content: [{ type: "text", text: JSON.stringify(reloaded, null, 2) }] };
15279
15468
  }
15280
15469
  case "stats": {
@@ -15942,63 +16131,63 @@ init_constants2();
15942
16131
  init_writer();
15943
16132
  init_wikilinks();
15944
16133
  init_wikilinkFeedback();
15945
- import fs19 from "fs/promises";
15946
- import path23 from "path";
16134
+ import fs20 from "fs/promises";
16135
+ import path24 from "path";
15947
16136
 
15948
16137
  // src/core/write/policy/policyPaths.ts
15949
- import fs18 from "fs/promises";
15950
- import path22 from "path";
16138
+ import fs19 from "fs/promises";
16139
+ import path23 from "path";
15951
16140
  function getPoliciesDir(vaultPath2) {
15952
- return path22.join(vaultPath2, ".flywheel", "policies");
16141
+ return path23.join(vaultPath2, ".flywheel", "policies");
15953
16142
  }
15954
16143
  function getLegacyPoliciesDir(vaultPath2) {
15955
- return path22.join(vaultPath2, ".claude", "policies");
16144
+ return path23.join(vaultPath2, ".claude", "policies");
15956
16145
  }
15957
16146
  async function ensurePoliciesDir(vaultPath2) {
15958
16147
  const dir = getPoliciesDir(vaultPath2);
15959
- await fs18.mkdir(dir, { recursive: true });
16148
+ await fs19.mkdir(dir, { recursive: true });
15960
16149
  }
15961
16150
  async function migratePoliciesIfNeeded(vaultPath2) {
15962
16151
  const legacyDir = getLegacyPoliciesDir(vaultPath2);
15963
16152
  let files;
15964
16153
  try {
15965
- files = await fs18.readdir(legacyDir);
16154
+ files = await fs19.readdir(legacyDir);
15966
16155
  } catch {
15967
16156
  return;
15968
16157
  }
15969
16158
  const yamlFiles = files.filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
15970
16159
  if (yamlFiles.length === 0) {
15971
16160
  await tryRmdir(legacyDir);
15972
- await tryRmdir(path22.join(vaultPath2, ".claude"));
16161
+ await tryRmdir(path23.join(vaultPath2, ".claude"));
15973
16162
  return;
15974
16163
  }
15975
16164
  await ensurePoliciesDir(vaultPath2);
15976
16165
  const destDir = getPoliciesDir(vaultPath2);
15977
16166
  for (const file of yamlFiles) {
15978
- const src = path22.join(legacyDir, file);
15979
- const dest = path22.join(destDir, file);
16167
+ const src = path23.join(legacyDir, file);
16168
+ const dest = path23.join(destDir, file);
15980
16169
  try {
15981
- await fs18.access(dest);
16170
+ await fs19.access(dest);
15982
16171
  } catch {
15983
- await fs18.copyFile(src, dest);
16172
+ await fs19.copyFile(src, dest);
15984
16173
  }
15985
- await fs18.unlink(src);
16174
+ await fs19.unlink(src);
15986
16175
  }
15987
16176
  await tryRmdir(legacyDir);
15988
- await tryRmdir(path22.join(vaultPath2, ".claude"));
16177
+ await tryRmdir(path23.join(vaultPath2, ".claude"));
15989
16178
  }
15990
16179
  async function tryRmdir(dir) {
15991
16180
  try {
15992
- const remaining = await fs18.readdir(dir);
16181
+ const remaining = await fs19.readdir(dir);
15993
16182
  if (remaining.length === 0) {
15994
- await fs18.rmdir(dir);
16183
+ await fs19.rmdir(dir);
15995
16184
  }
15996
16185
  } catch {
15997
16186
  }
15998
16187
  }
15999
16188
  var migrationCache = /* @__PURE__ */ new Map();
16000
16189
  async function ensureMigrated(vaultPath2) {
16001
- const key = path22.resolve(vaultPath2);
16190
+ const key = path23.resolve(vaultPath2);
16002
16191
  if (!migrationCache.has(key)) {
16003
16192
  migrationCache.set(key, migratePoliciesIfNeeded(vaultPath2));
16004
16193
  }
@@ -16054,7 +16243,7 @@ async function handleGitCommit(vaultPath2, notePath, commit, prefix) {
16054
16243
  async function getPolicyHint(vaultPath2) {
16055
16244
  try {
16056
16245
  const policiesDir = getPoliciesDir(vaultPath2);
16057
- const files = await fs19.readdir(policiesDir);
16246
+ const files = await fs20.readdir(policiesDir);
16058
16247
  const yamlFiles = files.filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
16059
16248
  if (yamlFiles.length > 0) {
16060
16249
  const names = yamlFiles.map((f) => f.replace(/\.ya?ml$/, "")).join(", ");
@@ -16069,9 +16258,9 @@ async function ensureFileExists(vaultPath2, notePath) {
16069
16258
  if (!validation.valid) {
16070
16259
  return errorResult(notePath, `Invalid path: ${validation.reason}`);
16071
16260
  }
16072
- const fullPath = path23.join(vaultPath2, notePath);
16261
+ const fullPath = path24.join(vaultPath2, notePath);
16073
16262
  try {
16074
- await fs19.access(fullPath);
16263
+ await fs20.access(fullPath);
16075
16264
  return null;
16076
16265
  } catch {
16077
16266
  const hint = await getPolicyHint(vaultPath2);
@@ -16274,17 +16463,17 @@ async function executeCreateNote(options) {
16274
16463
  if (!pathCheck.valid) {
16275
16464
  return { success: false, result: errorResult(notePath, `Path blocked: ${pathCheck.reason}`), filesWritten: [] };
16276
16465
  }
16277
- const fullPath = path23.join(vaultPath2, notePath);
16466
+ const fullPath = path24.join(vaultPath2, notePath);
16278
16467
  let fileExists = false;
16279
16468
  try {
16280
- await fs19.access(fullPath);
16469
+ await fs20.access(fullPath);
16281
16470
  fileExists = true;
16282
16471
  } catch {
16283
16472
  }
16284
16473
  if (fileExists && !overwrite) {
16285
16474
  return { success: false, result: errorResult(notePath, `File already exists: ${notePath}. Use overwrite=true to replace.`), filesWritten: [] };
16286
16475
  }
16287
- await fs19.mkdir(path23.dirname(fullPath), { recursive: true });
16476
+ await fs20.mkdir(path24.dirname(fullPath), { recursive: true });
16288
16477
  const { maybeApplyWikilinks: maybeApplyWikilinks2 } = await Promise.resolve().then(() => (init_wikilinks(), wikilinks_exports));
16289
16478
  const { content: processedContent } = maybeApplyWikilinks2(content, skipWikilinks ?? false, notePath);
16290
16479
  let finalFrontmatter = frontmatter;
@@ -16318,13 +16507,13 @@ async function executeDeleteNote(options) {
16318
16507
  if (!pathCheck.valid) {
16319
16508
  return { success: false, result: errorResult(notePath, `Path blocked: ${pathCheck.reason}`), filesWritten: [] };
16320
16509
  }
16321
- const fullPath = path23.join(vaultPath2, notePath);
16510
+ const fullPath = path24.join(vaultPath2, notePath);
16322
16511
  try {
16323
- await fs19.access(fullPath);
16512
+ await fs20.access(fullPath);
16324
16513
  } catch {
16325
16514
  return { success: false, result: errorResult(notePath, `File not found: ${notePath}`), filesWritten: [] };
16326
16515
  }
16327
- await fs19.unlink(fullPath);
16516
+ await fs20.unlink(fullPath);
16328
16517
  const result = successResult(notePath, `Deleted note: ${notePath}`, {});
16329
16518
  return { success: true, result, filesWritten: [notePath] };
16330
16519
  } catch (error) {
@@ -16479,19 +16668,19 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig2 = ()
16479
16668
  limit: z7.coerce.number().optional().describe("[sections] Max results (default 50)"),
16480
16669
  offset: z7.coerce.number().optional().describe("[sections] Results to skip for pagination (default 0)")
16481
16670
  };
16482
- const noteReadImpl = async ({ action, path: path39, include_content, max_content_chars, heading, include_subheadings, max_section_chars, pattern, folder, limit: requestedLimit, offset: requestedOffset }) => {
16671
+ const noteReadImpl = async ({ action, path: path40, include_content, max_content_chars, heading, include_subheadings, max_section_chars, pattern, folder, limit: requestedLimit, offset: requestedOffset }) => {
16483
16672
  const index = getIndex();
16484
16673
  const vaultPath2 = getVaultPath();
16485
16674
  if (action === "structure") {
16486
- if (!path39) {
16675
+ if (!path40) {
16487
16676
  return { content: [{ type: "text", text: JSON.stringify({
16488
16677
  error: "action=structure requires path.",
16489
16678
  example: { action: "structure", path: "projects/alpha.md" }
16490
16679
  }, null, 2) }] };
16491
16680
  }
16492
- const result2 = await getNoteStructure(index, path39, vaultPath2);
16681
+ const result2 = await getNoteStructure(index, path40, vaultPath2);
16493
16682
  if (!result2) {
16494
- return { content: [{ type: "text", text: JSON.stringify({ error: "Note not found", path: path39 }, null, 2) }] };
16683
+ return { content: [{ type: "text", text: JSON.stringify({ error: "Note not found", path: path40 }, null, 2) }] };
16495
16684
  }
16496
16685
  const maxChars = max_content_chars ?? 2e4;
16497
16686
  let totalChars = 0;
@@ -16502,7 +16691,7 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig2 = ()
16502
16691
  truncated = true;
16503
16692
  break;
16504
16693
  }
16505
- const sectionResult = await getSectionContent(index, path39, section.heading.text, vaultPath2, true);
16694
+ const sectionResult = await getSectionContent(index, path40, section.heading.text, vaultPath2, true);
16506
16695
  if (sectionResult) {
16507
16696
  let content = sectionResult.content;
16508
16697
  const remaining = maxChars - totalChars;
@@ -16517,13 +16706,13 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig2 = ()
16517
16706
  }
16518
16707
  }
16519
16708
  }
16520
- const note = index.notes.get(path39);
16709
+ const note = index.notes.get(path40);
16521
16710
  const enriched = { ...result2 };
16522
16711
  if (note) {
16523
16712
  enriched.frontmatter = note.frontmatter;
16524
16713
  enriched.tags = note.tags;
16525
16714
  enriched.aliases = note.aliases;
16526
- const normalizedPath = path39.toLowerCase().replace(/\.md$/, "");
16715
+ const normalizedPath = path40.toLowerCase().replace(/\.md$/, "");
16527
16716
  const backlinks = index.backlinks.get(normalizedPath) || [];
16528
16717
  enriched.backlink_count = backlinks.length;
16529
16718
  enriched.outlink_count = note.outlinks.length;
@@ -16547,7 +16736,7 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig2 = ()
16547
16736
  return { content: [{ type: "text", text: JSON.stringify(enriched, null, 2) }] };
16548
16737
  }
16549
16738
  if (action === "section") {
16550
- if (!path39) {
16739
+ if (!path40) {
16551
16740
  return { content: [{ type: "text", text: JSON.stringify({
16552
16741
  error: "action=section requires path.",
16553
16742
  example: { action: "section", path: "projects/alpha.md", heading: "Background" }
@@ -16559,9 +16748,9 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig2 = ()
16559
16748
  example: { action: "section", path: "projects/alpha.md", heading: "Background" }
16560
16749
  }, null, 2) }] };
16561
16750
  }
16562
- const result2 = await getSectionContent(index, path39, heading, vaultPath2, include_subheadings ?? true);
16751
+ const result2 = await getSectionContent(index, path40, heading, vaultPath2, include_subheadings ?? true);
16563
16752
  if (!result2) {
16564
- return { content: [{ type: "text", text: JSON.stringify({ error: "Section not found", path: path39, heading }, null, 2) }] };
16753
+ return { content: [{ type: "text", text: JSON.stringify({ error: "Section not found", path: path40, heading }, null, 2) }] };
16565
16754
  }
16566
16755
  const maxChars = max_section_chars ?? 1e4;
16567
16756
  let truncated = false;
@@ -16617,32 +16806,32 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig2 = ()
16617
16806
  session_id: z7.string().optional().describe("[toggle] Session identifier for scoping")
16618
16807
  }
16619
16808
  },
16620
- async ({ action = "list", path: path39, status, has_due_date, folder, tag, limit: requestedLimit, offset, task, section, commit, dry_run, agent_id, session_id }) => {
16809
+ async ({ action = "list", path: path40, status, has_due_date, folder, tag, limit: requestedLimit, offset, task, section, commit, dry_run, agent_id, session_id }) => {
16621
16810
  if (action === "toggle") {
16622
- if (!path39 || !task) {
16623
- return formatMcpResult(errorResult(path39 ?? "", "toggle requires path and task"));
16811
+ if (!path40 || !task) {
16812
+ return formatMcpResult(errorResult(path40 ?? "", "toggle requires path and task"));
16624
16813
  }
16625
16814
  const vaultPath3 = getVaultPath();
16626
16815
  try {
16627
- const existsError = await ensureFileExists(vaultPath3, path39);
16816
+ const existsError = await ensureFileExists(vaultPath3, path40);
16628
16817
  if (existsError) return formatMcpResult(existsError);
16629
- const { content: fileContent, frontmatter, contentHash: contentHash2 } = await readVaultFile(vaultPath3, path39);
16818
+ const { content: fileContent, frontmatter, contentHash: contentHash2 } = await readVaultFile(vaultPath3, path40);
16630
16819
  let sectionBoundary;
16631
16820
  if (section) {
16632
16821
  const found = findSection(fileContent, section);
16633
- if (!found) return formatMcpResult(errorResult(path39, `Section not found: ${section}`));
16822
+ if (!found) return formatMcpResult(errorResult(path40, `Section not found: ${section}`));
16634
16823
  sectionBoundary = found;
16635
16824
  }
16636
16825
  const tasks = findTasks(fileContent, sectionBoundary ?? void 0);
16637
16826
  const searchLower = task.toLowerCase();
16638
16827
  const matchingTask = tasks.find((t) => t.text.toLowerCase().includes(searchLower));
16639
- if (!matchingTask) return formatMcpResult(errorResult(path39, `No task found matching "${task}"`));
16828
+ if (!matchingTask) return formatMcpResult(errorResult(path40, `No task found matching "${task}"`));
16640
16829
  const toggleResult = toggleTask(fileContent, matchingTask.line);
16641
- if (!toggleResult) return formatMcpResult(errorResult(path39, "Failed to toggle task"));
16830
+ if (!toggleResult) return formatMcpResult(errorResult(path40, "Failed to toggle task"));
16642
16831
  const newStatus = toggleResult.newState ? "completed" : "incomplete";
16643
16832
  const checkbox = toggleResult.newState ? "[x]" : "[ ]";
16644
16833
  if (dry_run) {
16645
- return formatMcpResult(successResult(path39, `[dry run] Would toggle task to ${newStatus}`, {}, {
16834
+ return formatMcpResult(successResult(path40, `[dry run] Would toggle task to ${newStatus}`, {}, {
16646
16835
  preview: `${checkbox} ${matchingTask.text}`,
16647
16836
  dryRun: true
16648
16837
  }));
@@ -16651,11 +16840,11 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig2 = ()
16651
16840
  if (agent_id || session_id) {
16652
16841
  finalFrontmatter = injectMutationMetadata(frontmatter, { agent_id, session_id });
16653
16842
  }
16654
- await writeVaultFile(vaultPath3, path39, toggleResult.content, finalFrontmatter, "LF", contentHash2);
16655
- await updateTaskCacheForFile(vaultPath3, path39).catch(() => {
16843
+ await writeVaultFile(vaultPath3, path40, toggleResult.content, finalFrontmatter, "LF", contentHash2);
16844
+ await updateTaskCacheForFile(vaultPath3, path40).catch(() => {
16656
16845
  });
16657
- const gitInfo = await handleGitCommit(vaultPath3, path39, commit ?? false, "[Flywheel:Task]");
16658
- return formatMcpResult(successResult(path39, `Toggled task to ${newStatus}`, gitInfo, {
16846
+ const gitInfo = await handleGitCommit(vaultPath3, path40, commit ?? false, "[Flywheel:Task]");
16847
+ return formatMcpResult(successResult(path40, `Toggled task to ${newStatus}`, gitInfo, {
16659
16848
  preview: `${checkbox} ${matchingTask.text}`
16660
16849
  }));
16661
16850
  } catch (error) {
@@ -16663,18 +16852,18 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig2 = ()
16663
16852
  if (error instanceof WriteConflictError) {
16664
16853
  extras.warnings = [{ type: "write_conflict", message: error.message, suggestion: "Re-read and retry." }];
16665
16854
  }
16666
- return formatMcpResult(errorResult(path39, `Failed to toggle task: ${error instanceof Error ? error.message : String(error)}`, extras));
16855
+ return formatMcpResult(errorResult(path40, `Failed to toggle task: ${error instanceof Error ? error.message : String(error)}`, extras));
16667
16856
  }
16668
16857
  }
16669
16858
  const limit = Math.min(requestedLimit ?? 25, MAX_LIMIT);
16670
16859
  const index = getIndex();
16671
16860
  const vaultPath2 = getVaultPath();
16672
16861
  const config2 = getConfig2();
16673
- if (path39) {
16674
- const result2 = await getTasksFromNote(index, path39, vaultPath2, getExcludeTags(config2));
16862
+ if (path40) {
16863
+ const result2 = await getTasksFromNote(index, path40, vaultPath2, getExcludeTags(config2));
16675
16864
  if (!result2) {
16676
16865
  return {
16677
- content: [{ type: "text", text: JSON.stringify({ error: "Note not found", path: path39 }, null, 2) }]
16866
+ content: [{ type: "text", text: JSON.stringify({ error: "Note not found", path: path40 }, null, 2) }]
16678
16867
  };
16679
16868
  }
16680
16869
  let filtered = result2;
@@ -16684,7 +16873,7 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig2 = ()
16684
16873
  const paged2 = filtered.slice(offset, offset + limit);
16685
16874
  return {
16686
16875
  content: [{ type: "text", text: JSON.stringify({
16687
- path: path39,
16876
+ path: path40,
16688
16877
  total_count: filtered.length,
16689
16878
  returned_count: paged2.length,
16690
16879
  open: result2.filter((t) => t.status === "open").length,
@@ -17040,8 +17229,8 @@ function inferFolderConventions(index, folder, minConfidence = 0.5) {
17040
17229
 
17041
17230
  // src/tools/read/migrations.ts
17042
17231
  import { z as z8 } from "zod";
17043
- import * as fs20 from "fs/promises";
17044
- import * as path24 from "path";
17232
+ import * as fs21 from "fs/promises";
17233
+ import * as path25 from "path";
17045
17234
  import matter3 from "gray-matter";
17046
17235
  function getNotesInFolder2(index, folder) {
17047
17236
  const notes = [];
@@ -17054,17 +17243,17 @@ function getNotesInFolder2(index, folder) {
17054
17243
  return notes;
17055
17244
  }
17056
17245
  async function readFileContent(notePath, vaultPath2) {
17057
- const fullPath = path24.join(vaultPath2, notePath);
17246
+ const fullPath = path25.join(vaultPath2, notePath);
17058
17247
  try {
17059
- return await fs20.readFile(fullPath, "utf-8");
17248
+ return await fs21.readFile(fullPath, "utf-8");
17060
17249
  } catch {
17061
17250
  return null;
17062
17251
  }
17063
17252
  }
17064
17253
  async function writeFileContent(notePath, vaultPath2, content) {
17065
- const fullPath = path24.join(vaultPath2, notePath);
17254
+ const fullPath = path25.join(vaultPath2, notePath);
17066
17255
  try {
17067
- await fs20.writeFile(fullPath, content, "utf-8");
17256
+ await fs21.writeFile(fullPath, content, "utf-8");
17068
17257
  return true;
17069
17258
  } catch {
17070
17259
  return false;
@@ -17182,8 +17371,8 @@ async function migrateFieldValues(index, vaultPath2, field, mapping, options) {
17182
17371
  }
17183
17372
 
17184
17373
  // src/core/write/tagRename.ts
17185
- import * as fs21 from "fs/promises";
17186
- import * as path25 from "path";
17374
+ import * as fs22 from "fs/promises";
17375
+ import * as path26 from "path";
17187
17376
  import matter4 from "gray-matter";
17188
17377
  import { getProtectedZones as getProtectedZones2 } from "@velvetmonkey/vault-core";
17189
17378
  function getNotesInFolder3(index, folder) {
@@ -17289,10 +17478,10 @@ async function renameTag(index, vaultPath2, oldTag, newTag, options) {
17289
17478
  const previews = [];
17290
17479
  let totalChanges = 0;
17291
17480
  for (const note of affectedNotes) {
17292
- const fullPath = path25.join(vaultPath2, note.path);
17481
+ const fullPath = path26.join(vaultPath2, note.path);
17293
17482
  let fileContent;
17294
17483
  try {
17295
- fileContent = await fs21.readFile(fullPath, "utf-8");
17484
+ fileContent = await fs22.readFile(fullPath, "utf-8");
17296
17485
  } catch {
17297
17486
  continue;
17298
17487
  }
@@ -17365,7 +17554,7 @@ async function renameTag(index, vaultPath2, oldTag, newTag, options) {
17365
17554
  previews.push(preview);
17366
17555
  if (!dryRun) {
17367
17556
  const newContent = matter4.stringify(updatedContent, fm);
17368
- await fs21.writeFile(fullPath, newContent, "utf-8");
17557
+ await fs22.writeFile(fullPath, newContent, "utf-8");
17369
17558
  }
17370
17559
  }
17371
17560
  }
@@ -17458,8 +17647,8 @@ function registerSchemaTools(server2, getIndex, getVaultPath) {
17458
17647
  ensureFolder(parentFolder);
17459
17648
  folderMap.get(parentFolder).note_count += 1;
17460
17649
  }
17461
- const folders = Array.from(folderMap.entries()).filter(([f]) => f !== "").sort(([a], [b]) => a.localeCompare(b)).map(([path39, data]) => ({
17462
- path: path39,
17650
+ const folders = Array.from(folderMap.entries()).filter(([f]) => f !== "").sort(([a], [b]) => a.localeCompare(b)).map(([path40, data]) => ({
17651
+ path: path40,
17463
17652
  note_count: data.note_count,
17464
17653
  subfolder_count: data.subfolders.size
17465
17654
  }));
@@ -17699,12 +17888,246 @@ function getConnectionStrength(index, noteAPath, noteBPath) {
17699
17888
 
17700
17889
  // src/tools/read/graphTools.ts
17701
17890
  init_wikilinks();
17891
+
17892
+ // src/tools/read/graphExport.ts
17893
+ import { getAllEntitiesFromDb as getAllEntitiesFromDb4 } from "@velvetmonkey/vault-core";
17894
+ init_cooccurrence();
17895
+ function escapeXml(s) {
17896
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
17897
+ }
17898
+ function xmlId(prefix, value) {
17899
+ return `${prefix}:${value}`;
17900
+ }
17901
+ function dataTag(key, value) {
17902
+ if (value === void 0 || value === null) return "";
17903
+ return ` <data key="${key}">${escapeXml(String(value))}</data>
17904
+ `;
17905
+ }
17906
+ function buildGraphData(index, stateDb2, options) {
17907
+ const nodes = [];
17908
+ const edges = [];
17909
+ const noteIds = /* @__PURE__ */ new Set();
17910
+ const entityIds = /* @__PURE__ */ new Set();
17911
+ for (const [notePath, note] of index.notes) {
17912
+ const id = xmlId("note", notePath);
17913
+ noteIds.add(id);
17914
+ nodes.push({
17915
+ id,
17916
+ label: note.title,
17917
+ type: "note",
17918
+ category: typeof note.frontmatter?.type === "string" ? note.frontmatter.type : void 0,
17919
+ modified: note.modified?.toISOString(),
17920
+ tags: note.tags.length > 0 ? note.tags.join(", ") : void 0
17921
+ });
17922
+ }
17923
+ if (stateDb2) {
17924
+ const entities = getAllEntitiesFromDb4(stateDb2);
17925
+ for (const entity of entities) {
17926
+ const id = xmlId("entity", entity.name);
17927
+ if (entityIds.has(id)) continue;
17928
+ entityIds.add(id);
17929
+ nodes.push({
17930
+ id,
17931
+ label: entity.name,
17932
+ type: "entity",
17933
+ category: entity.category,
17934
+ hub_score: entity.hubScore,
17935
+ aliases: entity.aliases.length > 0 ? entity.aliases.join(", ") : void 0
17936
+ });
17937
+ }
17938
+ }
17939
+ const seenWikilinks = /* @__PURE__ */ new Set();
17940
+ for (const [notePath, note] of index.notes) {
17941
+ const sourceId = xmlId("note", notePath);
17942
+ for (const link of note.outlinks) {
17943
+ const resolved = resolveTarget(index, link.target);
17944
+ if (!resolved) continue;
17945
+ const targetId = xmlId("note", resolved);
17946
+ const edgeKey = `${sourceId}\u2192${targetId}`;
17947
+ if (seenWikilinks.has(edgeKey)) continue;
17948
+ seenWikilinks.add(edgeKey);
17949
+ edges.push({
17950
+ source: sourceId,
17951
+ target: targetId,
17952
+ edge_type: "wikilink",
17953
+ weight: 1
17954
+ });
17955
+ }
17956
+ }
17957
+ if (stateDb2) {
17958
+ const rows = stateDb2.db.prepare(
17959
+ "SELECT note_path, target, weight FROM note_links WHERE weight >= ?"
17960
+ ).all(options.min_edge_weight);
17961
+ for (const row of rows) {
17962
+ const sourceId = xmlId("note", row.note_path);
17963
+ if (!noteIds.has(sourceId)) continue;
17964
+ const targetLower = row.target.toLowerCase();
17965
+ let targetId;
17966
+ if (entityIds.has(xmlId("entity", row.target))) {
17967
+ targetId = xmlId("entity", row.target);
17968
+ } else {
17969
+ for (const node of nodes) {
17970
+ if (node.type !== "entity") continue;
17971
+ if (node.label.toLowerCase() === targetLower) {
17972
+ targetId = node.id;
17973
+ break;
17974
+ }
17975
+ if (node.aliases) {
17976
+ const aliases = node.aliases.split(", ").map((alias) => alias.toLowerCase());
17977
+ if (aliases.includes(targetLower)) {
17978
+ targetId = node.id;
17979
+ break;
17980
+ }
17981
+ }
17982
+ }
17983
+ }
17984
+ if (!targetId) continue;
17985
+ edges.push({
17986
+ source: sourceId,
17987
+ target: targetId,
17988
+ edge_type: "weighted",
17989
+ weight: row.weight
17990
+ });
17991
+ }
17992
+ }
17993
+ if (options.include_cooccurrence && stateDb2) {
17994
+ const cached = loadCooccurrenceFromStateDb(stateDb2);
17995
+ if (cached) {
17996
+ const seenCooccurrence = /* @__PURE__ */ new Set();
17997
+ for (const [entityName, associations] of Object.entries(cached.index.associations)) {
17998
+ const sourceId = xmlId("entity", entityName);
17999
+ if (!entityIds.has(sourceId)) continue;
18000
+ for (const [relatedName, count] of associations) {
18001
+ const targetId = xmlId("entity", relatedName);
18002
+ if (!entityIds.has(targetId)) continue;
18003
+ const pairKey = [entityName, relatedName].sort().join("\u2194");
18004
+ if (seenCooccurrence.has(pairKey)) continue;
18005
+ seenCooccurrence.add(pairKey);
18006
+ edges.push({
18007
+ source: sourceId,
18008
+ target: targetId,
18009
+ edge_type: "cooccurrence",
18010
+ weight: count
18011
+ });
18012
+ }
18013
+ }
18014
+ }
18015
+ }
18016
+ if (options.center_entity) {
18017
+ const centerLower = options.center_entity.toLowerCase();
18018
+ const maxDepth = options.depth ?? 1;
18019
+ const centerNode = nodes.find((node) => node.label.toLowerCase() === centerLower);
18020
+ if (centerNode) {
18021
+ const adjacency = /* @__PURE__ */ new Map();
18022
+ for (const edge of edges) {
18023
+ if (!adjacency.has(edge.source)) adjacency.set(edge.source, /* @__PURE__ */ new Set());
18024
+ if (!adjacency.has(edge.target)) adjacency.set(edge.target, /* @__PURE__ */ new Set());
18025
+ adjacency.get(edge.source).add(edge.target);
18026
+ adjacency.get(edge.target).add(edge.source);
18027
+ }
18028
+ const reachable = /* @__PURE__ */ new Set([centerNode.id]);
18029
+ const queue = [{ id: centerNode.id, depth: 0 }];
18030
+ while (queue.length > 0) {
18031
+ const current = queue.shift();
18032
+ if (current.depth >= maxDepth) continue;
18033
+ for (const neighbor of adjacency.get(current.id) ?? []) {
18034
+ if (reachable.has(neighbor)) continue;
18035
+ reachable.add(neighbor);
18036
+ queue.push({ id: neighbor, depth: current.depth + 1 });
18037
+ }
18038
+ }
18039
+ const filteredNodes = nodes.filter((node) => reachable.has(node.id));
18040
+ const filteredEdges = edges.filter(
18041
+ (edge) => reachable.has(edge.source) && reachable.has(edge.target)
18042
+ );
18043
+ return {
18044
+ nodes: filteredNodes,
18045
+ edges: filteredEdges,
18046
+ metadata: {
18047
+ note_count: filteredNodes.filter((node) => node.type === "note").length,
18048
+ entity_count: filteredNodes.filter((node) => node.type === "entity").length,
18049
+ edge_count: filteredEdges.length,
18050
+ exported_at: (/* @__PURE__ */ new Date()).toISOString()
18051
+ }
18052
+ };
18053
+ }
18054
+ }
18055
+ return {
18056
+ nodes,
18057
+ edges,
18058
+ metadata: {
18059
+ note_count: index.notes.size,
18060
+ entity_count: entityIds.size,
18061
+ edge_count: edges.length,
18062
+ exported_at: (/* @__PURE__ */ new Date()).toISOString()
18063
+ }
18064
+ };
18065
+ }
18066
+ function toGraphML(data) {
18067
+ let xml = `<?xml version="1.0" encoding="UTF-8"?>
18068
+ `;
18069
+ xml += `<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
18070
+ `;
18071
+ xml += ` xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
18072
+ `;
18073
+ xml += ` xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
18074
+ `;
18075
+ xml += ` <key id="label" for="node" attr.name="label" attr.type="string"/>
18076
+ `;
18077
+ xml += ` <key id="type" for="node" attr.name="type" attr.type="string"/>
18078
+ `;
18079
+ xml += ` <key id="category" for="node" attr.name="category" attr.type="string"/>
18080
+ `;
18081
+ xml += ` <key id="hub_score" for="node" attr.name="hub_score" attr.type="double"/>
18082
+ `;
18083
+ xml += ` <key id="modified" for="node" attr.name="modified" attr.type="string"/>
18084
+ `;
18085
+ xml += ` <key id="tags" for="node" attr.name="tags" attr.type="string"/>
18086
+ `;
18087
+ xml += ` <key id="aliases" for="node" attr.name="aliases" attr.type="string"/>
18088
+ `;
18089
+ xml += ` <key id="edge_type" for="edge" attr.name="edge_type" attr.type="string"/>
18090
+ `;
18091
+ xml += ` <key id="weight" for="edge" attr.name="weight" attr.type="double"/>
18092
+ `;
18093
+ xml += ` <graph id="vault" edgedefault="directed">
18094
+ `;
18095
+ for (const node of data.nodes) {
18096
+ xml += ` <node id="${escapeXml(node.id)}">
18097
+ `;
18098
+ xml += dataTag("label", node.label);
18099
+ xml += dataTag("type", node.type);
18100
+ xml += dataTag("category", node.category);
18101
+ xml += dataTag("hub_score", node.hub_score);
18102
+ xml += dataTag("modified", node.modified);
18103
+ xml += dataTag("tags", node.tags);
18104
+ xml += dataTag("aliases", node.aliases);
18105
+ xml += ` </node>
18106
+ `;
18107
+ }
18108
+ let edgeIndex = 0;
18109
+ for (const edge of data.edges) {
18110
+ xml += ` <edge id="e${edgeIndex++}" source="${escapeXml(edge.source)}" target="${escapeXml(edge.target)}">
18111
+ `;
18112
+ xml += dataTag("edge_type", edge.edge_type);
18113
+ xml += dataTag("weight", edge.weight);
18114
+ xml += ` </edge>
18115
+ `;
18116
+ }
18117
+ xml += ` </graph>
18118
+ `;
18119
+ xml += `</graphml>
18120
+ `;
18121
+ return xml;
18122
+ }
18123
+
18124
+ // src/tools/read/graphTools.ts
17702
18125
  function registerGraphTools2(server2, getIndex, getVaultPath, getStateDb4) {
17703
18126
  server2.registerTool(
17704
18127
  "graph",
17705
18128
  {
17706
18129
  title: "Graph",
17707
- description: 'Vault graph analysis. action: analyse \u2014 hubs/orphans/clusters. action: backlinks/forward_links \u2014 links to/from note. action: strong_connections \u2014 top links. action: path \u2014 shortest chain. action: neighbors \u2014 shared connections. action: strength \u2014 link weight. action: cooccurrence_gaps \u2014 unlinked co-occurring pairs. Returns metrics, links, paths, or gaps. Does not modify notes. e.g. { action:"backlinks", path:"people/alice.md" } { action:"path", from:"projects/x.md", to:"people/bob.md" }',
18130
+ description: "Vault graph analysis. action: analyse \u2014 hubs/orphans/clusters. action: backlinks/forward_links \u2014 links to/from note. action: strong_connections \u2014 top links. action: path \u2014 shortest chain. action: neighbors \u2014 shared connections. action: strength \u2014 link weight. action: cooccurrence_gaps \u2014 unlinked co-occurring pairs. action: export \u2014 GraphML or JSON export for Gephi, yEd, Cytoscape, or code. Returns metrics, links, paths, gaps, or serialized graph data. Does not modify notes.",
17708
18131
  inputSchema: {
17709
18132
  action: z10.enum([
17710
18133
  "analyse",
@@ -17714,7 +18137,8 @@ function registerGraphTools2(server2, getIndex, getVaultPath, getStateDb4) {
17714
18137
  "path",
17715
18138
  "neighbors",
17716
18139
  "strength",
17717
- "cooccurrence_gaps"
18140
+ "cooccurrence_gaps",
18141
+ "export"
17718
18142
  ]).describe("Graph operation to perform"),
17719
18143
  limit: z10.coerce.number().optional().describe("[analyse|cooccurrence_gaps] Maximum results to return"),
17720
18144
  path: z10.string().optional().describe("[backlinks|forward_links|strong_connections] Note path"),
@@ -17722,7 +18146,13 @@ function registerGraphTools2(server2, getIndex, getVaultPath, getStateDb4) {
17722
18146
  to: z10.string().optional().describe("[path] Target note path"),
17723
18147
  path_a: z10.string().optional().describe("[neighbors|strength] First note path"),
17724
18148
  path_b: z10.string().optional().describe("[neighbors|strength] Second note path"),
17725
- entity: z10.string().optional().describe("[cooccurrence_gaps] Entity name to find gaps for")
18149
+ entity: z10.string().optional().describe("[cooccurrence_gaps] Entity name to find gaps for"),
18150
+ format: z10.enum(["graphml", "json"]).optional().describe("[export] Output format: graphml for Gephi/yEd/Cytoscape, json for programmatic use"),
18151
+ include_cooccurrence: z10.boolean().optional().describe("[export] Include co-occurrence edges between entities (default true)"),
18152
+ min_edge_weight: z10.coerce.number().optional().describe("[export] Minimum edge weight threshold for learned weighted edges"),
18153
+ center_entity: z10.string().optional().describe("[export] Center the export on this entity; only include nodes within depth hops"),
18154
+ depth: z10.coerce.number().optional().describe("[export] Hops from center_entity to include (default 1)"),
18155
+ max_nodes: z10.coerce.number().optional().describe("[export] Maximum nodes when center_entity is omitted (default 500)")
17726
18156
  }
17727
18157
  },
17728
18158
  async (params) => {
@@ -17979,6 +18409,43 @@ function registerGraphTools2(server2, getIndex, getVaultPath, getStateDb4) {
17979
18409
  }, null, 2) }]
17980
18410
  };
17981
18411
  }
18412
+ // -----------------------------------------------------------------
18413
+ // export — scoped/full graph export as GraphML or JSON
18414
+ // -----------------------------------------------------------------
18415
+ case "export": {
18416
+ const stateDb2 = getStateDb4?.() ?? null;
18417
+ const format = params.format ?? "graphml";
18418
+ const includeCooccurrence = params.include_cooccurrence ?? true;
18419
+ const minEdgeWeight = params.min_edge_weight ?? 0;
18420
+ const depth = params.depth ?? 1;
18421
+ const maxNodes = params.max_nodes ?? 500;
18422
+ const data = buildGraphData(index, stateDb2, {
18423
+ include_cooccurrence: includeCooccurrence,
18424
+ min_edge_weight: minEdgeWeight,
18425
+ center_entity: params.center_entity,
18426
+ depth
18427
+ });
18428
+ if (!params.center_entity && data.nodes.length > maxNodes) {
18429
+ return {
18430
+ content: [{
18431
+ type: "text",
18432
+ text: JSON.stringify({
18433
+ error: `Graph has ${data.nodes.length} nodes and ${data.edges.length} edges, exceeding max_nodes=${maxNodes}. Use center_entity to scope the export or raise max_nodes.`,
18434
+ node_count: data.nodes.length,
18435
+ edge_count: data.edges.length,
18436
+ max_nodes: maxNodes
18437
+ }, null, 2)
18438
+ }],
18439
+ isError: true
18440
+ };
18441
+ }
18442
+ return {
18443
+ content: [{
18444
+ type: "text",
18445
+ text: format === "json" ? JSON.stringify(data, null, 2) : toGraphML(data)
18446
+ }]
18447
+ };
18448
+ }
17982
18449
  }
17983
18450
  }
17984
18451
  );
@@ -17988,15 +18455,15 @@ function registerGraphTools2(server2, getIndex, getVaultPath, getStateDb4) {
17988
18455
  import { z as z11 } from "zod";
17989
18456
 
17990
18457
  // src/tools/read/bidirectional.ts
17991
- import * as fs22 from "fs/promises";
17992
- import * as path26 from "path";
18458
+ import * as fs23 from "fs/promises";
18459
+ import * as path27 from "path";
17993
18460
  import matter5 from "gray-matter";
17994
18461
  var PROSE_PATTERN_REGEX = /^([A-Za-z][A-Za-z0-9 _-]*):\s*(?:\[\[([^\]]+)\]\]|"([^"]+)"|([^\n]+?))\s*$/gm;
17995
18462
  var CODE_BLOCK_REGEX2 = /```[\s\S]*?```|`[^`\n]+`/g;
17996
18463
  async function readFileContent2(notePath, vaultPath2) {
17997
- const fullPath = path26.join(vaultPath2, notePath);
18464
+ const fullPath = path27.join(vaultPath2, notePath);
17998
18465
  try {
17999
- return await fs22.readFile(fullPath, "utf-8");
18466
+ return await fs23.readFile(fullPath, "utf-8");
18000
18467
  } catch {
18001
18468
  return null;
18002
18469
  }
@@ -18172,21 +18639,21 @@ async function suggestWikilinksInFrontmatter(index, notePath, vaultPath2) {
18172
18639
  }
18173
18640
 
18174
18641
  // src/tools/read/computed.ts
18175
- import * as fs23 from "fs/promises";
18176
- import * as path27 from "path";
18642
+ import * as fs24 from "fs/promises";
18643
+ import * as path28 from "path";
18177
18644
  import matter6 from "gray-matter";
18178
18645
  async function readFileContent3(notePath, vaultPath2) {
18179
- const fullPath = path27.join(vaultPath2, notePath);
18646
+ const fullPath = path28.join(vaultPath2, notePath);
18180
18647
  try {
18181
- return await fs23.readFile(fullPath, "utf-8");
18648
+ return await fs24.readFile(fullPath, "utf-8");
18182
18649
  } catch {
18183
18650
  return null;
18184
18651
  }
18185
18652
  }
18186
18653
  async function getFileStats(notePath, vaultPath2) {
18187
- const fullPath = path27.join(vaultPath2, notePath);
18654
+ const fullPath = path28.join(vaultPath2, notePath);
18188
18655
  try {
18189
- const stats = await fs23.stat(fullPath);
18656
+ const stats = await fs24.stat(fullPath);
18190
18657
  return {
18191
18658
  modified: stats.mtime,
18192
18659
  created: stats.birthtime
@@ -18773,7 +19240,7 @@ function registerFrontmatterTools(server2, getVaultPath) {
18773
19240
  }
18774
19241
 
18775
19242
  // src/tools/write/policy.ts
18776
- import * as path32 from "path";
19243
+ import * as path33 from "path";
18777
19244
  import { z as z14 } from "zod";
18778
19245
 
18779
19246
  // src/core/write/policy/index.ts
@@ -18782,8 +19249,8 @@ init_schema();
18782
19249
 
18783
19250
  // src/core/write/policy/parser.ts
18784
19251
  init_schema();
18785
- import fs24 from "fs/promises";
18786
- import path28 from "path";
19252
+ import fs25 from "fs/promises";
19253
+ import path29 from "path";
18787
19254
  import matter7 from "gray-matter";
18788
19255
  function parseYaml(content) {
18789
19256
  const parsed = matter7(`---
@@ -18808,7 +19275,7 @@ function parsePolicyString(yamlContent) {
18808
19275
  }
18809
19276
  async function loadPolicyFile(filePath) {
18810
19277
  try {
18811
- const content = await fs24.readFile(filePath, "utf-8");
19278
+ const content = await fs25.readFile(filePath, "utf-8");
18812
19279
  return parsePolicyString(content);
18813
19280
  } catch (error) {
18814
19281
  if (error.code === "ENOENT") {
@@ -18834,14 +19301,14 @@ async function loadPolicyFile(filePath) {
18834
19301
  async function loadPolicy(vaultPath2, policyName) {
18835
19302
  await ensureMigrated(vaultPath2);
18836
19303
  const policiesDir = getPoliciesDir(vaultPath2);
18837
- const policyPath = path28.join(policiesDir, `${policyName}.yaml`);
19304
+ const policyPath = path29.join(policiesDir, `${policyName}.yaml`);
18838
19305
  try {
18839
- await fs24.access(policyPath);
19306
+ await fs25.access(policyPath);
18840
19307
  return loadPolicyFile(policyPath);
18841
19308
  } catch {
18842
- const ymlPath = path28.join(policiesDir, `${policyName}.yml`);
19309
+ const ymlPath = path29.join(policiesDir, `${policyName}.yml`);
18843
19310
  try {
18844
- await fs24.access(ymlPath);
19311
+ await fs25.access(ymlPath);
18845
19312
  return loadPolicyFile(ymlPath);
18846
19313
  } catch {
18847
19314
  return {
@@ -18981,8 +19448,8 @@ init_schema();
18981
19448
  init_writer();
18982
19449
  init_git();
18983
19450
  init_wikilinks();
18984
- import fs26 from "fs/promises";
18985
- import path30 from "path";
19451
+ import fs27 from "fs/promises";
19452
+ import path31 from "path";
18986
19453
  init_constants2();
18987
19454
  async function executeStep(step, vaultPath2, context, conditionResults, searchFn) {
18988
19455
  const { execute, reason } = shouldStepExecute(step.when, conditionResults);
@@ -19173,12 +19640,12 @@ async function executeCreateNote2(params, vaultPath2, context) {
19173
19640
  let frontmatter = params.frontmatter || {};
19174
19641
  if (params.template) {
19175
19642
  try {
19176
- const templatePath = path30.join(vaultPath2, String(params.template));
19177
- const raw = await fs26.readFile(templatePath, "utf-8");
19643
+ const templatePath = path31.join(vaultPath2, String(params.template));
19644
+ const raw = await fs27.readFile(templatePath, "utf-8");
19178
19645
  const matter10 = (await import("gray-matter")).default;
19179
19646
  const parsed = matter10(raw);
19180
19647
  const dateStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
19181
- const title = path30.basename(notePath, ".md");
19648
+ const title = path31.basename(notePath, ".md");
19182
19649
  let templateContent = parsed.content.replace(/\{\{date\}\}/g, dateStr).replace(/\{\{title\}\}/g, title);
19183
19650
  if (content) {
19184
19651
  templateContent = templateContent.trimEnd() + "\n\n" + content;
@@ -19211,9 +19678,9 @@ async function executeToggleTask(params, vaultPath2) {
19211
19678
  const notePath = String(params.path || "");
19212
19679
  const task = String(params.task || "");
19213
19680
  const section = params.section ? String(params.section) : void 0;
19214
- const fullPath = path30.join(vaultPath2, notePath);
19681
+ const fullPath = path31.join(vaultPath2, notePath);
19215
19682
  try {
19216
- await fs26.access(fullPath);
19683
+ await fs27.access(fullPath);
19217
19684
  } catch {
19218
19685
  return { success: false, message: `File not found: ${notePath}`, path: notePath };
19219
19686
  }
@@ -19494,15 +19961,15 @@ async function rollbackChanges(vaultPath2, originalContents, filesModified) {
19494
19961
  const pathCheck = await validatePathSecure(vaultPath2, filePath);
19495
19962
  if (!pathCheck.valid) continue;
19496
19963
  const original = originalContents.get(filePath);
19497
- const fullPath = path30.join(vaultPath2, filePath);
19964
+ const fullPath = path31.join(vaultPath2, filePath);
19498
19965
  if (original === null) {
19499
19966
  try {
19500
- await fs26.unlink(fullPath);
19967
+ await fs27.unlink(fullPath);
19501
19968
  } catch {
19502
19969
  }
19503
19970
  } else if (original !== void 0) {
19504
19971
  try {
19505
- await fs26.writeFile(fullPath, original);
19972
+ await fs27.writeFile(fullPath, original);
19506
19973
  } catch {
19507
19974
  }
19508
19975
  }
@@ -19548,21 +20015,21 @@ async function previewPolicy(policy, vaultPath2, variables) {
19548
20015
  }
19549
20016
 
19550
20017
  // src/core/write/policy/storage.ts
19551
- import fs27 from "fs/promises";
19552
- import path31 from "path";
20018
+ import fs28 from "fs/promises";
20019
+ import path32 from "path";
19553
20020
  async function listPolicies(vaultPath2) {
19554
20021
  await ensureMigrated(vaultPath2);
19555
20022
  const dir = getPoliciesDir(vaultPath2);
19556
20023
  const policies = [];
19557
20024
  try {
19558
- const files = await fs27.readdir(dir);
20025
+ const files = await fs28.readdir(dir);
19559
20026
  for (const file of files) {
19560
20027
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) {
19561
20028
  continue;
19562
20029
  }
19563
- const filePath = path31.join(dir, file);
19564
- const stat4 = await fs27.stat(filePath);
19565
- const content = await fs27.readFile(filePath, "utf-8");
20030
+ const filePath = path32.join(dir, file);
20031
+ const stat4 = await fs28.stat(filePath);
20032
+ const content = await fs28.readFile(filePath, "utf-8");
19566
20033
  const metadata = extractPolicyMetadata(content);
19567
20034
  policies.push({
19568
20035
  name: metadata.name || file.replace(/\.ya?ml$/, ""),
@@ -19586,10 +20053,10 @@ async function writePolicyRaw(vaultPath2, policyName, content, overwrite = false
19586
20053
  const dir = getPoliciesDir(vaultPath2);
19587
20054
  await ensurePoliciesDir(vaultPath2);
19588
20055
  const filename = `${policyName}.yaml`;
19589
- const filePath = path31.join(dir, filename);
20056
+ const filePath = path32.join(dir, filename);
19590
20057
  if (!overwrite) {
19591
20058
  try {
19592
- await fs27.access(filePath);
20059
+ await fs28.access(filePath);
19593
20060
  return {
19594
20061
  success: false,
19595
20062
  path: filename,
@@ -19606,7 +20073,7 @@ async function writePolicyRaw(vaultPath2, policyName, content, overwrite = false
19606
20073
  message: `Invalid policy: ${validation.errors.map((e) => e.message).join("; ")}`
19607
20074
  };
19608
20075
  }
19609
- await fs27.writeFile(filePath, content, "utf-8");
20076
+ await fs28.writeFile(filePath, content, "utf-8");
19610
20077
  return {
19611
20078
  success: true,
19612
20079
  path: filename,
@@ -19693,7 +20160,7 @@ function registerPolicyTools(server2, getVaultPath, getSearchFn) {
19693
20160
  const policies = await listPolicies(vaultPath2);
19694
20161
  const response = {
19695
20162
  success: true,
19696
- vault: path32.basename(vaultPath2),
20163
+ vault: path33.basename(vaultPath2),
19697
20164
  vault_path: vaultPath2,
19698
20165
  count: policies.length,
19699
20166
  policies: policies.map((p) => ({
@@ -20138,9 +20605,9 @@ function registerCorrectTool(server2, getStateDb4, getVaultPath) {
20138
20605
  limit: z15.number().optional().describe("[list] Maximum corrections to return"),
20139
20606
  correction_id: z15.string().optional().describe("[resolve] ID of the correction to mark resolved")
20140
20607
  },
20141
- async ({ action, path: path39, entity, note, limit, correction_id }) => {
20608
+ async ({ action, path: path40, entity, note, limit, correction_id }) => {
20142
20609
  if (action === "record") {
20143
- if (!path39) {
20610
+ if (!path40) {
20144
20611
  return {
20145
20612
  content: [{ type: "text", text: JSON.stringify({ error: "path is required for action: record" }) }],
20146
20613
  isError: true
@@ -20165,7 +20632,7 @@ function registerCorrectTool(server2, getStateDb4, getVaultPath) {
20165
20632
  isError: true
20166
20633
  };
20167
20634
  }
20168
- const correction = recordCorrection(stateDb2, "general", note, "user", entity, path39);
20635
+ const correction = recordCorrection(stateDb2, "general", note, "user", entity, path40);
20169
20636
  return {
20170
20637
  content: [{
20171
20638
  type: "text",
@@ -20182,10 +20649,10 @@ function registerCorrectTool(server2, getStateDb4, getVaultPath) {
20182
20649
  };
20183
20650
  }
20184
20651
  let corrections;
20185
- if (path39) {
20652
+ if (path40) {
20186
20653
  corrections = stateDb2.db.prepare(
20187
20654
  `SELECT * FROM corrections WHERE note_path = ? ORDER BY created_at DESC LIMIT ?`
20188
- ).all(path39, limit ?? 50);
20655
+ ).all(path40, limit ?? 50);
20189
20656
  } else {
20190
20657
  corrections = listCorrections(stateDb2, void 0, void 0, limit ?? 50);
20191
20658
  }
@@ -20299,7 +20766,7 @@ Message: ${undoResult.undoneCommit.message}` : void 0
20299
20766
  // src/tools/write/entity.ts
20300
20767
  init_embeddings();
20301
20768
  import { z as z17 } from "zod";
20302
- import { getEntityIndexFromDb as getEntityIndexFromDb3, getAllEntitiesFromDb as getAllEntitiesFromDb4, getDismissedMergePairs, recordMergeDismissal } from "@velvetmonkey/vault-core";
20769
+ import { getEntityIndexFromDb as getEntityIndexFromDb3, getAllEntitiesFromDb as getAllEntitiesFromDb5, getDismissedMergePairs, recordMergeDismissal } from "@velvetmonkey/vault-core";
20303
20770
 
20304
20771
  // src/core/read/aliasSuggestions.ts
20305
20772
  import { STOPWORDS_EN as STOPWORDS_EN4 } from "@velvetmonkey/vault-core";
@@ -20376,8 +20843,8 @@ init_writer();
20376
20843
  init_git();
20377
20844
  init_wikilinks();
20378
20845
  import { z as z16 } from "zod";
20379
- import fs28 from "fs/promises";
20380
- import path33 from "path";
20846
+ import fs29 from "fs/promises";
20847
+ import path34 from "path";
20381
20848
  import matter8 from "gray-matter";
20382
20849
  function escapeRegex(str) {
20383
20850
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -20396,16 +20863,16 @@ function extractWikilinks2(content) {
20396
20863
  return wikilinks;
20397
20864
  }
20398
20865
  function getTitleFromPath(filePath) {
20399
- return path33.basename(filePath, ".md");
20866
+ return path34.basename(filePath, ".md");
20400
20867
  }
20401
20868
  async function findBacklinks(vaultPath2, targetTitle, targetAliases) {
20402
20869
  const results = [];
20403
20870
  const allTargets = [targetTitle, ...targetAliases].map((t) => t.toLowerCase());
20404
20871
  async function scanDir(dir) {
20405
20872
  const files = [];
20406
- const entries = await fs28.readdir(dir, { withFileTypes: true });
20873
+ const entries = await fs29.readdir(dir, { withFileTypes: true });
20407
20874
  for (const entry of entries) {
20408
- const fullPath = path33.join(dir, entry.name);
20875
+ const fullPath = path34.join(dir, entry.name);
20409
20876
  if (entry.isDirectory() && !entry.name.startsWith(".")) {
20410
20877
  files.push(...await scanDir(fullPath));
20411
20878
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -20416,8 +20883,8 @@ async function findBacklinks(vaultPath2, targetTitle, targetAliases) {
20416
20883
  }
20417
20884
  const allFiles = await scanDir(vaultPath2);
20418
20885
  for (const filePath of allFiles) {
20419
- const relativePath = path33.relative(vaultPath2, filePath);
20420
- const content = await fs28.readFile(filePath, "utf-8");
20886
+ const relativePath = path34.relative(vaultPath2, filePath);
20887
+ const content = await fs29.readFile(filePath, "utf-8");
20421
20888
  const wikilinks = extractWikilinks2(content);
20422
20889
  const matchingLinks = [];
20423
20890
  for (const link of wikilinks) {
@@ -20475,13 +20942,14 @@ function extractAliases2(frontmatter) {
20475
20942
  }
20476
20943
 
20477
20944
  // src/tools/write/entity.ts
20478
- import fs29 from "fs/promises";
20945
+ init_prospects();
20946
+ import fs30 from "fs/promises";
20479
20947
  function registerEntityTool(server2, getVaultPath, getStateDb4, getIndex) {
20480
20948
  server2.tool(
20481
20949
  "entity",
20482
- 'Manage vault entities and aliases. action: list \u2014 browse by category. alias \u2014 register alternate name (aka/nickname). suggest_aliases \u2014 find missing aliases. merge \u2014 absorb one entity into another, rewiring all links (deduplicate). suggest_merges \u2014 find duplicates. dismiss_merge \u2014 mark a suggestion incorrect (not the same entity). Returns list, result, or candidates. Does not create notes. e.g. { action:"list", category:"people" } { action:"alias", entity:"people/alice.md", alias:"Ali" }',
20950
+ "Manage vault entities and aliases. action: list \u2014 browse by category. alias \u2014 add an alternate name. suggest_aliases \u2014 find missing aliases. merge \u2014 absorb one entity into another and rewire links. suggest_merges \u2014 find duplicates. dismiss_merge \u2014 mark a merge suggestion incorrect. dismiss_prospect \u2014 reject an unresolved prospect term so it stops surfacing as an active stub candidate. Returns lists, results, or candidates. Does not create notes.",
20483
20951
  {
20484
- action: z17.enum(["list", "alias", "suggest_aliases", "merge", "suggest_merges", "dismiss_merge"]).describe("Operation to perform"),
20952
+ action: z17.enum(["list", "alias", "suggest_aliases", "merge", "suggest_merges", "dismiss_merge", "dismiss_prospect"]).describe("Operation to perform"),
20485
20953
  query: z17.string().optional().describe("[list] Filter entities by name substring"),
20486
20954
  category: z17.string().optional().describe("[list|suggest_aliases] Filter to a specific category"),
20487
20955
  limit: z17.number().optional().describe("[list|suggest_aliases|suggest_merges] Maximum results to return"),
@@ -20493,9 +20961,11 @@ function registerEntityTool(server2, getVaultPath, getStateDb4, getIndex) {
20493
20961
  target_path: z17.string().optional().describe("[dismiss_merge] Target entity path"),
20494
20962
  source_name: z17.string().optional().describe("[dismiss_merge] Source entity name"),
20495
20963
  target_name: z17.string().optional().describe("[dismiss_merge] Target entity name"),
20496
- reason: z17.string().optional().describe("[dismiss_merge] Reason for the original suggestion")
20964
+ reason: z17.string().optional().describe("[dismiss_merge] Reason for the original suggestion"),
20965
+ prospect: z17.string().optional().describe("[dismiss_prospect] Prospect term or display name to reject"),
20966
+ note_path: z17.string().optional().describe("[dismiss_prospect] Optional note path that motivated the dismissal")
20497
20967
  },
20498
- async ({ action, query, category, limit, entity, alias, primary, secondary, source_path, target_path, source_name, target_name, reason }) => {
20968
+ async ({ action, query, category, limit, entity, alias, primary, secondary, source_path, target_path, source_name, target_name, reason, prospect, note_path }) => {
20499
20969
  const stateDb2 = getStateDb4();
20500
20970
  if (action === "list") {
20501
20971
  if (!stateDb2) {
@@ -20606,6 +21076,7 @@ function registerEntityTool(server2, getVaultPath, getStateDb4, getIndex) {
20606
21076
  }
20607
21077
  fileData.frontmatter.aliases = Array.from(deduped);
20608
21078
  await writeVaultFile(vaultPath2, entity, fileData.content, fileData.frontmatter, fileData.lineEnding, fileData.contentHash);
21079
+ const resolvedProspects = resolveProspectForAlias(entity, alias);
20609
21080
  return {
20610
21081
  content: [{
20611
21082
  type: "text",
@@ -20613,7 +21084,14 @@ function registerEntityTool(server2, getVaultPath, getStateDb4, getIndex) {
20613
21084
  success: true,
20614
21085
  entity,
20615
21086
  alias_added: alias,
20616
- all_aliases: Array.from(deduped)
21087
+ all_aliases: Array.from(deduped),
21088
+ ...resolvedProspects.length > 0 ? {
21089
+ prospect_resolution: {
21090
+ resolved_terms: resolvedProspects,
21091
+ status: "merged",
21092
+ resolved_entity_path: entity
21093
+ }
21094
+ } : {}
20617
21095
  }, null, 2)
20618
21096
  }]
20619
21097
  };
@@ -20698,7 +21176,7 @@ ${trimmedSource}`;
20698
21176
  }
20699
21177
  }
20700
21178
  await writeVaultFile(vaultPath2, primary, targetContent, targetFrontmatter, "LF", targetContentHash);
20701
- await fs29.unlink(`${vaultPath2}/${secondary}`);
21179
+ await fs30.unlink(`${vaultPath2}/${secondary}`);
20702
21180
  initializeEntityIndex(vaultPath2).catch((err) => {
20703
21181
  console.error(`[Flywheel] Entity cache rebuild failed: ${err}`);
20704
21182
  });
@@ -20730,7 +21208,7 @@ ${trimmedSource}`;
20730
21208
  content: [{ type: "text", text: JSON.stringify({ suggestions: [], error: "StateDb not available" }) }]
20731
21209
  };
20732
21210
  }
20733
- const entities = getAllEntitiesFromDb4(stateDb2);
21211
+ const entities = getAllEntitiesFromDb5(stateDb2);
20734
21212
  if (entities.length === 0) {
20735
21213
  return { content: [{ type: "text", text: JSON.stringify({ suggestions: [] }) }] };
20736
21214
  }
@@ -20818,6 +21296,28 @@ ${trimmedSource}`;
20818
21296
  content: [{ type: "text", text: JSON.stringify({ dismissed: true, pair_key: pairKey }) }]
20819
21297
  };
20820
21298
  }
21299
+ if (action === "dismiss_prospect") {
21300
+ if (!prospect) {
21301
+ return {
21302
+ content: [{ type: "text", text: JSON.stringify({ error: "prospect is required for action: dismiss_prospect" }) }],
21303
+ isError: true
21304
+ };
21305
+ }
21306
+ const dismissed = dismissProspect(prospect, reason ?? null, note_path ?? null);
21307
+ return {
21308
+ content: [{
21309
+ type: "text",
21310
+ text: JSON.stringify({
21311
+ dismissed,
21312
+ prospect,
21313
+ status: dismissed ? "rejected" : "not_found",
21314
+ ...reason ? { reason } : {},
21315
+ ...note_path ? { note_path } : {}
21316
+ }, null, 2)
21317
+ }],
21318
+ ...dismissed ? {} : { isError: true }
21319
+ };
21320
+ }
20821
21321
  return {
20822
21322
  content: [{ type: "text", text: JSON.stringify({ error: `Unknown action: ${action}` }) }],
20823
21323
  isError: true
@@ -20934,6 +21434,7 @@ function registerLinkTool(server2, getIndex, getVaultPath, getStateDb4) {
20934
21434
  fix: z18.boolean().optional().describe("[validate] Reserved for future auto-fix support"),
20935
21435
  limit: z18.number().optional().describe("Maximum items to return"),
20936
21436
  min_frequency: z18.coerce.number().optional().describe("[stubs] Minimum reference count to include (default 5)"),
21437
+ status: z18.enum(["prospect", "entity_created", "merged", "rejected", "all"]).optional().describe("[stubs] Prospect lifecycle status filter (default: prospect)"),
20937
21438
  days_back: z18.number().optional().describe("[timeline|layer_timeseries] Days to look back (default 30)"),
20938
21439
  granularity: z18.enum(["day", "week"]).optional().describe("[layer_timeseries] Time bucket granularity (default: day)"),
20939
21440
  timestamp_before: z18.number().optional().describe("[snapshot_diff] Earlier timestamp"),
@@ -20954,6 +21455,7 @@ function registerLinkTool(server2, getIndex, getVaultPath, getStateDb4) {
20954
21455
  group_by_target,
20955
21456
  limit: rawLimit,
20956
21457
  min_frequency,
21458
+ status,
20957
21459
  days_back,
20958
21460
  granularity,
20959
21461
  timestamp_before,
@@ -21043,9 +21545,9 @@ function registerLinkTool(server2, getIndex, getVaultPath, getStateDb4) {
21043
21545
  try {
21044
21546
  for (const prospect of prospects) {
21045
21547
  const row = stateDb2.db.prepare(
21046
- "SELECT note_count, day_count, best_source, best_score, promotion_score, last_seen_at FROM prospect_summary WHERE term = ?"
21548
+ "SELECT note_count, day_count, best_source, best_score, promotion_score, last_seen_at, status, resolved_entity_path FROM prospect_summary WHERE term = ?"
21047
21549
  ).get(prospect.entity.toLowerCase());
21048
- if (row) {
21550
+ if (row && row.status === "prospect") {
21049
21551
  prospect.ledger_source = row.best_source;
21050
21552
  prospect.ledger_note_count = row.note_count;
21051
21553
  prospect.ledger_day_count = row.day_count;
@@ -21053,6 +21555,8 @@ function registerLinkTool(server2, getIndex, getVaultPath, getStateDb4) {
21053
21555
  const effective = Math.round(row.promotion_score * decay * 10) / 10;
21054
21556
  prospect.effective_score = effective;
21055
21557
  prospect.promotion_ready = effective >= PROMOTION_THRESHOLD;
21558
+ prospect.status = row.status;
21559
+ prospect.resolved_entity_path = row.resolved_entity_path;
21056
21560
  }
21057
21561
  }
21058
21562
  } catch {
@@ -21235,24 +21739,48 @@ function registerLinkTool(server2, getIndex, getVaultPath, getStateDb4) {
21235
21739
  if (action === "stubs") {
21236
21740
  const limit = Math.min(rawLimit ?? 20, 100);
21237
21741
  const minFreq = min_frequency ?? 5;
21742
+ const statusFilter = status ?? "prospect";
21238
21743
  requireIndex();
21239
21744
  const index = getIndex();
21240
- const prospectCandidates = getPromotionCandidates(limit * 2);
21745
+ const hasLedgerSummaries = !!stateDb2 && (() => {
21746
+ try {
21747
+ const row = stateDb2.db.prepare("SELECT COUNT(*) as cnt FROM prospect_summary").get();
21748
+ return row.cnt > 0;
21749
+ } catch {
21750
+ return false;
21751
+ }
21752
+ })();
21753
+ const prospectCandidates = getPromotionCandidates(limit * 4, statusFilter);
21241
21754
  if (prospectCandidates.length > 0) {
21242
21755
  const filtered = prospectCandidates.filter((c) => c.backlinkMax >= minFreq).slice(0, limit).map((c) => ({
21243
21756
  term: c.displayName,
21757
+ status: c.status,
21758
+ resolved_entity_path: c.resolvedEntityPath,
21244
21759
  wikilink_references: c.backlinkMax,
21245
21760
  content_mentions: countFTS5Mentions(c.term),
21246
21761
  sample_notes: getProspectSampleNotes(c.term, 3),
21762
+ first_seen_at: c.firstSeenAt,
21763
+ last_seen_at: c.lastSeenAt,
21764
+ note_count: c.noteCount,
21765
+ day_count: c.dayCount,
21247
21766
  effective_score: c.effectiveScore,
21248
21767
  promotion_ready: c.promotionReady
21249
21768
  }));
21250
21769
  return { content: [{ type: "text", text: JSON.stringify({
21770
+ status: statusFilter,
21251
21771
  total_dead_targets: prospectCandidates.length,
21252
21772
  candidates_above_threshold: filtered.length,
21253
21773
  candidates: filtered
21254
21774
  }, null, 2) }] };
21255
21775
  }
21776
+ if (hasLedgerSummaries || statusFilter !== "prospect") {
21777
+ return { content: [{ type: "text", text: JSON.stringify({
21778
+ status: statusFilter,
21779
+ total_dead_targets: 0,
21780
+ candidates_above_threshold: 0,
21781
+ candidates: []
21782
+ }, null, 2) }] };
21783
+ }
21256
21784
  const targetMap = /* @__PURE__ */ new Map();
21257
21785
  for (const note of index.notes.values()) {
21258
21786
  for (const link of note.outlinks) {
@@ -21343,8 +21871,9 @@ init_wikilinks();
21343
21871
  import { z as z19 } from "zod";
21344
21872
  init_git();
21345
21873
  init_wikilinks();
21346
- import fs30 from "fs/promises";
21347
- import path34 from "path";
21874
+ init_prospects();
21875
+ import fs31 from "fs/promises";
21876
+ import path35 from "path";
21348
21877
  import matter9 from "gray-matter";
21349
21878
  function registerNoteTool(server2, getVaultPath, getIndex) {
21350
21879
  server2.tool(
@@ -21456,12 +21985,12 @@ async function handleCreate(params, getVaultPath) {
21456
21985
  if (!validatePath(vaultPath2, notePath)) {
21457
21986
  return formatMcpResult(errorResult(notePath, "Invalid path: path traversal not allowed"));
21458
21987
  }
21459
- const fullPath = path34.join(vaultPath2, notePath);
21988
+ const fullPath = path35.join(vaultPath2, notePath);
21460
21989
  const existsCheck = await ensureFileExists(vaultPath2, notePath);
21461
21990
  if (existsCheck === null && !overwrite) {
21462
21991
  return formatMcpResult(errorResult(notePath, `File already exists: ${notePath}. Use overwrite:true to replace.`));
21463
21992
  }
21464
- await fs30.mkdir(path34.dirname(fullPath), { recursive: true });
21993
+ await fs31.mkdir(path35.dirname(fullPath), { recursive: true });
21465
21994
  let effectiveContent = content;
21466
21995
  let effectiveFrontmatter = rawFrontmatter;
21467
21996
  if (template) {
@@ -21469,13 +21998,13 @@ async function handleCreate(params, getVaultPath) {
21469
21998
  if (!templateValidation.valid) {
21470
21999
  return formatMcpResult(errorResult(notePath, `Invalid template path: ${templateValidation.reason}`));
21471
22000
  }
21472
- const templatePath = path34.join(vaultPath2, template);
22001
+ const templatePath = path35.join(vaultPath2, template);
21473
22002
  try {
21474
- const raw = await fs30.readFile(templatePath, "utf-8");
22003
+ const raw = await fs31.readFile(templatePath, "utf-8");
21475
22004
  const gm = (await import("gray-matter")).default;
21476
22005
  const parsed = gm(raw);
21477
22006
  const dateStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
21478
- const title = path34.basename(notePath, ".md");
22007
+ const title = path35.basename(notePath, ".md");
21479
22008
  let templateContent = parsed.content.replace(/\{\{date\}\}/g, dateStr).replace(/\{\{title\}\}/g, title);
21480
22009
  if (content) {
21481
22010
  templateContent = templateContent.trimEnd() + "\n\n" + content;
@@ -21490,7 +22019,7 @@ async function handleCreate(params, getVaultPath) {
21490
22019
  if (!effectiveFrontmatter.date) effectiveFrontmatter.date = now.toISOString().split("T")[0];
21491
22020
  if (!effectiveFrontmatter.created) effectiveFrontmatter.created = now.toISOString();
21492
22021
  const warnings = [];
21493
- const noteName = path34.basename(notePath, ".md");
22022
+ const noteName = path35.basename(notePath, ".md");
21494
22023
  const existingAliases = Array.isArray(effectiveFrontmatter?.aliases) ? effectiveFrontmatter.aliases.filter((a) => typeof a === "string") : [];
21495
22024
  const preflight = await checkPreflightSimilarity(noteName);
21496
22025
  if (preflight.existingEntity) {
@@ -21558,11 +22087,21 @@ async function handleCreate(params, getVaultPath) {
21558
22087
  );
21559
22088
  }
21560
22089
  await writeVaultFile(vaultPath2, notePath, processedContent, finalFrontmatter);
22090
+ const resolvedProspects = resolveProspectsForCreatedEntity(
22091
+ notePath,
22092
+ noteName,
22093
+ extractAliases2(finalFrontmatter)
22094
+ );
21561
22095
  const gitInfo = await handleGitCommit(vaultPath2, notePath, commit, "[Flywheel:Create]");
21562
22096
  return formatMcpResult(
21563
22097
  successResult(notePath, `Created note: ${notePath}`, gitInfo, {
21564
22098
  preview: previewLines.join("\n"),
21565
- warnings: warnings.length > 0 ? warnings : void 0
22099
+ warnings: warnings.length > 0 ? warnings : void 0,
22100
+ prospect_resolution: resolvedProspects.length > 0 ? {
22101
+ resolved_terms: resolvedProspects,
22102
+ status: "entity_created",
22103
+ resolved_entity_path: notePath
22104
+ } : void 0
21566
22105
  })
21567
22106
  );
21568
22107
  } catch (error) {
@@ -21589,21 +22128,21 @@ async function handleMove(params, getVaultPath) {
21589
22128
  const result2 = { success: false, message: "Invalid destination path: path traversal not allowed", path: newPath };
21590
22129
  return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
21591
22130
  }
21592
- const oldFullPath = path34.join(vaultPath2, oldPath);
21593
- const newFullPath = path34.join(vaultPath2, newPath);
22131
+ const oldFullPath = path35.join(vaultPath2, oldPath);
22132
+ const newFullPath = path35.join(vaultPath2, newPath);
21594
22133
  try {
21595
- await fs30.access(oldFullPath);
22134
+ await fs31.access(oldFullPath);
21596
22135
  } catch {
21597
22136
  const result2 = { success: false, message: `Source file not found: ${oldPath}`, path: oldPath };
21598
22137
  return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
21599
22138
  }
21600
22139
  try {
21601
- await fs30.access(newFullPath);
22140
+ await fs31.access(newFullPath);
21602
22141
  const result2 = { success: false, message: `Destination already exists: ${newPath}`, path: newPath };
21603
22142
  return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
21604
22143
  } catch {
21605
22144
  }
21606
- const sourceContent = await fs30.readFile(oldFullPath, "utf-8");
22145
+ const sourceContent = await fs31.readFile(oldFullPath, "utf-8");
21607
22146
  const parsed = matter9(sourceContent);
21608
22147
  const aliases = extractAliases2(parsed.data);
21609
22148
  const oldTitle = getTitleFromPath(oldPath);
@@ -21642,8 +22181,8 @@ async function handleMove(params, getVaultPath) {
21642
22181
  const result2 = { success: true, message: `[dry run] Would move note: ${oldPath} \u2192 ${newPath}`, path: newPath, preview: previewLines.join("\n"), dryRun: true };
21643
22182
  return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
21644
22183
  }
21645
- await fs30.mkdir(path34.dirname(newFullPath), { recursive: true });
21646
- await fs30.rename(oldFullPath, newFullPath);
22184
+ await fs31.mkdir(path35.dirname(newFullPath), { recursive: true });
22185
+ await fs31.rename(oldFullPath, newFullPath);
21647
22186
  let gitCommit;
21648
22187
  let undoAvailable;
21649
22188
  let staleLockDetected;
@@ -21687,25 +22226,25 @@ async function handleRename(params, getVaultPath) {
21687
22226
  return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
21688
22227
  }
21689
22228
  const sanitizedTitle = newTitle.replace(/[<>:"/\\|?*]/g, "");
21690
- const fullPath = path34.join(vaultPath2, notePath);
21691
- const dir = path34.dirname(notePath);
21692
- const newPath = dir === "." ? `${sanitizedTitle}.md` : path34.join(dir, `${sanitizedTitle}.md`);
21693
- const newFullPath = path34.join(vaultPath2, newPath);
22229
+ const fullPath = path35.join(vaultPath2, notePath);
22230
+ const dir = path35.dirname(notePath);
22231
+ const newPath = dir === "." ? `${sanitizedTitle}.md` : path35.join(dir, `${sanitizedTitle}.md`);
22232
+ const newFullPath = path35.join(vaultPath2, newPath);
21694
22233
  try {
21695
- await fs30.access(fullPath);
22234
+ await fs31.access(fullPath);
21696
22235
  } catch {
21697
22236
  const result2 = { success: false, message: `File not found: ${notePath}`, path: notePath };
21698
22237
  return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
21699
22238
  }
21700
22239
  if (fullPath !== newFullPath) {
21701
22240
  try {
21702
- await fs30.access(newFullPath);
22241
+ await fs31.access(newFullPath);
21703
22242
  const result2 = { success: false, message: `A note with this title already exists: ${newPath}`, path: notePath };
21704
22243
  return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
21705
22244
  } catch {
21706
22245
  }
21707
22246
  }
21708
- const sourceContent = await fs30.readFile(fullPath, "utf-8");
22247
+ const sourceContent = await fs31.readFile(fullPath, "utf-8");
21709
22248
  const parsed = matter9(sourceContent);
21710
22249
  const aliases = extractAliases2(parsed.data);
21711
22250
  const oldTitle = getTitleFromPath(notePath);
@@ -21744,7 +22283,7 @@ async function handleRename(params, getVaultPath) {
21744
22283
  return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
21745
22284
  }
21746
22285
  if (fullPath !== newFullPath) {
21747
- await fs30.rename(fullPath, newFullPath);
22286
+ await fs31.rename(fullPath, newFullPath);
21748
22287
  }
21749
22288
  let gitCommit;
21750
22289
  let undoAvailable;
@@ -21814,8 +22353,8 @@ ${sources}`;
21814
22353
  }
21815
22354
  return formatMcpResult(errorResult(notePath, previewLines.join("\n")));
21816
22355
  }
21817
- const fullPath = path34.join(vaultPath2, notePath);
21818
- await fs30.unlink(fullPath);
22356
+ const fullPath = path35.join(vaultPath2, notePath);
22357
+ await fs31.unlink(fullPath);
21819
22358
  const gitInfo = await handleGitCommit(vaultPath2, notePath, commit, "[Flywheel:Delete]");
21820
22359
  const message = backlinkWarning ? `Deleted note: ${notePath}
21821
22360
 
@@ -21831,8 +22370,8 @@ Warning: ${backlinkWarning}` : `Deleted note: ${notePath}`;
21831
22370
  // src/tools/write/editSection.ts
21832
22371
  init_writer();
21833
22372
  import { z as z21 } from "zod";
21834
- import fs32 from "fs/promises";
21835
- import path36 from "path";
22373
+ import fs33 from "fs/promises";
22374
+ import path37 from "path";
21836
22375
  init_wikilinks();
21837
22376
  init_wikilinkFeedback();
21838
22377
  init_markdown_structure();
@@ -21840,8 +22379,8 @@ init_markdown_structure();
21840
22379
  // src/tools/write/mutations.ts
21841
22380
  init_writer();
21842
22381
  import { z as z20 } from "zod";
21843
- import fs31 from "fs/promises";
21844
- import path35 from "path";
22382
+ import fs32 from "fs/promises";
22383
+ import path36 from "path";
21845
22384
  init_wikilinks();
21846
22385
  init_wikilinkFeedback();
21847
22386
  init_markdown_structure();
@@ -21850,10 +22389,10 @@ async function createNoteFromTemplate(vaultPath2, notePath, config2) {
21850
22389
  if (!validation.valid) {
21851
22390
  throw new Error(`Path blocked: ${validation.reason}`);
21852
22391
  }
21853
- const fullPath = path35.join(vaultPath2, notePath);
21854
- await fs31.mkdir(path35.dirname(fullPath), { recursive: true });
22392
+ const fullPath = path36.join(vaultPath2, notePath);
22393
+ await fs32.mkdir(path36.dirname(fullPath), { recursive: true });
21855
22394
  const templates = config2.templates || {};
21856
- const filename = path35.basename(notePath, ".md").toLowerCase();
22395
+ const filename = path36.basename(notePath, ".md").toLowerCase();
21857
22396
  let templatePath;
21858
22397
  let periodicType;
21859
22398
  const dailyPattern = /^\d{4}-\d{2}-\d{2}/;
@@ -21886,7 +22425,7 @@ async function createNoteFromTemplate(vaultPath2, notePath, config2) {
21886
22425
  ];
21887
22426
  for (const candidate of candidates) {
21888
22427
  try {
21889
- await fs31.access(path35.join(vaultPath2, candidate));
22428
+ await fs32.access(path36.join(vaultPath2, candidate));
21890
22429
  templatePath = candidate;
21891
22430
  console.error(`[Flywheel] Template not in config but found at ${candidate} \u2014 using it`);
21892
22431
  break;
@@ -21897,11 +22436,11 @@ async function createNoteFromTemplate(vaultPath2, notePath, config2) {
21897
22436
  let templateContent;
21898
22437
  if (templatePath) {
21899
22438
  try {
21900
- const absTemplatePath = path35.join(vaultPath2, templatePath);
21901
- templateContent = await fs31.readFile(absTemplatePath, "utf-8");
22439
+ const absTemplatePath = path36.join(vaultPath2, templatePath);
22440
+ templateContent = await fs32.readFile(absTemplatePath, "utf-8");
21902
22441
  } catch {
21903
22442
  console.error(`[Flywheel] Template at ${templatePath} not readable, using minimal fallback`);
21904
- const title = path35.basename(notePath, ".md");
22443
+ const title = path36.basename(notePath, ".md");
21905
22444
  templateContent = `---
21906
22445
  ---
21907
22446
 
@@ -21913,7 +22452,7 @@ async function createNoteFromTemplate(vaultPath2, notePath, config2) {
21913
22452
  if (periodicType) {
21914
22453
  console.error(`[Flywheel] No ${periodicType} template found in config or vault \u2014 using minimal fallback`);
21915
22454
  }
21916
- const title = path35.basename(notePath, ".md");
22455
+ const title = path36.basename(notePath, ".md");
21917
22456
  templateContent = `---
21918
22457
  ---
21919
22458
 
@@ -21922,7 +22461,7 @@ async function createNoteFromTemplate(vaultPath2, notePath, config2) {
21922
22461
  }
21923
22462
  const now = /* @__PURE__ */ new Date();
21924
22463
  const dateStr = now.toISOString().split("T")[0];
21925
- templateContent = templateContent.replace(/\{\{date\}\}/g, dateStr).replace(/\{\{title\}\}/g, path35.basename(notePath, ".md"));
22464
+ templateContent = templateContent.replace(/\{\{date\}\}/g, dateStr).replace(/\{\{title\}\}/g, path36.basename(notePath, ".md"));
21926
22465
  const matter10 = (await import("gray-matter")).default;
21927
22466
  const parsed = matter10(templateContent);
21928
22467
  if (!parsed.data.date) {
@@ -22060,9 +22599,9 @@ async function handleAdd(params, getVaultPath, getConfig2) {
22060
22599
  let noteCreated = false;
22061
22600
  let templateUsed;
22062
22601
  if (create_if_missing && !dry_run) {
22063
- const fullPath = path36.join(vaultPath2, notePath);
22602
+ const fullPath = path37.join(vaultPath2, notePath);
22064
22603
  try {
22065
- await fs32.access(fullPath);
22604
+ await fs33.access(fullPath);
22066
22605
  } catch {
22067
22606
  const config2 = getConfig2();
22068
22607
  const result = await createNoteFromTemplate(vaultPath2, notePath, config2);
@@ -22071,9 +22610,9 @@ async function handleAdd(params, getVaultPath, getConfig2) {
22071
22610
  }
22072
22611
  }
22073
22612
  if (create_if_missing && dry_run) {
22074
- const fullPath = path36.join(vaultPath2, notePath);
22613
+ const fullPath = path37.join(vaultPath2, notePath);
22075
22614
  try {
22076
- await fs32.access(fullPath);
22615
+ await fs33.access(fullPath);
22077
22616
  } catch {
22078
22617
  return {
22079
22618
  content: [{
@@ -22791,7 +23330,7 @@ function registerMemoryTools(server2, getStateDb4) {
22791
23330
  // src/tools/read/semantic.ts
22792
23331
  init_embeddings();
22793
23332
  import { z as z23 } from "zod";
22794
- import { getAllEntitiesFromDb as getAllEntitiesFromDb5 } from "@velvetmonkey/vault-core";
23333
+ import { getAllEntitiesFromDb as getAllEntitiesFromDb6 } from "@velvetmonkey/vault-core";
22795
23334
  function registerSemanticTools(server2, getVaultPath, getStateDb4) {
22796
23335
  server2.registerTool(
22797
23336
  "init_semantic",
@@ -22856,7 +23395,7 @@ function registerSemanticTools(server2, getVaultPath, getStateDb4) {
22856
23395
  const embedded = progress.total - progress.skipped;
22857
23396
  let entityEmbedded = 0;
22858
23397
  try {
22859
- const allEntities = getAllEntitiesFromDb5(stateDb2);
23398
+ const allEntities = getAllEntitiesFromDb6(stateDb2);
22860
23399
  const entityMap = /* @__PURE__ */ new Map();
22861
23400
  for (const e of allEntities) {
22862
23401
  entityMap.set(e.name, {
@@ -22947,14 +23486,8 @@ function registerDiscoveryTools(server2, controller) {
22947
23486
  }
22948
23487
  }
22949
23488
  const matchedCategories = [];
22950
- const newlyActivatedCategories = [];
22951
23489
  for (const { category, tier } of signals) {
22952
- const wasActive = controller.activeCategories.has(category);
22953
23490
  matchedCategories.push(category);
22954
- controller.activateCategory(category, tier);
22955
- if (!wasActive && controller.activeCategories.has(category)) {
22956
- newlyActivatedCategories.push(category);
22957
- }
22958
23491
  }
22959
23492
  const tools = [];
22960
23493
  for (const [name, handle] of controller.getRegisteredTools()) {
@@ -22970,10 +23503,9 @@ function registerDiscoveryTools(server2, controller) {
22970
23503
  }
22971
23504
  const result = {
22972
23505
  matched_categories: matchedCategories,
22973
- newly_activated_categories: newlyActivatedCategories,
22974
23506
  match_method: matchMethod,
22975
23507
  tools,
22976
- hint: tools.length === 0 ? `No tools matched "${query}". Available categories: ${ALL_CATEGORIES.join(", ")}` : `${tools.length} tools available across ${matchedCategories.join(", ")}`
23508
+ hint: tools.length === 0 ? `No tools matched "${query}". Available categories: ${ALL_CATEGORIES.join(", ")}` : `${tools.length} tools match ${matchedCategories.join(", ")}. These tools are already callable; discover_tools does not change visibility.`
22977
23509
  };
22978
23510
  return {
22979
23511
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
@@ -23088,7 +23620,7 @@ function registerVaultResources(server2, getIndex) {
23088
23620
  // src/tool-registry.ts
23089
23621
  var __trFilename = fileURLToPath3(import.meta.url);
23090
23622
  var __trDirname = dirname6(__trFilename);
23091
- var trPkg = JSON.parse(readFileSync5(join17(__trDirname, "../package.json"), "utf-8"));
23623
+ var trPkg = JSON.parse(readFileSync5(join18(__trDirname, "../package.json"), "utf-8"));
23092
23624
  var ACTIVATION_PATTERNS = [
23093
23625
  {
23094
23626
  category: "memory",
@@ -23352,7 +23884,7 @@ function applyToolGating(targetServer, categories, getDb4, registry, getVaultPat
23352
23884
  let totalBytes = 0;
23353
23885
  for (const p of notePaths) {
23354
23886
  try {
23355
- totalBytes += statSync5(path37.join(vp, p)).size;
23887
+ totalBytes += statSync5(path38.join(vp, p)).size;
23356
23888
  } catch {
23357
23889
  }
23358
23890
  }
@@ -23702,7 +24234,7 @@ function registerAllTools(targetServer, ctx, controller, options = {}) {
23702
24234
  // src/index.ts
23703
24235
  var __filename2 = fileURLToPath4(import.meta.url);
23704
24236
  var __dirname = dirname8(__filename2);
23705
- var pkg = JSON.parse(readFileSync6(join19(__dirname, "../package.json"), "utf-8"));
24237
+ var pkg = JSON.parse(readFileSync6(join20(__dirname, "../package.json"), "utf-8"));
23706
24238
  var vaultPath;
23707
24239
  var resolvedVaultPath;
23708
24240
  var vaultIndex;
@@ -23734,26 +24266,8 @@ function getWatcherStatus() {
23734
24266
  var toolConfig = resolveToolConfig();
23735
24267
  var enabledCategories = toolConfig.categories;
23736
24268
  var toolTierMode = toolConfig.enableProgressiveDisclosure ? "tiered" : "off";
23737
- var runtimeToolTierOverride = INITIAL_TIER_OVERRIDE;
23738
- var runtimeActiveCategoryTiers = /* @__PURE__ */ new Map();
23739
- var primaryToolTierController = null;
23740
24269
  function getInstructionActiveCategories() {
23741
- if (toolTierMode !== "tiered") return void 0;
23742
- if (runtimeToolTierOverride === "full") {
23743
- return new Set(enabledCategories);
23744
- }
23745
- return new Set(runtimeActiveCategoryTiers.keys());
23746
- }
23747
- function syncRuntimeTierState(controller) {
23748
- runtimeToolTierOverride = controller.getOverride();
23749
- runtimeActiveCategoryTiers = new Map(controller.getActivatedCategoryTiers());
23750
- }
23751
- function handleTierStateChange(controller) {
23752
- syncRuntimeTierState(controller);
23753
- invalidateHttpPool();
23754
- }
23755
- function getConfigToolTierOverride(config2) {
23756
- return config2.tool_tier_override ?? "auto";
24270
+ return toolConfig.enableProgressiveDisclosure ? new Set(enabledCategories) : void 0;
23757
24271
  }
23758
24272
  function buildRegistryContext() {
23759
24273
  return {
@@ -23798,17 +24312,13 @@ function createConfiguredServer() {
23798
24312
  ctx.getVaultPath,
23799
24313
  buildVaultCallbacks(),
23800
24314
  toolTierMode,
23801
- handleTierStateChange,
24315
+ void 0,
23802
24316
  toolConfig.isFullToolset,
23803
24317
  () => {
23804
24318
  lastMcpRequestAt = Date.now();
23805
24319
  }
23806
24320
  );
23807
24321
  registerAllTools(s, ctx, toolTierController);
23808
- toolTierController.setOverride(runtimeToolTierOverride);
23809
- for (const [category, tier] of runtimeActiveCategoryTiers) {
23810
- toolTierController.activateCategory(category, tier);
23811
- }
23812
24322
  toolTierController.finalizeRegistration();
23813
24323
  return s;
23814
24324
  }
@@ -23855,17 +24365,14 @@ var _gatingResult = applyToolGating(
23855
24365
  _registryCtx.getVaultPath,
23856
24366
  buildVaultCallbacks(),
23857
24367
  toolTierMode,
23858
- handleTierStateChange,
24368
+ void 0,
23859
24369
  toolConfig.isFullToolset,
23860
24370
  () => {
23861
24371
  lastMcpRequestAt = Date.now();
23862
24372
  }
23863
24373
  );
23864
24374
  registerAllTools(server, _registryCtx, _gatingResult);
23865
- _gatingResult.setOverride(runtimeToolTierOverride);
23866
24375
  _gatingResult.finalizeRegistration();
23867
- primaryToolTierController = _gatingResult;
23868
- syncRuntimeTierState(_gatingResult);
23869
24376
  var categoryList = Array.from(enabledCategories).sort().join(", ");
23870
24377
  serverLog("server", `Tool categories: ${categoryList}`);
23871
24378
  serverLog("server", `Registered ${_gatingResult.registered} tools, skipped ${_gatingResult.skipped}`);
@@ -24098,11 +24605,6 @@ function updateVaultIndex(index) {
24098
24605
  function updateFlywheelConfig(config2) {
24099
24606
  flywheelConfig = config2;
24100
24607
  setWikilinkConfig(config2);
24101
- if (toolTierMode === "tiered" && primaryToolTierController) {
24102
- primaryToolTierController.setOverride(getConfigToolTierOverride(config2));
24103
- syncRuntimeTierState(primaryToolTierController);
24104
- invalidateHttpPool();
24105
- }
24106
24608
  const ctx = getActiveVaultContext();
24107
24609
  if (ctx) {
24108
24610
  ctx.flywheelConfig = config2;
@@ -24549,7 +25051,7 @@ async function runPostIndexWork(ctx) {
24549
25051
  serverLog("semantic", "Embeddings up-to-date, skipping build");
24550
25052
  loadEntityEmbeddingsToMemory();
24551
25053
  if (sd) {
24552
- const entities = getAllEntitiesFromDb6(sd);
25054
+ const entities = getAllEntitiesFromDb7(sd);
24553
25055
  if (entities.length > 0) {
24554
25056
  saveInferredCategories(classifyUncategorizedEntities(
24555
25057
  entities.map((entity) => ({
@@ -24586,7 +25088,7 @@ async function runPostIndexWork(ctx) {
24586
25088
  }
24587
25089
  });
24588
25090
  if (sd) {
24589
- const entities = getAllEntitiesFromDb6(sd);
25091
+ const entities = getAllEntitiesFromDb7(sd);
24590
25092
  if (entities.length > 0) {
24591
25093
  const entityMap = new Map(entities.map((e) => [e.name, {
24592
25094
  name: e.name,
@@ -24601,7 +25103,7 @@ async function runPostIndexWork(ctx) {
24601
25103
  activateVault(ctx);
24602
25104
  loadEntityEmbeddingsToMemory();
24603
25105
  if (sd) {
24604
- const entities = getAllEntitiesFromDb6(sd);
25106
+ const entities = getAllEntitiesFromDb7(sd);
24605
25107
  if (entities.length > 0) {
24606
25108
  saveInferredCategories(classifyUncategorizedEntities(
24607
25109
  entities.map((entity) => ({
@@ -24678,8 +25180,8 @@ async function runPostIndexWork(ctx) {
24678
25180
  }
24679
25181
  } catch {
24680
25182
  try {
24681
- const dir = path38.dirname(rawPath);
24682
- const base = path38.basename(rawPath);
25183
+ const dir = path39.dirname(rawPath);
25184
+ const base = path39.basename(rawPath);
24683
25185
  const resolvedDir = realpathSync(dir).replace(/\\/g, "/");
24684
25186
  for (const prefix of vaultPrefixes) {
24685
25187
  if (resolvedDir.startsWith(prefix + "/") || resolvedDir === prefix) {
@@ -24711,7 +25213,7 @@ async function runPostIndexWork(ctx) {
24711
25213
  continue;
24712
25214
  }
24713
25215
  try {
24714
- const content = await fs33.readFile(path38.join(vp, event.path), "utf-8");
25216
+ const content = await fs34.readFile(path39.join(vp, event.path), "utf-8");
24715
25217
  const hash = createHash3("sha256").update(content).digest("hex").slice(0, 16);
24716
25218
  if (lastContentHashes.get(event.path) === hash) {
24717
25219
  serverLog("watcher", `Hash unchanged, skipping: ${event.path}`);