@velvetmonkey/flywheel-memory 2.5.10 → 2.5.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,12 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  var __defProp = Object.defineProperty;
3
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
6
- }) : x)(function(x) {
7
- if (typeof require !== "undefined") return require.apply(this, arguments);
8
- throw Error('Dynamic require of "' + x + '" is not supported');
9
- });
10
4
  var __esm = (fn, res) => function __init() {
11
5
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
12
6
  };
@@ -283,6 +277,8 @@ var init_vault_scope = __esm({
283
277
  import * as crypto from "crypto";
284
278
  import * as fs3 from "fs";
285
279
  import * as path2 from "path";
280
+ import { Worker } from "node:worker_threads";
281
+ import { fileURLToPath } from "node:url";
286
282
  function getModelConfig() {
287
283
  const envModel = process.env.EMBEDDING_MODEL?.trim();
288
284
  if (!envModel) return MODEL_REGISTRY[DEFAULT_MODEL];
@@ -334,92 +330,115 @@ function clearEmbeddingsForRebuild() {
334
330
  function setEmbeddingsDatabase(database) {
335
331
  db = database;
336
332
  }
337
- function clearModelCache(modelId) {
338
- try {
339
- const candidates = [];
340
- try {
341
- const transformersDir = path2.dirname(__require.resolve("@huggingface/transformers/package.json"));
342
- candidates.push(path2.join(transformersDir, ".cache", ...modelId.split("/")));
343
- } catch {
344
- }
345
- const home = process.env.HOME || process.env.USERPROFILE || "";
346
- if (home) {
347
- const npxDir = path2.join(home, ".npm", "_npx");
348
- if (fs3.existsSync(npxDir)) {
349
- for (const hash of fs3.readdirSync(npxDir)) {
350
- const candidate = path2.join(npxDir, hash, "node_modules", "@huggingface", "transformers", ".cache", ...modelId.split("/"));
351
- if (fs3.existsSync(candidate)) candidates.push(candidate);
352
- }
353
- }
354
- }
355
- for (const cacheDir of candidates) {
356
- if (fs3.existsSync(cacheDir)) {
357
- fs3.rmSync(cacheDir, { recursive: true, force: true });
358
- console.error(`[Semantic] Deleted corrupted model cache: ${cacheDir}`);
359
- }
360
- }
361
- } catch (e) {
362
- console.error(`[Semantic] Could not clear model cache: ${e instanceof Error ? e.message : e}`);
363
- }
333
+ function resolveWorkerPath() {
334
+ const thisFile = typeof __filename !== "undefined" ? __filename : fileURLToPath(import.meta.url);
335
+ const thisDir = path2.dirname(thisFile);
336
+ const workerPath = path2.join(thisDir, "embedding-worker.js");
337
+ if (fs3.existsSync(workerPath)) return workerPath;
338
+ const devPath = path2.resolve(thisDir, "..", "..", "..", "dist", "embedding-worker.js");
339
+ if (fs3.existsSync(devPath)) return devPath;
340
+ throw new Error(
341
+ `Embedding worker not found at ${workerPath}. Run 'npm run build' to generate it.`
342
+ );
364
343
  }
365
344
  async function initEmbeddings() {
366
- if (pipeline) return;
367
- if (initPromise) return initPromise;
368
- initPromise = (async () => {
369
- const MAX_RETRIES = 3;
370
- const RETRY_DELAYS = [2e3, 5e3, 1e4];
371
- let cacheCleared = false;
372
- for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
373
- try {
374
- const transformers = await Function("specifier", "return import(specifier)")("@huggingface/transformers");
375
- console.error(`[Semantic] Loading model ${activeModelConfig.id} (~23MB, cached after first download)...`);
376
- pipeline = await transformers.pipeline("feature-extraction", activeModelConfig.id, {
377
- dtype: "fp32"
378
- });
379
- console.error(`[Semantic] Model loaded successfully`);
380
- if (activeModelConfig.dims === 0) {
381
- const probe = await pipeline("test", { pooling: "mean", normalize: true });
382
- activeModelConfig.dims = probe.data.length;
383
- console.error(`[Semantic] Probed model ${activeModelConfig.id}: ${activeModelConfig.dims} dims`);
384
- }
385
- return;
386
- } catch (err) {
387
- if (err instanceof Error && (err.message.includes("Cannot find package") || err.message.includes("MODULE_NOT_FOUND") || err.message.includes("Cannot find module") || err.message.includes("ERR_MODULE_NOT_FOUND"))) {
388
- initPromise = null;
389
- throw new Error(
390
- "Semantic search requires @huggingface/transformers. Install it with: npm install @huggingface/transformers"
391
- );
345
+ if (workerReady && worker) return;
346
+ if (workerInitPromise) return workerInitPromise;
347
+ workerInitPromise = new Promise((resolve3, 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
+ resolve3();
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
+ }
392
388
  }
393
- const errMsg = err instanceof Error ? err.message : String(err);
394
- if (!cacheCleared && (errMsg.includes("Protobuf parsing failed") || errMsg.includes("onnx"))) {
395
- console.error(`[Semantic] Corrupted model cache detected: ${errMsg}`);
396
- clearModelCache(activeModelConfig.id);
397
- cacheCleared = true;
398
- pipeline = null;
399
- continue;
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);
400
396
  }
401
- if (attempt < MAX_RETRIES) {
402
- const delay = RETRY_DELAYS[attempt - 1];
403
- console.error(`[Semantic] Model load failed (attempt ${attempt}/${MAX_RETRIES}): ${errMsg}`);
404
- console.error(`[Semantic] Retrying in ${delay / 1e3}s...`);
405
- await new Promise((resolve2) => setTimeout(resolve2, delay));
406
- pipeline = null;
407
- } else {
408
- console.error(`[Semantic] Model load failed after ${MAX_RETRIES} attempts: ${err instanceof Error ? err.message : err}`);
409
- console.error(`[Semantic] Semantic search disabled. Keyword search (BM25) remains available.`);
410
- initPromise = null;
411
- throw err;
397
+ });
398
+ worker.on("exit", (code) => {
399
+ if (code !== 0 && workerReady) {
400
+ console.error(`[Semantic] Worker exited with code ${code}`);
401
+ handleWorkerCrash();
412
402
  }
413
- }
403
+ });
404
+ worker.postMessage({ type: "init", modelId: activeModelConfig.id });
405
+ } catch (err) {
406
+ workerInitPromise = null;
407
+ reject(err);
414
408
  }
415
- })();
416
- return initPromise;
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;
428
+ }
429
+ workerReady = false;
430
+ workerInitPromise = null;
417
431
  }
418
432
  async function embedText(text) {
419
433
  await initEmbeddings();
420
- const truncated = text.slice(0, 2e3);
421
- const result = await pipeline(truncated, { pooling: "mean", normalize: true });
422
- return new Float32Array(result.data);
434
+ if (!worker) {
435
+ throw new Error("Embedding worker not available");
436
+ }
437
+ const id = ++embedRequestId;
438
+ return new Promise((resolve3, reject) => {
439
+ pendingEmbeds.set(id, { resolve: resolve3, reject });
440
+ worker.postMessage({ type: "embed", id, text });
441
+ });
423
442
  }
424
443
  async function embedTextCached(text) {
425
444
  const existing = embeddingCache.get(text);
@@ -1116,7 +1135,7 @@ function getEntityEmbeddingsCount() {
1116
1135
  return 0;
1117
1136
  }
1118
1137
  }
1119
- var MODEL_REGISTRY, DEFAULT_MODEL, activeModelConfig, MAX_FILE_SIZE2, db, pipeline, initPromise, embeddingsBuilding, embeddingCache, EMBEDDING_CACHE_MAX, entityEmbeddingsMap, inferredCategoriesMap, EMBEDDING_TEXT_VERSION;
1138
+ 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;
1120
1139
  var init_embeddings = __esm({
1121
1140
  "src/core/read/embeddings.ts"() {
1122
1141
  "use strict";
@@ -1133,9 +1152,13 @@ var init_embeddings = __esm({
1133
1152
  activeModelConfig = getModelConfig();
1134
1153
  MAX_FILE_SIZE2 = 5 * 1024 * 1024;
1135
1154
  db = null;
1136
- pipeline = null;
1137
- initPromise = null;
1138
1155
  embeddingsBuilding = false;
1156
+ worker = null;
1157
+ workerReady = false;
1158
+ workerDims = 0;
1159
+ workerInitPromise = null;
1160
+ embedRequestId = 0;
1161
+ pendingEmbeds = /* @__PURE__ */ new Map();
1139
1162
  embeddingCache = /* @__PURE__ */ new Map();
1140
1163
  EMBEDDING_CACHE_MAX = 500;
1141
1164
  entityEmbeddingsMap = /* @__PURE__ */ new Map();
@@ -1255,9 +1278,12 @@ function saveRecencyToStateDb(index, explicitStateDb) {
1255
1278
  }
1256
1279
  console.error(`[Flywheel] saveRecencyToStateDb: Saving ${index.lastMentioned.size} entries...`);
1257
1280
  try {
1258
- for (const [entityNameLower, timestamp] of index.lastMentioned) {
1259
- recordEntityMention(stateDb2, entityNameLower, new Date(timestamp));
1260
- }
1281
+ const runInTransaction = stateDb2.db.transaction(() => {
1282
+ for (const [entityNameLower, timestamp] of index.lastMentioned) {
1283
+ recordEntityMention(stateDb2, entityNameLower, new Date(timestamp));
1284
+ }
1285
+ });
1286
+ runInTransaction();
1261
1287
  const count = stateDb2.db.prepare("SELECT COUNT(*) as cnt FROM recency").get();
1262
1288
  console.error(`[Flywheel] Saved recency: ${index.lastMentioned.size} entries \u2192 ${count.cnt} rows in table`);
1263
1289
  } catch (e) {
@@ -1930,18 +1956,18 @@ function updateSuppressionList(stateDb2, now) {
1930
1956
  `DELETE FROM wikilink_suppressions
1931
1957
  WHERE datetime(updated_at, '+' || ? || ' days') <= datetime('now')`
1932
1958
  ).run(SUPPRESSION_TTL_DAYS);
1933
- for (const stat5 of weightedStats) {
1934
- const effectiveAlpha = getEffectiveAlpha(stat5.entity);
1935
- const posteriorMean = computePosteriorMean(stat5.weightedCorrect, stat5.weightedFp, effectiveAlpha);
1936
- const totalObs = effectiveAlpha + stat5.weightedCorrect + PRIOR_BETA + stat5.weightedFp;
1959
+ for (const stat4 of weightedStats) {
1960
+ const effectiveAlpha = getEffectiveAlpha(stat4.entity);
1961
+ const posteriorMean = computePosteriorMean(stat4.weightedCorrect, stat4.weightedFp, effectiveAlpha);
1962
+ const totalObs = effectiveAlpha + stat4.weightedCorrect + PRIOR_BETA + stat4.weightedFp;
1937
1963
  if (totalObs < SUPPRESSION_MIN_OBSERVATIONS) {
1938
1964
  continue;
1939
1965
  }
1940
1966
  if (posteriorMean < SUPPRESSION_POSTERIOR_THRESHOLD) {
1941
- upsert.run(stat5.entity, 1 - posteriorMean);
1967
+ upsert.run(stat4.entity, 1 - posteriorMean);
1942
1968
  updated++;
1943
1969
  } else {
1944
- remove.run(stat5.entity);
1970
+ remove.run(stat4.entity);
1945
1971
  }
1946
1972
  }
1947
1973
  });
@@ -2011,31 +2037,31 @@ function getAllFeedbackBoosts(stateDb2, folder, now) {
2011
2037
  if (folder !== void 0) {
2012
2038
  folderStatsMap = /* @__PURE__ */ new Map();
2013
2039
  for (const gs of globalStats) {
2014
- const fs35 = getWeightedFolderStats(stateDb2, gs.entity, folder, now);
2015
- if (fs35.rawTotal >= FEEDBACK_BOOST_MIN_SAMPLES) {
2040
+ const fs36 = getWeightedFolderStats(stateDb2, gs.entity, folder, now);
2041
+ if (fs36.rawTotal >= FEEDBACK_BOOST_MIN_SAMPLES) {
2016
2042
  folderStatsMap.set(gs.entity, {
2017
- weightedAccuracy: fs35.weightedAccuracy,
2018
- rawCount: fs35.rawTotal
2043
+ weightedAccuracy: fs36.weightedAccuracy,
2044
+ rawCount: fs36.rawTotal
2019
2045
  });
2020
2046
  }
2021
2047
  }
2022
2048
  }
2023
2049
  const boosts = /* @__PURE__ */ new Map();
2024
- for (const stat5 of globalStats) {
2025
- if (stat5.rawTotal < FEEDBACK_BOOST_MIN_SAMPLES) continue;
2050
+ for (const stat4 of globalStats) {
2051
+ if (stat4.rawTotal < FEEDBACK_BOOST_MIN_SAMPLES) continue;
2026
2052
  let accuracy;
2027
2053
  let sampleCount;
2028
- const fs35 = folderStatsMap?.get(stat5.entity);
2029
- if (fs35 && fs35.rawCount >= FEEDBACK_BOOST_MIN_SAMPLES) {
2030
- accuracy = fs35.weightedAccuracy;
2031
- sampleCount = fs35.rawCount;
2054
+ const fs36 = folderStatsMap?.get(stat4.entity);
2055
+ if (fs36 && fs36.rawCount >= FEEDBACK_BOOST_MIN_SAMPLES) {
2056
+ accuracy = fs36.weightedAccuracy;
2057
+ sampleCount = fs36.rawCount;
2032
2058
  } else {
2033
- accuracy = stat5.weightedAccuracy;
2034
- sampleCount = stat5.rawTotal;
2059
+ accuracy = stat4.weightedAccuracy;
2060
+ sampleCount = stat4.rawTotal;
2035
2061
  }
2036
2062
  const boost = computeBoostFromAccuracy(accuracy, sampleCount);
2037
2063
  if (boost !== 0) {
2038
- boosts.set(stat5.entity, boost);
2064
+ boosts.set(stat4.entity, boost);
2039
2065
  }
2040
2066
  }
2041
2067
  return boosts;
@@ -2043,18 +2069,18 @@ function getAllFeedbackBoosts(stateDb2, folder, now) {
2043
2069
  function getAllSuppressionPenalties(stateDb2, now) {
2044
2070
  const penalties = /* @__PURE__ */ new Map();
2045
2071
  const weightedStats = getWeightedEntityStats(stateDb2, now);
2046
- for (const stat5 of weightedStats) {
2047
- const effectiveAlpha = getEffectiveAlpha(stat5.entity);
2048
- const posteriorMean = computePosteriorMean(stat5.weightedCorrect, stat5.weightedFp, effectiveAlpha);
2049
- const totalObs = effectiveAlpha + stat5.weightedCorrect + PRIOR_BETA + stat5.weightedFp;
2072
+ for (const stat4 of weightedStats) {
2073
+ const effectiveAlpha = getEffectiveAlpha(stat4.entity);
2074
+ const posteriorMean = computePosteriorMean(stat4.weightedCorrect, stat4.weightedFp, effectiveAlpha);
2075
+ const totalObs = effectiveAlpha + stat4.weightedCorrect + PRIOR_BETA + stat4.weightedFp;
2050
2076
  if (totalObs >= SUPPRESSION_MIN_OBSERVATIONS) {
2051
2077
  if (posteriorMean < SUPPRESSION_POSTERIOR_THRESHOLD) {
2052
2078
  const penalty = Math.round(MAX_SUPPRESSION_PENALTY * (1 - posteriorMean / SUPPRESSION_POSTERIOR_THRESHOLD));
2053
2079
  if (penalty < 0) {
2054
- penalties.set(stat5.entity, penalty);
2080
+ penalties.set(stat4.entity, penalty);
2055
2081
  }
2056
2082
  } else if (posteriorMean < SOFT_PENALTY_THRESHOLD) {
2057
- penalties.set(stat5.entity, SOFT_PENALTY);
2083
+ penalties.set(stat4.entity, SOFT_PENALTY);
2058
2084
  }
2059
2085
  }
2060
2086
  }
@@ -2632,8 +2658,8 @@ function clearLastMutationCommit() {
2632
2658
  async function checkGitLock(vaultPath2) {
2633
2659
  const lockPath = path10.join(vaultPath2, ".git/index.lock");
2634
2660
  try {
2635
- const stat5 = await fs6.stat(lockPath);
2636
- const ageMs = Date.now() - stat5.mtimeMs;
2661
+ const stat4 = await fs6.stat(lockPath);
2662
+ const ageMs = Date.now() - stat4.mtimeMs;
2637
2663
  return {
2638
2664
  locked: true,
2639
2665
  stale: ageMs > STALE_LOCK_THRESHOLD_MS,
@@ -2655,8 +2681,8 @@ async function isGitRepo(vaultPath2) {
2655
2681
  async function checkLockFile(vaultPath2) {
2656
2682
  const lockPath = path10.join(vaultPath2, ".git/index.lock");
2657
2683
  try {
2658
- const stat5 = await fs6.stat(lockPath);
2659
- const ageMs = Date.now() - stat5.mtimeMs;
2684
+ const stat4 = await fs6.stat(lockPath);
2685
+ const ageMs = Date.now() - stat4.mtimeMs;
2660
2686
  return { stale: ageMs > STALE_LOCK_THRESHOLD_MS, ageMs };
2661
2687
  } catch {
2662
2688
  return null;
@@ -2670,7 +2696,7 @@ function isLockContentionError(error) {
2670
2696
  return false;
2671
2697
  }
2672
2698
  function sleep(ms) {
2673
- return new Promise((resolve2) => setTimeout(resolve2, ms));
2699
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
2674
2700
  }
2675
2701
  function calculateDelay(attempt, config2) {
2676
2702
  let delay = config2.baseDelayMs * Math.pow(2, attempt);
@@ -4672,8 +4698,8 @@ async function applyProactiveSuggestions(filePath, vaultPath2, suggestions, conf
4672
4698
  }
4673
4699
  const fullPath = path11.join(vaultPath2, filePath);
4674
4700
  try {
4675
- const stat5 = await fs7.stat(fullPath);
4676
- if (Date.now() - stat5.mtimeMs < 3e4) {
4701
+ const stat4 = await fs7.stat(fullPath);
4702
+ if (Date.now() - stat4.mtimeMs < 3e4) {
4677
4703
  return { applied: [], skipped: candidates.map((c) => c.entity) };
4678
4704
  }
4679
4705
  } catch {
@@ -5081,8 +5107,8 @@ var init_tool_embeddings_generated = __esm({
5081
5107
  model: "Xenova/all-MiniLM-L6-v2",
5082
5108
  dims: 384,
5083
5109
  version: 1,
5084
- generatedAt: "2026-04-03T22:38:15.295Z",
5085
- sourceHash: "1fb6c9a93b42b358",
5110
+ generatedAt: "2026-04-06T22:11:22.074Z",
5111
+ sourceHash: "55904c4f8b00ff85",
5086
5112
  tools: [
5087
5113
  { name: "absorb_as_alias", category: "corrections", tier: 2, descriptionHash: "27554e8b6b3bb1a4", embedding: [-0.087313, -0.015109, 0.022541, 8661e-6, -0.024621, -0.027376, -9959e-6, -4143e-6, 0.020362, -0.025815, 0.03722, -0.017272, 0.010364, -0.082973, 0.063234, 0.105669, 0.030314, 0.109193, -0.024833, -0.022116, 0.020565, 0.067968, -0.013485, -4453e-6, 0.023703, -0.012531, -0.110704, 0.046425, 0.037009, -0.100492, 0.057064, 0.106952, -0.064645, 0.032072, 0.011054, 0.113279, 6113e-6, 2155e-6, 0.052647, -0.037832, 0.032187, -6735e-6, -0.027158, -0.033756, -0.071285, -0.025865, -0.040482, 0.02512, -0.037086, 4166e-6, -0.012929, -0.07895, -0.101903, 0.085107, -0.014636, 0.091582, -0.052795, 0.05756, -0.057044, -2231e-6, -0.013445, 2289e-6, -77e-5, -0.049304, -0.013433, -0.01156, 0.039263, 0.055036, -228e-5, -0.021411, 0.025402, -0.015392, -0.016927, -0.01263, 0.016506, 5128e-6, -0.045499, 0.041929, -0.098371, -0.102299, -0.05505, -0.021133, -0.011038, -0.045412, 0.051449, 0.043985, -0.026773, -0.061248, -0.013004, 0.020089, 0.020349, -0.049656, 0.14248, -0.023849, 1326e-6, 0.038924, 0.015142, -0.027207, 0.137747, 0.086333, -0.051942, 0.125201, -0.015227, 0.035816, -0.016593, -3143e-6, 0.016584, 0.057709, 3425e-6, -0.086785, 0.077055, 0.012249, 0.054973, -0.041238, 0.036758, -0.018482, 0.017911, -0.025632, 0.070721, -0.025979, 0.090299, 0.013505, -0.015338, 0.035118, -0.062938, -55e-6, -0.031485, 0, 0.048271, 0.118939, -7432e-6, -0.027482, -0.017351, -2898e-6, -0.036961, -3044e-6, -0.032485, -0.039268, 8085e-6, -0.01109, 0.025195, 273e-6, -0.081679, -0.043759, -1642e-6, 0.133163, 0.054599, 0.052329, -0.014879, 0.066345, -0.063461, 0.046176, -6885e-6, 0.050879, -0.032148, -0.03098, -0.01647, 2323e-6, -0.012937, 0.020916, 0.05669, 0.050599, -0.012922, 0.029857, -0.023119, -0.056459, -0.052397, -0.063056, 0.032488, 0.063419, 5355e-6, -0.081225, -2636e-6, -0.051448, -0.01502, 0.046703, 0.158323, -0.016006, 0.054453, -5225e-6, 0.055346, 3194e-6, -0.055126, -0.047608, -0.027439, -6931e-6, 0.015054, 0.070964, 0.016329, -7436e-6, -0.087056, 0.0326, -8886e-6, 0.069308, 1744e-6, -0.031456, 0.05816, -0.024318, -0.084045, 0.034875, -0.052924, 0.060689, -0.020979, -0.137039, -0.069438, 4228e-6, 0.103073, 0.026546, -0.043743, 0.015869, -1255e-6, -0.020976, -0.036293, 0.019493, 0.019183, -0.167767, -0.047504, -0.043037, -0.05305, -0.011494, 0.020628, -0.029303, 0.066295, -0, 0.06668, 6677e-6, -0.027402, 0.074721, -0.071961, 0.022582, 0.074355, 0.042852, -0.025373, 0.034536, 0.017667, -0.010542, -4169e-6, -0.083182, -2746e-6, -0.053237, 0.041962, -0.041424, -0.037738, 0.075779, 7597e-6, -0.035105, 0.089325, 0.059282, 0.087981, 0.014721, -6421e-6, -0.050171, 0.022545, -0.066806, 0.053691, -0.046373, -0.066624, -0.05594, -2923e-6, -0.072017, -0.035938, -0.031965, -0.078192, -0.01764, 0.047027, 0.05296, -0.039368, 0.060137, -0.014895, 2928e-6, -0.053409, 0.059899, -0.071938, -0.084993, 0.014731, -9255e-6, -0.012538, -0.057773, -0.01937, 0.011484, 0.118908, -4683e-6, -0.101681, -0.030016, 0.04375, 0.078497, -0.024205, -4214e-6, 0.041916, -0.032365, -0.03231, -8687e-6, -0.054573, 9854e-6, 3192e-6, -0.041575, 0.030278, -0.063586, 0.050707, -0.033235, 0.028844, -0.078475, -0.046236, 0.019996, -0.103771, -0.031058, 0.036113, 0.053975, -0.013333, -0.037514, -0.05237, 0.069865, -0.022002, 0.043238, -0.058168, -0.01832, 0.065564, 0.052553, -0.016286, -0, -0.060219, 0.015225, -0.044145, 0.023352, -0.052523, -0.013584, -0.073037, -0.033518, -0.01456, -7575e-6, 2766e-6, -0.030461, -0.045765, -0.042223, -0.032423, -0.03025, 0.020423, 0.066116, -0.085401, -0.038306, -0.12109, 0.040213, 131e-6, -0.04345, 0.070947, 0.014882, 7721e-6, 0.088877, 0.047515, -0.074231, 0.048281, -648e-6, 0.016151, 0.047549, -1148e-6, 0.028044, 0.088863, 0.014517, 0.022091, 0.123896, 0.05443, 0.032042, -0.05105, 0.069732, 0.057286, -0.060648, 108e-5, -0.050034, 0.03852, -0.017144, 0.024196, -0.032345, -0.031836, -0.030237, -0.01748, -1953e-6, 0.045463, 0.059662, 0.020283, -603e-5, 0.145025, -0.031073, 0.069219, 0.012386] },
5088
5114
  { name: "brief", category: "memory", tier: 1, descriptionHash: "cd54c8b5f8962c0c", embedding: [-0.03413, 0.038967, -0.058868, 5065e-6, 0.013581, -9201e-6, 0.12418, 0.084974, 0.0466, -0.027719, -0.03003, 2981e-6, -0.019524, 6126e-6, 0.121445, 0.030564, 0.113974, -0.019305, 0.010584, 0.022772, 0.040912, 0.049654, 0.012009, 0.014554, -317e-6, 0.010126, -0.084735, -1667e-6, 0.083471, -7537e-6, 0.013307, 0.106008, 0.040402, 0.065893, -0.017905, 0.099291, 0.017319, 0.015036, -6372e-6, -0.066617, -0.060547, -0.011005, -0.057781, 0.076661, 9708e-6, -0.045502, -0.044302, -9454e-6, -0.045664, 9896e-6, -0.053175, 0.012171, -0.021067, 0.071767, -8367e-6, 0.128232, -5307e-6, 0.069086, -0.038624, 0.028583, -0.068574, -0.100884, -0.052176, 0.044373, -0.012476, 0.041925, 0.032421, 9466e-6, 0.055237, -0.135804, -0.045271, -0.032277, -0.034088, 0.044972, -0.037657, 0.01615, 0.023087, -0.047546, 5856e-6, -0.118672, -0.013503, 0.027683, 0.021988, 623e-5, -9077e-6, -0.021581, 0.013314, -0.037775, -9507e-6, 0.037748, 85e-5, -0.052845, -7436e-6, 0.03521, 1699e-6, 0.028288, -0.035951, -0.049538, 3357e-6, 0.065678, 0.059998, 0.099599, 0.012784, 0.041595, -0.076292, -0.037029, -0.037229, 0.013993, -0.035633, 4893e-6, -0.057584, 0.047254, -0.010266, -0.037457, 0.077024, -0.074891, -0.038335, -0.034745, 0.026768, 0.120412, 0.06315, -0.034399, -0.048602, -0.025597, -0.086307, -0.035078, 0.03381, 0, 0.074016, -5576e-6, -0.035261, 0.135218, 8885e-6, 0.058899, -0.020769, -0.018972, -0.036681, -0.017513, 0.022473, 0.099641, -0.01237, 0.02122, 0.020966, -0.011241, -0.106938, 0.129492, 0.066344, -0.036365, -0.033113, -6609e-6, -6963e-6, -335e-5, 0.113098, 0.012043, 0.013074, -0.05108, -0.02582, 0.038526, -0.04915, -0.044315, -0.060091, -8148e-6, 0.053718, 0.02143, -5476e-6, -0.021335, -0.010914, -0.106699, -0.040708, 0.013624, 0.031717, -0.058864, -0.091039, -0.10624, -0.040266, 0.024783, 0.036104, 0.013351, 5674e-6, 0.013377, -0.014192, 0.012503, 6394e-6, -0.02841, -4971e-6, -0.022927, -2823e-6, 0.087578, 0.041583, 7853e-6, -0.083155, 0.025704, 0.033491, 0.011361, -0.04942, -0.044508, 0.0311, -0.046498, -0.027239, 3602e-6, 0.040659, 0.050427, -0.025982, 0.014929, 0.015421, 0.031525, -0.062248, 0.03429, 0.052807, -0.044957, -0.023206, 0.055626, -0.038784, 0.022958, 0.043242, -0.128127, -0.054922, 3364e-6, -0.076564, -0.037719, 0.03462, 0.055063, -0.070653, -0, 0.06233, -0.030029, -0.032604, 0.014582, 0.045522, 0.028487, 0.060517, -2969e-6, -0.114903, 0.015776, -0.035656, 5943e-6, 0.029417, 1415e-6, 0.010575, 6686e-6, 0.033255, -0.076697, -0.018056, 0.07942, 0.059409, -0.03671, -0.127963, 0.026159, 0.014287, -0.024613, -0.05576, -0.032465, -0.023479, -0.030419, 9631e-6, -9214e-6, -0.016757, 0.013094, -0.050212, -0.035049, 0.049743, -0.065495, -0.075293, -9875e-6, 0.129848, 0.020889, -0.079259, -0.026347, -0.02803, 2228e-6, -0.065164, 0.043506, -0.033239, -295e-6, -6674e-6, -0.011676, 0.014787, -0.070129, -0.065786, -0.041317, -3707e-6, -0.025125, -0.027828, -0.086907, 0.07926, 7317e-6, -0.053674, -0.034213, 0.054837, -0.062371, 0.036652, 0.070297, -0.090998, 0.015399, 0.052273, -0.051188, 0.039306, -0.066122, 0.040192, 0.02005, -0.022352, -0.17157, -0.039433, -7233e-6, -0.039524, 15e-4, -0.027335, 0.059864, 0.062908, 0.051305, -0.020745, 0.089525, -0.011786, -0.020093, -0.070926, -0.055612, -0.052107, 0.110824, -385e-5, -0, -0.070805, -0.035939, 0.03615, 0.036301, 0.044026, 2509e-6, -5092e-6, 0.068686, 0.037356, 0.02202, 0.025483, -0.032118, -0.107202, -0.04086, 0.048949, 0.038155, -5906e-6, 0.013435, -0.031491, -0.055225, 0.067576, 0.035719, -0.022875, 0.016182, 0.043324, 0.011605, 0.061764, 0.143727, 0.050779, -0.052731, -0.015323, 0.062416, -0.018611, -0.07632, -0.047169, 0.100932, 0.033838, -0.021418, 0.046654, 0.014842, 0.036839, -0.024439, 0.035967, 0.067279, -5978e-6, 0.097739, -0.058634, 0.020037, 1243e-6, -0.081814, -0.06543, 8175e-6, 5117e-6, 0.080321, 57e-6, 0.063212, 0.053892, -0.021493, 0.052762, 0.018396, 0.067694, 0.088151, -0.031927, -0.019349] },
@@ -5107,7 +5133,6 @@ var init_tool_embeddings_generated = __esm({
5107
5133
  { name: "get_note_structure", category: "read", tier: 1, descriptionHash: "d46b747577458fa3", embedding: [-0.034053, 0.058568, -0.013073, 0.051956, 1878e-6, -3484e-6, -0.021384, 0.029459, 0.01866, -0.048506, 4879e-6, -0.02044, 0.02816, -0.035958, 0.080657, 0.031094, 0.034978, 0.025658, 0.023314, -0.026633, 0.088011, 0.055726, 0.045466, -0.019004, -0.045637, 0.051535, -0.119519, -817e-5, 0.051132, -8649e-6, 0.044961, 0.056027, 0.074836, 0.074553, 475e-5, 0.110606, 1981e-6, -0.035258, 0.012263, -0.027338, -0.030202, 0.040594, -0.03311, 0.025563, 0.016389, -7492e-6, -0.057405, -1909e-6, -0.045447, 0.022976, -0.076963, -0.012285, -0.068218, 0.041681, 0.041577, 0.117179, 0.019101, -0.019711, -0.089762, -0.050572, 0.028838, -0.050339, -0.029523, -0.061273, -0.030107, 0.02912, 0.019308, -5468e-6, 0.049428, -0.14302, 0.095878, 9145e-6, 0.020457, 0.041474, 9214e-6, 4388e-6, -4607e-6, -0.014015, -0.047316, -0.11267, -0.098773, 0.044953, 8675e-6, 0.041169, 0.025942, -0.011891, 0.026525, -0.064685, -6678e-6, 0.061513, 0.096213, -0.123228, -0.065633, -0.019303, 8386e-6, 0.072118, 0.01913, -0.061346, 0.102101, 5084e-6, 0.055616, 0.078131, 0.079695, 0.018583, -0.035607, 0.0278, -0.045358, 0.060122, -0.048107, -0.049176, -0.011027, 0.064188, 0.053857, -0.01995, 6125e-6, -0.108854, -7305e-6, -0.03411, 0.045967, 0.111935, 0.112075, 0.01486, -0.022984, 0.015949, -0.102044, -0.012269, -0.075949, 0, 0.054186, 0.018959, 0.0149, 0.017011, -0.049196, 0.023439, 0.023984, 0.05285, -0.06726, -0.020796, -4855e-6, -7865e-6, -0.024857, 0.043349, -0.02489, -1547e-6, -0.045001, 0.06978, 0.019432, 0.03429, 0.011628, 7296e-6, 0.018451, -0.048771, 0.057362, 0.011788, -0.064353, -0.059757, -0.106931, -8745e-6, -0.036667, -0.079833, 0.024444, -0.047112, 0.016105, 0.06526, -0.040127, -4395e-6, -0.046705, -0.106663, 7097e-6, 3845e-6, 0.063465, -0.057979, -0.069587, 773e-6, -0.11854, 0.03829, 0.025318, 0.012997, 0.071065, 0.019042, -653e-5, 0.015978, 0.011882, 0.021631, 0.056059, 0.037697, -0.025745, 0.029873, 0.069977, -1341e-6, -0.017607, 0.032514, -0.040447, 0.023605, -0.032664, -0.0646, 0.069692, 8649e-6, -7163e-6, 0.047986, -7216e-6, 0.023747, -0.016205, -0.082133, -0.048612, -0.094448, 0.069621, -7387e-6, -0.038751, 0.01059, 0.040886, 0.077897, -0.032101, 0.034213, 0.053679, -0.182541, -0.026943, -0.061374, -0.044323, -0.04285, -0.047162, -0.073464, -8375e-6, -0, 0.045809, -0.051449, 0.014081, -0.057152, -0.024508, 0.044098, -0.031783, -2289e-6, -9969e-6, 0.082517, 0.02157, 0.014477, -0.029174, -0.04392, 0.011175, 0.048167, 9909e-6, -0.051525, 0.047285, 0.080488, -0.050922, -0.01143, -0.040418, 0.062125, 0.028396, -8963e-6, -0.051493, -0.048817, 0.027338, -0.066401, 0.017883, -0.053035, -0.053539, -0.036246, -0.057684, -0.034075, -414e-5, -0.073031, -0.040457, 0.086656, 0.068735, 0.107286, 4776e-6, -4959e-6, -0.047611, -0.028712, -0.024964, 0.089701, -0.045587, -0.043428, 0.053476, -0.030139, 3572e-6, -1346e-6, -0.018707, 0.049658, 5663e-6, 1265e-6, -0.078038, -0.049664, -0.022299, 0.065011, -0.11443, 0.034629, 3051e-6, -0.084661, 0.014807, -0.076934, -0.094602, -0.014275, -0.038493, 7669e-6, 0.05943, -0.032143, 0.065115, 0.079638, -0.061122, -0.014708, -0.043751, -0.029774, -0.015585, -0.015531, 0.043522, 0.07072, 0.040783, -0.031524, 9546e-6, 0.02525, -0.023371, -0.010383, -2826e-6, -0.059428, 9702e-6, 0.06052, 0.040492, -0, -0.11971, -0.057381, -0.063901, -0.019077, -5356e-6, -1707e-6, 0.040946, 0.026112, -0.042693, 5638e-6, 0.034895, -0.043335, -0.135079, -0.044002, -0.016958, 2444e-6, 0.091011, 0.011747, -0.040649, -0.039531, -0.015739, 0.053451, -0.049184, -1028e-6, 0.066912, 0.023815, 1227e-6, 0.099626, 0.038918, 0.016415, 0.082349, 0.038295, -0.012661, 5537e-6, 0.054001, 0.03846, 0.067522, -0.012906, -4587e-6, 0.111114, 0.082928, 0.054718, -0.064304, 0.059634, 0.073812, -0.026092, -0.040453, 0.016418, 0.038886, -0.059243, -0.028257, -0.024486, -0.051302, 7722e-6, -0.095123, 0.021788, 0.070279, 0.054412, 0.042015, -0.062366, 0.102527, 0.025488, 0.072279, 0.017399] },
5108
5134
  { name: "get_section_content", category: "read", tier: 1, descriptionHash: "3143db09c864e123", embedding: [-0.028641, 0.085473, -76e-6, 0.05119, 0.031131, 1587e-6, -0.018978, 0.057946, -0.01217, -0.034409, -567e-6, 8665e-6, 0.021315, -0.022961, 0.091059, -0.030405, 0.046316, 0.042966, 0.021119, -1504e-6, 0.053647, 0.101898, 8477e-6, 0.03071, -0.054229, 0.035659, -0.15261, 0.053486, -4781e-6, -0.043234, 0.043718, -0.012788, 0.018779, 0.011845, 8181e-6, 0.036182, 0.0978, -0.036718, 0.072551, 0.017413, -0.027154, 0.029073, -0.060769, 0.023862, 0.027807, -0.022091, -0.063303, -5347e-6, 7137e-6, -0.021798, -0.034714, -0.023498, -0.02925, 0.092221, 0.010238, 0.109993, 534e-6, -0.025775, -0.050855, 6795e-6, -0.064772, -0.069964, -4102e-6, -0.073128, -0.035828, 0.016207, -0.03324, 0.016634, -0.045777, -0.027336, 0.027186, -0.025611, 0.038306, 0.052737, 9481e-6, -0.025895, -0.050778, -0.043424, -0.049807, -0.119121, -0.084864, 0.066539, -0.016666, 0.049291, -0.018263, 5135e-6, -2983e-6, -0.012152, -0.070296, 0.027834, 0.053321, -0.082358, -0.014167, 0.030441, -0.064228, 0.044649, -144e-5, -0.109388, 0.060139, 0.015573, -8612e-6, 0.030612, 0.060786, -0.01802, -0.067729, -0.013319, -8888e-6, 0.028932, -0.045929, -0.042227, 0.010539, 0.033105, -0.015885, -4513e-6, 116e-6, -0.066676, 0.048411, -0.029626, 0.032187, 0.082548, 0.114786, -0.01838, -8558e-6, 0.065853, -0.074634, -0.039559, 0.031106, 0, 6209e-6, -8677e-6, 3492e-6, 0.05194, -0.032895, 0.03922, -0.031535, -898e-5, -0.025381, -0.014504, 0.013425, -0.047406, -7584e-6, 0.06063, -0.029333, -0.011628, 5507e-6, 0.057618, -0.025885, 0.023597, -0.031007, 2971e-6, 0.012595, -0.060759, 0.050706, 0.052725, -0.065455, 734e-6, -0.113944, -0.011068, -908e-5, -0.03675, 0.037886, -0.118776, 254e-5, 0.051742, 3988e-6, -2943e-6, -0.073215, -0.046089, -0.014969, -6248e-6, 0.06288, -0.03653, -0.076457, 0.040562, -0.053199, 0.046905, -665e-6, -0.03219, 0.052905, 0.018131, 0.047858, -0.034036, 0.052139, -0.031547, 3647e-6, 0.053643, -4297e-6, 7731e-6, 0.124256, 0.012433, -0.04248, 0.029914, -0.059878, 0.025681, -1956e-6, -0.046563, 167e-6, -2874e-6, -0.067715, 0.032702, -0.010757, 0.048113, 729e-6, -0.046407, -0.069157, -0.070698, 0.116455, -0.038527, -454e-5, 0.038641, 0.064124, 8841e-6, 8073e-6, 0.029897, 0.065531, -0.099762, -0.027115, -0.081608, -0.128888, -0.097702, 0.03308, -0.087019, 0.013349, -0, 0.072201, -0.014661, -0.048643, -0.060926, -0.077314, 0.059431, 0.011764, 0.035201, 0.016747, 0.085562, 0.018052, 9969e-6, -0.039091, -0.012121, 0.065632, -906e-5, -0.072452, -0.069153, 0.059193, 0.019054, -0.085421, -0.077256, -0.018214, 0.012881, 0.020715, 7903e-6, -0.055617, -0.029759, 0.015393, -0.088237, -8017e-6, -0.045987, -1644e-6, -8979e-6, -0.075813, -0.031571, -0.061005, -0.027525, -339e-5, 0.060508, 0.110903, 0.101027, 0.077668, -0.034899, -0.072861, 0.028758, 0.028136, 0.095881, -0.049, 0.016251, -0.045377, -0.04172, -4138e-6, 0.031363, -0.016481, 0.051365, -0.02863, 0.038089, -0.095247, -0.068709, -0.017717, 0.067932, -0.094599, 0.061901, 0.042007, -0.020073, 0.031228, -0.09808, -0.041746, -821e-6, -0.024428, -0.04163, 0.071431, -0.059914, 0.06119, 0.112077, -0.08753, 0.020743, -0.103866, 0.039082, -4396e-6, -0.02896, -0.056667, 0.066637, 0.090426, -0.014902, -0.050542, -0.016232, 0.015545, -0.017757, 7608e-6, -0.03554, 0.078521, 0.078539, -0.030191, -0, -0.017856, -0.069979, -0.012196, -0.062197, -0.054607, 0.061452, -0.028817, -0.059814, -0.033044, 0.023097, 5961e-6, -0.069378, -0.095493, -0.084676, -0.036096, 0.047724, 0.036811, 0.060726, -0.012988, -0.051958, -0.059858, 0.063799, -0.010038, -838e-5, 0.046756, 0.077427, -2525e-6, 0.093047, 0.057901, -0.037286, 0.114778, 0.032906, 0.026368, 0.016743, 0.085209, 0.042384, 0.038353, 0.051377, 0.079111, 0.114371, 0.081498, -557e-5, -0.036095, 0.027621, 0.078159, 2603e-6, -0.046535, 0.032286, 0.069105, -0.031222, -0.071619, -0.015424, -0.045878, 0.032742, -0.087811, 0.022644, 0.071666, 0.020854, -0.028094, -0.044219, 0.070801, 0.031554, 0.06052, 0.063509] },
5109
5135
  { name: "get_strong_connections", category: "graph", tier: 2, descriptionHash: "6e2af7b6029af542", embedding: [-0.037771, -0.027994, -0.068021, 0.023556, -0.090681, -0.051207, -0.041261, 0.017216, -0.06359, -0.055238, 806e-5, 0.02676, 8123e-6, 1787e-6, 6061e-6, 0.135593, 0.059854, 0.028837, -0.030354, -0.060799, 0.0423, -0.063322, -0.018217, -4433e-6, 0.047159, -0.055318, -0.083385, 0.060145, 0.073422, -0.064649, 356e-6, 5751e-6, -0.139108, 7324e-6, -0.042962, 0.037446, 0.053805, -0.037605, 372e-5, 0.011429, 0.026703, 0.020876, 0.03223, -0.03014, -0.040705, 0.016356, -0.101406, 0.074424, -0.047714, -0.037129, -0.088537, 0.012154, -0.057325, 0.045473, 0.084099, 0.054132, -5249e-6, -5968e-6, -0.055892, 0.068053, 0.054631, -0.04568, -0.069245, -0.020054, -0.04224, 5718e-6, -2155e-6, 0.114993, 7884e-6, 0.018219, 0.031962, -0.072873, -0.097566, 0.019057, 0.063863, 0.052558, 0.011555, -1668e-6, -0.067272, -0.120076, -0.06419, 0.01966, -0.028191, 0.045533, 0.068489, 814e-6, -0.012517, -0.081064, 0.038081, 0.052053, 0.036193, 0.040413, -0.052446, 0.026766, 0.028761, 0.060208, -0.025242, -0.087489, -0.04182, 0.056964, -0.017134, 0.016552, 5959e-6, -0.045877, 0.043168, 0.072253, -0.031332, 0.029309, 0.046305, -7642e-6, -0.022719, 0.034447, 0.022557, 3578e-6, -0.041477, -0.024104, -0.015113, 0.027006, 0.080433, 0.090614, 0.04795, 0.015571, -5917e-6, -0.030432, -0.036741, -0.040443, -4554e-6, 0, 0.059822, 0.0145, 0.051421, 0.015885, -0.022594, 0.037805, -0.078622, 0.014572, -0.061651, 4526e-6, -0.13038, 0.075147, -0.014407, 0.027354, 0.071657, -0.043857, 0.050021, 0.026305, 0.031753, -0.01056, 0.021751, -0.040921, -7686e-6, -0.02379, 0.114929, -0.034895, -9839e-6, 0.010689, -0.035789, 0.031663, -9746e-6, -0.039082, 0.017535, -0.013062, -0.015549, 0.02697, -0.067409, -0.018802, -0.025118, -0.024353, -0.022472, -0.04769, -0.022257, -0.021798, -0.036261, 0.023876, -0.072232, 0.017299, -0.036421, 9764e-6, -0.019015, -0.018019, 0.028643, 0.059689, 0.011619, -0.061575, -0.011098, 0.135227, 0.01339, 0.095882, 0.028497, -0.015913, -0.021305, 0.012422, 0.033127, 0.02329, -0.098138, -0.039889, 0.061132, 0.025942, -0.053474, 0.080174, 0.010111, -0.012041, -0.034366, -0.098504, -0.092239, -0.066017, 0.091857, 0.02822, -0.139999, 2266e-6, -2271e-6, 0.055157, -0.04945, 0.013613, 0.046267, -0.121393, -0.048062, -4372e-6, -0.082383, 3035e-6, 0.034201, -0.018272, 0.038456, -0, -2843e-6, 0.069342, 0.103103, 0.010287, 0.029563, -0.022873, 0.027775, -0.043618, 0.010446, 0.138289, 0.03564, 0.031568, 0.039643, -0.057704, 0.14409, -0.071936, -0.010229, -0.07411, 0.01354, 0.058899, -4457e-6, 0.05122, -0.064179, -1085e-6, 0.077797, -0.021331, 8365e-6, -0.110735, -0.012208, -2982e-6, 554e-6, 5155e-6, -0.081401, 7275e-6, -0.044218, 0.097863, -0.014108, 8492e-6, 0.040481, -0.026258, 0.065645, 0.06016, -0.0312, -0.026998, -0.014959, 0.047424, -0.05033, -0.019567, -0.101543, -0.033671, 0.016911, 0.041148, 0.018528, 0.058475, 0.011338, -1783e-6, -6998e-6, 0.051356, -0.057736, -0.025262, -0.010656, -0.061711, -0.043316, 0.076918, 0.016766, -0.030118, -1567e-6, -0.063203, -0.012617, 0.019781, 7747e-6, 0.083593, 0.064443, -259e-6, 0.030238, 0.019059, -0.058083, 9456e-6, -0.061151, 0.029125, -0.071687, 0.053585, 0.056561, 5823e-6, 0.023318, -0.020783, 0.025751, 0.035499, 0.068327, 0.019582, -0.015069, -0.02526, -0.041987, 3336e-6, -0.050373, -0, -0.076057, -0.060965, 8849e-6, -2043e-6, 0.015217, 0.080132, 0.037776, 0.092546, -0.037172, 0.115836, 0.026506, 6788e-6, -0.073694, 0.019286, -974e-5, -9829e-6, 0.046523, -0.018646, -0.041308, -0.059466, -0.096567, 192e-6, 0.025832, 0.129585, -0.01088, -0.06024, -0.019829, 0.028988, -0.011028, 0.017712, 0.022421, -0.043442, 0.01067, 0.013991, -0.031013, 0.152245, -0.121124, 0.078891, -0.028629, 0.117615, 0.026723, 0.03564, 0.032972, 0.05445, 0.111144, 0.037447, 0.02066, 0.018956, -8914e-6, -0.070642, -0.052423, -0.041498, -0.044652, -0.101854, -0.057583, -0.01058, -0.01979, -0.013734, -0.021211, -6494e-6, 2554e-6, 0.021907, 304e-5, -2321e-6] },
5110
- { name: "get_weighted_links", category: "graph", tier: 2, descriptionHash: "b15908c4739b5d3a", embedding: [-0.090975, -0.014501, -0.021864, 0.065818, -0.030286, -0.047781, -0.026542, 0.021761, -0.038294, -0.032738, -0.015163, -0.012753, 0.031894, 0.01047, 0.029989, 0.120474, 0.098771, 0.067441, -0.040694, -0.062644, 0.035177, -0.050144, -0.034699, -1753e-6, 0.070949, -0.10291, -0.13736, 0.074743, 0.089653, -0.05479, 0.020764, 0.020775, -0.10811, -0.010933, -0.097484, 0.018926, 0.046231, -0.062474, 0.022908, -0.021497, 3353e-6, 6996e-6, -1637e-6, -0.020593, -0.031638, 1062e-6, -0.07396, 0.049341, -0.096428, 0.032815, -0.058664, 0.01456, -0.032546, 0.070596, 0.048763, 0.05182, 0.023216, -0.039782, -0.049001, 0.037621, 0.029424, -0.047569, -0.074779, 0.011681, -0.012067, 3717e-6, -0.030751, 0.089352, 298e-6, -0.018922, 0.056772, -0.092662, -0.063705, 0.022077, 0.065903, 0.02897, -0.024127, -0.055941, -0.030059, -0.065825, -0.072135, 0.032097, -0.023324, 0.015092, 0.061272, -7666e-6, 0.012571, -0.051188, -0.010824, 0.079681, 0.013229, 0.065022, -0.012118, 0.063461, 0.017044, 0.059285, -0.04809, -0.079425, -0.016637, 0.076686, -5778e-6, 0.035252, 9646e-6, -0.021157, 0.022145, 6747e-6, 879e-6, 0.113067, 0.037145, -1402e-6, -0.036647, 0.037682, 0.04401, -6466e-6, -0.03851, -0.012131, 0.029901, 0.024441, 0.068556, 0.054587, 0.075806, 7062e-6, -0.016095, -0.076931, -0.022381, -0.035324, -0.02266, 0, 0.100173, -0.015921, 0.029145, -0.022108, -0.011857, 0.042613, -0.070996, -0.032842, -0.072239, -0.05262, -0.10894, 0.133753, 0.013103, 0.038695, 0.044727, -0.033728, 0.038247, 0.068295, 0.07883, -0.052155, 0.044765, -0.014218, 215e-6, 0.028915, 0.082827, -531e-6, -9761e-6, -0.019842, -0.06516, 0.047081, 4414e-6, -0.070453, -1103e-6, -0.052589, -0.018823, 0.012986, -0.037209, -0.010124, -0.011257, -0.071029, -0.016809, -0.037493, 331e-5, -0.014289, -0.078064, 7253e-6, -0.053571, 0.019083, -0.040748, 0.015793, 0.015338, -0.046805, 0.029152, 0.030541, -9975e-6, -0.024135, -0.011031, 0.086744, 0.013653, 0.032038, 0.037415, -0.013344, -0.040472, -3412e-6, -0.012778, 0.010936, -0.054764, -0.062977, 0.022929, 9276e-6, -2083e-6, 0.092949, 0.020496, 0.021255, -0.02846, -0.078688, -0.102784, -0.090458, 0.071563, 0.039953, -0.09925, -0.02562, 9363e-6, 0.026493, -0.04102, 0.024758, 0.024951, -0.134036, -0.039121, 8251e-6, -0.067827, -0.043155, -0.021372, -0.020859, 0.015264, -0, -0.029416, 0.080464, 0.060345, 0.010391, 0.02143, -6675e-6, 0.010375, -0.068239, -0.016398, 0.122661, 0.0456, 4852e-6, -0.02345, -0.025092, 0.133585, -0.079084, -0.025699, -0.044697, -0.05656, 0.03485, 0.040477, 0.051672, -0.082537, 0.09383, 0.095729, -0.021573, 0.015405, -0.051452, 81e-6, -0.022034, 4398e-6, -0.010902, -0.051642, 1343e-6, -0.02102, 0.073711, 0.024084, -0.039672, -0.012054, 3372e-6, 0.048955, 0.019228, -0.032866, -0.014474, -6002e-6, 0.021877, -0.070833, 6029e-6, -0.087879, -0.056169, 0.020016, 0.017023, 0.029297, 0.061129, -0.017747, -8161e-6, 0.017038, 0.056091, -0.092429, -0.026094, 0.016189, -0.020079, -0.0584, 0.066234, -1429e-6, -0.038221, 0.030045, -0.06633, -0.054358, 0.064258, 79e-6, 0.03817, 0.099264, -0.040309, 0.058427, -454e-6, -0.044228, 0.052338, -0.081565, -0.017557, -0.074933, 2475e-6, 0.127554, 7727e-6, 0.053678, -0.045102, 2107e-6, 0.037336, 0.040023, 4466e-6, -0.019027, -0.047474, -0.077896, 0.022258, -0.032852, -0, -0.07619, -0.01597, 0.030851, 0.057193, -0.021068, 0.108372, 0.055887, 0.076764, -0.017763, 0.10255, 0.034333, -0.039576, -0.061609, -0.02854, 0.014108, 0.016585, 0.030504, -4742e-6, -0.036712, -0.090062, -0.096437, -0.017134, 0.021224, 0.094701, 8389e-6, -0.012675, -0.020066, 0.035665, 0.050386, 0.028501, 0.038512, 238e-5, 295e-6, -0.039607, -0.024497, 0.142554, -0.075649, 0.028408, -0.039409, 0.119073, 0.046154, 0.060929, 0.039705, 0.05497, 0.116029, 0.047151, -0.059783, 0.068407, 0.039543, -0.086565, -0.01137, -0.08773, -0.061231, -0.037986, -0.052677, 0.015221, 0.022846, -7088e-6, 6404e-6, 0.010344, 0.112113, -0.020958, -6841e-6, 0.020835] },
5111
5136
  { name: "graph_analysis", category: "graph", tier: 2, descriptionHash: "21da4313470c8acf", embedding: [0.014982, 0.048667, -0.05496, 0.012859, -7511e-6, -0.080556, -0.080775, 0.010218, -6301e-6, 0.017034, 0.013734, -7477e-6, 0.060422, 0.076067, 1336e-6, 0.08975, -0.041889, 0.014917, 0.079108, -0.074126, 5897e-6, -0.056713, -0.010258, -0.042079, 0.062049, 8864e-6, -0.111993, 0.040664, 0.054887, -0.027314, -8775e-6, 0.049098, 0.016304, 0.015778, 2669e-6, 0.087052, 0.05313, 0.015003, 0.026028, -6206e-6, -0.033553, 0.01072, 0.017311, 0.035093, 0.012491, -0.034683, -0.153859, -2641e-6, -0.065432, 0.010869, -0.072863, 0.042287, -0.036151, 0.035371, 0.062681, 0.078202, 7565e-6, -0.027103, 8832e-6, -0.015145, 0.129478, -96e-5, -0.084373, 0.018726, 0.030673, 0.08512, 0.05594, 0.068198, 0.03111, 0.02847, 0.01319, -0.068583, -0.042534, 0.046815, 0.062125, 0.099523, -0.025556, 0.033946, -0.021172, -0.149886, -0.024221, -4303e-6, 2622e-6, 0.022859, -0.022048, 0.025957, -0.055911, -0.076048, 0.014287, 0.066012, 0.010988, 0.058647, -0.010238, -7619e-6, 0.046626, -6447e-6, -8203e-6, -0.041375, 3573e-6, 0.050071, 0.012537, -0.024124, 0.031998, -0.029242, -759e-5, 0.034055, -3655e-6, 0.019935, -0.020079, 3175e-6, -7819e-6, 0.024804, 0.023123, 8955e-6, 0.03206, -0.039055, -0.0511, -0.024222, 0.058775, 0.084928, 0.054938, -8055e-6, 0.067706, -0.057881, -0.017355, -0.017372, -0.071099, 0, 0.039272, -3494e-6, -0.049648, -0.017106, 0.026142, -7155e-6, -0.124206, -0.022045, -0.034048, 0.042819, -0.047638, 0.098044, -0.014169, 0.016236, 0.093998, 0.029911, 0.079728, 0.053739, -0.017549, -0.064304, 0.03097, -0.036439, 0.033522, 0.035343, 0.134186, 0.017999, 0.01137, -0.044759, -0.058738, 0.024135, -0.037312, 0.019298, 0.013909, 6484e-6, 0.038982, -0.014468, -6381e-6, -0.021227, -0.053476, -0.071868, -0.010886, -0.058535, 0.014366, -0.038675, -0.033031, 4711e-6, -0.013062, -0.031503, 0.01143, 0.02046, -0.024102, -6962e-6, -0.036209, 0.079632, -0.042118, -1449e-6, 0.013005, -1418e-6, 0.017152, 0.065533, 0.020589, -0.013602, -1018e-6, -0.029669, -0.035822, -0.026891, -0.12942, -0.02858, 0.076096, 0.044514, -0.054821, 0.082988, -6901e-6, 0.049194, -0.057347, -0.099937, -0.089271, -0.013113, -0.025257, -6699e-6, -0.083914, -0.079291, 0.014989, -0.010643, -1926e-6, -0.02845, 0.051667, -0.068924, -0.042244, -0.067379, -0.078613, -0.020605, -0.01071, 0.020394, 0.02361, -0, 5196e-6, 0.059459, 0.066098, 0.016319, 0.029665, -0.038921, 0.019445, -0.108754, 9862e-6, 0.099327, 0.011067, 0.019257, 7469e-6, -0.026524, 0.067341, -0.024194, -0.047803, -0.138884, -0.035914, 0.064449, 0.020511, -0.012535, -0.074021, 0.012927, 0.078131, 0.01318, -0.021434, -0.092091, 0.039101, 9615e-6, -0.034145, 0.013148, 0.011523, -0.010175, 0.019436, 0.023398, 0.101393, -0.080156, -0.03636, -0.066278, 0.05756, 0.068323, -0.095833, -0.029751, 0.031757, 0.075222, 66e-6, 0.073814, -0.151532, -0.067838, 0.023268, 0.060245, 0.072305, -0.038108, -0.024749, -9942e-6, 0.04971, 0.073733, -0.072968, 0.032388, 0.028846, -0.057119, -0.032219, 6511e-6, 1294e-6, -0.080719, 474e-5, -0.045133, -0.157085, 0.069242, 0.064041, 0.026467, -0.022417, -0.032153, 0.04462, -0.040503, -0.041883, -4582e-6, -5381e-6, -0.014891, -0.042522, -7419e-6, 0.060908, 0.053358, 0.013997, -697e-5, -8638e-6, 0.039554, 8026e-6, 0.027568, -0.042951, -0.046245, -0.118002, 0.030924, 0.032844, -0, -0.073586, -0.03406, -0.02731, -0.040197, 0.035654, -43e-4, 0.068621, 0.104104, -0.019369, 0.063457, 0.068685, -0.018536, -0.142823, -6219e-6, -0.040994, -0.039883, -504e-6, -0.011205, -0.037401, 0.014862, -0.0493, -1524e-6, -0.024527, 0.053348, 0.020769, -0.076086, -0.048086, 0.035365, 0.017626, -0.012496, 0.031508, 0.0174, 0.080662, -0.032491, -0.019471, 0.142096, 0.052662, 0.066275, -7575e-6, 0.089928, -0.020622, 0.022103, -0.021359, 5322e-6, 0.037768, 0.031636, -9026e-6, 0.091438, 0.049468, -0.069661, -0.018383, -0.064816, -0.094888, -0.050419, 0.015122, 0.029533, 0.01494, -0.021185, 0.085005, 0.033213, 0.107679, -0.02922, -1768e-6, -0.116227] },
5112
5137
  { name: "init_semantic", category: "search", tier: 1, descriptionHash: "43c65824a56583c8", embedding: [-0.036645, -0.048423, -0.02987, 0.017334, 918e-6, 0.017996, -0.055598, -0.046157, -0.060235, -0.03943, 0.0203, -0.068196, 0.06205, 4746e-6, 0.021267, 0.1163, 0.082818, 7109e-6, 7912e-6, -0.031837, 0.039406, 0.039051, 0.041681, -0.024567, -0.030271, -4424e-6, -0.073251, -0.01792, 0.06297, -0.021106, 0.068028, 0.119778, -8886e-6, 0.124277, -0.015507, 0.047549, -0.043916, -0.03781, 798e-6, -0.068685, -0.042466, 0.022345, -0.045979, 0.02311, 0.025188, 0.011397, -0.107553, -0.055501, -0.024378, 0.018865, -0.112677, -2974e-6, -0.063417, 0.01448, 0.06073, 0.052563, -0.029852, 0.026697, -0.026249, -0.095955, 0.011018, -0.064869, 0.03559, -0.013392, -0.025816, -6166e-6, 0.03396, -3985e-6, 0.074746, -0.051948, 0.04735, 5699e-6, -0.047815, 5083e-6, -6656e-6, 0.058819, 0.017751, 9618e-6, -0.034329, -0.142559, -0.092611, -0.011707, 0.054788, 0.026713, 0.046238, -0.058496, 0.053149, -0.064674, -7911e-6, 0.025146, 0.090716, -0.095411, -0.025432, -4719e-6, 0.044307, -9021e-6, 0.03782, 5209e-6, 0.090933, 0.010226, -0.031091, 0.059074, 0.050608, 0.02373, -0.066836, -6565e-6, -0.019631, -0.010734, 0.051661, -0.114177, -143e-5, 0.012429, 0.075123, -0.028144, 146e-5, -0.024961, 0.018168, -0.07083, 0.118612, 0.069403, 0.025245, 0.058002, -0.02929, -0.028592, -0.108462, 0.041775, -0.053198, 0, 0.081256, -6094e-6, -7254e-6, 0.056054, -0.015568, 0.037045, 0.028584, 0.106462, -0.131533, -0.058554, -0.077175, 0.046473, -0.028723, 0.082435, 0.02169, -0.05884, -0.066908, 7516e-6, -0.024083, -0.016896, 0.043299, 0.025071, -0.052559, -0.036259, 0.018016, 0.014868, 0.059475, -0.10813, -734e-6, 0.013911, -0.069934, -0.023654, -0.046397, 0.028024, 7712e-6, 0.013454, -0.034854, 0.039348, -0.084795, -0.118392, -0.010387, 0.027472, -0.013331, -0.125895, -0.041034, 0.016784, -0.037666, 0.010413, 0.062172, -0.028341, 0.054028, 0.056302, -0.026385, 0.017281, 0.080924, 0.022605, 0.028539, 0.040226, 0.033684, 4577e-6, 0.026979, -0.011067, 659e-6, 0.085469, -0.020598, 0.049251, 0.041391, -0.010572, 0.097357, 0.043209, 0.037071, 0.025847, 0.012736, -0.0629, -0.024554, -0.093576, -0.038353, -0.11029, -0.041252, 0.017235, -0.059938, -0.013057, 6945e-6, -0.02508, 1215e-6, -0.023817, 0.030486, -0.14928, 0.033516, -0.032182, 778e-5, -0.058548, -0.028677, -5839e-6, -0.018994, -0, 0.014996, -0.058951, 0.048915, 0.047534, -0.053714, -0.025611, 0.039118, 0.045065, -0.011793, 0.065329, 0.03063, -0.033068, 0.025043, -0.032686, -0.038037, 0.056003, -0.043733, -0.019769, 0.02776, 0.120434, -0.029215, 0.041728, -0.074871, 0.110722, 0.047525, 0.081546, 0.028591, -0.030607, -0.023528, -0.103818, 0.02561, -0.069368, -0.103536, -0.041664, -0.088307, 0.018, 31e-4, -0.02202, -0.099577, 0.04134, 8269e-6, 0.092631, -0.093147, 0.024291, 0.01071, -0.017115, -0.090242, 0.029033, 0.041009, -0.067994, 0.027573, -9146e-6, 0.032512, -0.033344, 1196e-6, -0.081688, 0.027215, 0.053545, -0.134254, 0.033339, 0.043814, -0.014692, 0.044891, 0.015723, -6774e-6, -0.021276, -0.036136, 0.043279, -0.04103, -3137e-6, -0.025336, 0.027017, 0.031852, 0.037979, 0.056888, 0.016986, 0.015888, -0.046773, -8154e-6, -0.053904, -0.066498, -0.012196, 0.056062, 0.091648, -0.044858, -73e-4, 0.01175, 0.061546, -0.017644, 0.02004, -66e-5, -0.018841, -0.018539, 0.079675, 0.022509, -0, -0.064331, -0.026576, -0.042327, 0.028332, -5853e-6, -0.024744, 0.047413, 0.051537, -0.056245, 4566e-6, 0.036773, -0.029659, -0.079398, 0.052442, 8523e-6, 0.020647, 9384e-6, -3593e-6, -0.014809, -0.013876, -328e-6, 0.079194, 0.010541, 0.048098, 0.018196, -6731e-6, 0.03661, 0.05604, 0.119197, 0.027253, -0.041915, 0.046821, -0.053771, -0.02169, 0.046453, 0.08273, 0.053455, 3144e-6, -0.037192, 0.043435, 0.073059, -0.034059, -0.036581, -0.041038, 0.088468, 0.015768, -0.094215, -0.021958, 0.035929, 0.011529, -0.025067, -0.013653, -0.04267, 0.0741, 4846e-6, 0.039491, -1457e-6, 7501e-6, 0.104915, -0.062235, 0.049405, -0.074123, 0.092452, 0.022295] },
5113
5138
  { name: "list_entities", category: "graph", tier: 2, descriptionHash: "151c9f9cc7ae7935", embedding: [9869e-6, 0.039221, -0.017985, 0.062127, 0.017846, 0.011479, -0.053497, 0.012181, -0.027631, 0.022112, 0.024476, -0.067664, 0.036259, -6546e-6, 0.060455, 0.083451, 0.04418, 0.055013, 0.05941, -0.150598, 0.090187, 0.018138, -0.029135, -0.021231, -5622e-6, -0.045522, -0.093901, 4966e-6, 0.019375, -0.045165, -0.046949, 0.08159, -0.05141, 0.107208, -0.062976, 0.015833, 0.072251, -0.034373, 7219e-6, -0.034998, 1076e-6, 0.013932, -0.015443, -0.025458, -0.026742, 0.020433, -0.110288, -0.017173, -0.059967, -572e-6, -0.07416, 0.038236, -0.052883, 0.05788, 0.068984, 0.076051, -0.018585, -0.029614, -0.060105, 8377e-6, 1809e-6, -0.016518, -9934e-6, 6265e-6, -0.053017, -9911e-6, 8147e-6, -404e-6, 0.043481, -0.098265, 0.080826, -0.038752, -0.055578, -0.021447, 0.046618, 5738e-6, 0.018936, 0.018056, -6225e-6, -0.09769, -0.11041, 0.089765, 0.041564, -4204e-6, -0.012703, -0.044349, -0.016736, -0.082801, -0.048237, 0.048849, -4514e-6, -0.014904, 0.091902, 0.011808, 0.06668, 0.059157, 0.067194, -0.081303, 0.044341, 0.016443, -0.039689, 0.02914, -0.032206, 0.021104, -0.073646, -0.013962, -0.014455, 0.040568, -0.022705, -8866e-6, -0.011802, 0.118062, -0.016973, -0.045874, 0.011322, -0.048643, -3256e-6, -0.0199, 0.063331, 0.037032, 0.042789, 0.03297, 6748e-6, -0.037267, -0.029454, 0.055477, -0.031838, 0, 0.132252, 0.032721, 0.040518, -0.029734, -0.088739, 0.028325, -0.027406, -8194e-6, -0.035274, 0.026574, -0.10169, 0.132857, -0.01054, 0.085067, 0.072249, -0.018404, 0.029723, 0.124009, 0.050307, -0.044323, 4088e-6, 0.034195, 8592e-6, 0.023349, 0.03524, 0.073328, -0.042406, -0.062921, -0.048544, 0.043889, -9885e-6, -0.046737, 4034e-6, 2817e-6, 0.023997, 0.066605, -0.041633, 0.023126, -0.028927, -0.076544, 0.027614, -0.025601, 0.022261, -0.039308, -0.08337, -102e-6, -0.039863, -0.058725, 0.041901, 0.062422, -261e-5, 155e-5, -0.02527, 0.047808, 0.016203, 0.020861, 0.072298, 7431e-6, -0.025393, 0.050597, 128e-6, -0.018836, -0.014498, 0.010012, -5951e-6, 0.029245, -0.029082, -0.042208, 0.06618, 0.011464, 0.046211, 0.100401, 0.096154, 101e-5, 893e-6, -0.065115, -0.074135, -0.146964, -0.034718, 0.025901, -0.050778, -0.039288, -0.060746, -0.017685, 0.029436, -0.042277, 3545e-6, -0.076755, 4314e-6, -0.032518, -0.07518, -2035e-6, 9925e-6, 121e-5, -0.031225, -0, 0.03046, -0.020084, 0.084786, -0.047479, 396e-6, -0.090925, 0.045119, 1007e-6, -0.090049, 0.087244, 1199e-6, -0.0213, -2816e-6, -0.034068, 0.046173, -0.019643, -0.052543, -0.061895, 4877e-6, 0.098381, -0.0366, -0.036437, -0.091761, 0.115674, 0.077214, -4719e-6, -0.036058, -0.074632, 0.040946, -0.080891, 0.076584, -0.071783, -0.030318, -0.018569, -6304e-6, -0.028519, -0.011312, -0.085765, -0.081931, -0.028463, -0.041507, 0.045099, -0.070759, 0.031346, 2321e-6, -0.014253, -9167e-6, 0.071664, -0.017914, -0.044684, -7361e-6, 0.033823, 0.064097, 0.034082, 0.031671, 9526e-6, -0.046141, 0.071486, -0.06172, -2236e-6, 0.030522, -3738e-6, -0.048973, 0.098027, 495e-5, -0.080678, 2526e-6, -0.049155, -0.064288, -0.01438, 0.01443, -0.017578, 9537e-6, -0.047826, 0.056887, -0.052009, -0.024801, 0.023291, -0.024461, 0.012786, -0.023644, -0.037693, 0.047088, 0.032393, 0.046701, -0.061738, 0.028013, 0.08225, 4238e-6, 0.039802, -0.028564, -0.050046, -0.115669, 0.074233, 0.050805, -0, -0.082516, 0.015736, -5736e-6, -0.033366, -0.028511, 9821e-6, 0.052369, 0.086908, -0.066551, 0.051093, 0.045218, -7851e-6, -0.121843, 4426e-6, 0.103404, -0.028686, 0.068992, 0.028774, 0.033047, 0.072594, -0.096302, -0.014749, -0.046137, -0.042746, -0.016003, -545e-5, -3868e-6, 0.047832, 0.046029, 0.038886, 0.025325, 0.070839, 0.015144, 8753e-6, 0.015014, 0.035623, 5691e-6, 0.010876, 4773e-6, 0.078394, 0.092455, 0.055167, -9887e-6, 0.067516, 0.051329, 0.031391, -0.01022, 0.017734, 0.064036, -0.063985, -0.124364, -0.058518, -0.089096, -0.042014, -0.023448, 0.04869, 0.013319, -0.032993, 0.058465, -0.016633, 0.130929, -0.055697, 7264e-6, -0.018472] },
@@ -5158,28 +5183,207 @@ var init_tool_embeddings_generated = __esm({
5158
5183
  }
5159
5184
  });
5160
5185
 
5161
- // src/core/write/constants.ts
5162
- function estimateTokens(content) {
5163
- const str = typeof content === "string" ? content : JSON.stringify(content);
5164
- return Math.ceil(str.length / 4);
5165
- }
5166
- var HEADING_REGEX3;
5167
- var init_constants2 = __esm({
5168
- "src/core/write/constants.ts"() {
5169
- "use strict";
5170
- HEADING_REGEX3 = /^(#{1,6})\s+(.+)$/;
5171
- }
5172
- });
5173
-
5174
- // src/core/write/writer.ts
5186
+ // src/core/write/path-security.ts
5175
5187
  import fs20 from "fs/promises";
5176
5188
  import path22 from "path";
5177
- import matter5 from "gray-matter";
5178
- import { createHash as createHash2 } from "node:crypto";
5179
5189
  function isSensitivePath(filePath) {
5180
5190
  const normalizedPath = filePath.replace(/\\/g, "/");
5181
5191
  return SENSITIVE_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath));
5182
5192
  }
5193
+ function isWithinDirectory(child, parent, allowEqual = false) {
5194
+ const rel = path22.relative(path22.resolve(parent), path22.resolve(child));
5195
+ if (rel === "") return allowEqual;
5196
+ const firstSeg = rel.split(path22.sep)[0];
5197
+ return firstSeg !== ".." && !path22.isAbsolute(rel);
5198
+ }
5199
+ function validatePath(vaultPath2, notePath) {
5200
+ if (notePath.startsWith("/")) {
5201
+ return false;
5202
+ }
5203
+ if (process.platform === "win32" && /^[a-zA-Z]:/.test(notePath)) {
5204
+ return false;
5205
+ }
5206
+ if (notePath.startsWith("\\")) {
5207
+ return false;
5208
+ }
5209
+ return isWithinDirectory(path22.resolve(vaultPath2, notePath), vaultPath2);
5210
+ }
5211
+ function sanitizeNotePath(notePath) {
5212
+ const dir = path22.dirname(notePath);
5213
+ let filename = path22.basename(notePath);
5214
+ const ext = filename.endsWith(".md") ? ".md" : "";
5215
+ let stem2 = ext ? filename.slice(0, -ext.length) : filename;
5216
+ stem2 = stem2.replace(/\s+/g, "-");
5217
+ stem2 = stem2.replace(/[?*<>|":]/g, "");
5218
+ stem2 = stem2.toLowerCase();
5219
+ stem2 = stem2.replace(/-{2,}/g, "-");
5220
+ stem2 = stem2.replace(/^-+|-+$/g, "");
5221
+ filename = stem2 + (ext || ".md");
5222
+ return dir === "." ? filename : path22.join(dir, filename).replace(/\\/g, "/");
5223
+ }
5224
+ async function validatePathSecure(vaultPath2, notePath) {
5225
+ if (notePath.startsWith("/")) {
5226
+ return {
5227
+ valid: false,
5228
+ reason: "Absolute paths not allowed"
5229
+ };
5230
+ }
5231
+ if (process.platform === "win32" && /^[a-zA-Z]:/.test(notePath)) {
5232
+ return {
5233
+ valid: false,
5234
+ reason: "Absolute paths not allowed"
5235
+ };
5236
+ }
5237
+ if (notePath.startsWith("\\")) {
5238
+ return {
5239
+ valid: false,
5240
+ reason: "Absolute paths not allowed"
5241
+ };
5242
+ }
5243
+ const firstSeg = path22.normalize(notePath).split(path22.sep).filter(Boolean)[0];
5244
+ if (firstSeg === "..") {
5245
+ return {
5246
+ valid: false,
5247
+ reason: "Path traversal not allowed"
5248
+ };
5249
+ }
5250
+ if (!isWithinDirectory(path22.resolve(vaultPath2, notePath), vaultPath2)) {
5251
+ return {
5252
+ valid: false,
5253
+ reason: "Path traversal not allowed"
5254
+ };
5255
+ }
5256
+ if (isSensitivePath(notePath)) {
5257
+ return {
5258
+ valid: false,
5259
+ reason: "Cannot write to sensitive file (credentials, keys, secrets)"
5260
+ };
5261
+ }
5262
+ try {
5263
+ const fullPath = path22.join(vaultPath2, notePath);
5264
+ try {
5265
+ await fs20.access(fullPath);
5266
+ const realPath = await fs20.realpath(fullPath);
5267
+ const realVaultPath = await fs20.realpath(vaultPath2);
5268
+ if (!isWithinDirectory(realPath, realVaultPath)) {
5269
+ return {
5270
+ valid: false,
5271
+ reason: "Symlink target is outside vault"
5272
+ };
5273
+ }
5274
+ const relativePath = path22.relative(realVaultPath, realPath);
5275
+ if (isSensitivePath(relativePath)) {
5276
+ return {
5277
+ valid: false,
5278
+ reason: "Symlink target is a sensitive file"
5279
+ };
5280
+ }
5281
+ } catch {
5282
+ const parentDir = path22.dirname(fullPath);
5283
+ try {
5284
+ await fs20.access(parentDir);
5285
+ const realParentPath = await fs20.realpath(parentDir);
5286
+ const realVaultPath = await fs20.realpath(vaultPath2);
5287
+ if (!isWithinDirectory(realParentPath, realVaultPath, true)) {
5288
+ return {
5289
+ valid: false,
5290
+ reason: "Parent directory symlink target is outside vault"
5291
+ };
5292
+ }
5293
+ } catch {
5294
+ }
5295
+ }
5296
+ } catch (error) {
5297
+ return {
5298
+ valid: false,
5299
+ reason: `Path validation error: ${error.message}`
5300
+ };
5301
+ }
5302
+ return { valid: true };
5303
+ }
5304
+ var SENSITIVE_PATH_PATTERNS;
5305
+ var init_path_security = __esm({
5306
+ "src/core/write/path-security.ts"() {
5307
+ "use strict";
5308
+ SENSITIVE_PATH_PATTERNS = [
5309
+ // Environment files (including backups, variations, and Windows ADS)
5310
+ /\.env($|\..*|~|\.swp|\.swo|:)/i,
5311
+ // .env, .env.local, .env~, .env.swp, .env:$DATA (ADS), etc.
5312
+ // Git credentials and config
5313
+ /\.git\/config$/i,
5314
+ // Git config (may contain tokens)
5315
+ /\.git\/credentials$/i,
5316
+ // Git credentials
5317
+ // SSL/TLS certificates and private keys (including backups)
5318
+ /\.pem($|\.bak|\.backup|\.old|\.orig|~)$/i,
5319
+ // SSL/TLS certificates + backups
5320
+ /\.key($|\.bak|\.backup|\.old|\.orig|~)$/i,
5321
+ // Private keys + backups
5322
+ /\.p12($|\.bak|\.backup|\.old|\.orig|~)$/i,
5323
+ // PKCS#12 certificates + backups
5324
+ /\.pfx($|\.bak|\.backup|\.old|\.orig|~)$/i,
5325
+ // Windows certificate format + backups
5326
+ /\.jks($|\.bak|\.backup|\.old|\.orig|~)$/i,
5327
+ // Java keystore + backups
5328
+ /\.crt($|\.bak|\.backup|\.old|\.orig|~)$/i,
5329
+ // Certificate files + backups
5330
+ // SSH keys
5331
+ /id_rsa/i,
5332
+ // SSH private key
5333
+ /id_ed25519/i,
5334
+ // SSH private key (ed25519)
5335
+ /id_ecdsa/i,
5336
+ // SSH private key (ecdsa)
5337
+ /id_dsa/i,
5338
+ // SSH private key (dsa)
5339
+ /\.ssh\/config$/i,
5340
+ // SSH config
5341
+ /authorized_keys$/i,
5342
+ // SSH authorized keys
5343
+ /known_hosts$/i,
5344
+ // SSH known hosts
5345
+ // Generic credentials/secrets files (including backups)
5346
+ /credentials\.json($|\.bak|\.backup|\.old|\.orig|~)$/i,
5347
+ // Cloud credentials + backups
5348
+ /secrets\.json($|\.bak|\.backup|\.old|\.orig|~)$/i,
5349
+ // Secrets files + backups
5350
+ /secrets\.ya?ml($|\.bak|\.backup|\.old|\.orig|~)$/i,
5351
+ // Secrets YAML + backups
5352
+ // Package manager auth
5353
+ /\.npmrc$/i,
5354
+ // npm config (may contain tokens)
5355
+ /\.netrc$/i,
5356
+ // Netrc (HTTP auth credentials)
5357
+ /\.yarnrc$/i,
5358
+ // Yarn config
5359
+ // Cloud provider credentials
5360
+ /\.aws\/credentials$/i,
5361
+ // AWS credentials
5362
+ /\.aws\/config$/i,
5363
+ // AWS config
5364
+ /gcloud\/credentials\.json/i,
5365
+ // Google Cloud credentials
5366
+ /\.azure\/credentials$/i,
5367
+ // Azure credentials
5368
+ /\.docker\/config\.json$/i,
5369
+ // Docker registry auth
5370
+ /\.kube\/config$/i,
5371
+ // Kubernetes config
5372
+ // System password files
5373
+ /\.htpasswd$/i,
5374
+ // Apache password file
5375
+ /shadow$/,
5376
+ // Unix shadow password file
5377
+ /passwd$/,
5378
+ // Unix password file
5379
+ // Hidden credential files (starting with dot)
5380
+ /^\.(credentials|secrets|tokens)$/i
5381
+ // .credentials, .secrets, .tokens
5382
+ ];
5383
+ }
5384
+ });
5385
+
5386
+ // src/core/write/regex-safety.ts
5183
5387
  function checkRegexSafety(pattern) {
5184
5388
  if (pattern.length > MAX_REGEX_LENGTH) {
5185
5389
  return `Regex pattern too long (${pattern.length} chars, max ${MAX_REGEX_LENGTH})`;
@@ -5216,21 +5420,62 @@ function safeRegexReplace(input, pattern, replacement, useRegex, global = false)
5216
5420
  const regex = createSafeRegex(pattern, global ? "g" : void 0);
5217
5421
  return input.replace(regex, replacement);
5218
5422
  }
5219
- function detectLineEnding(content) {
5220
- const crlfCount = (content.match(/\r\n/g) || []).length;
5221
- const lfCount = (content.match(/(?<!\r)\n/g) || []).length;
5222
- return crlfCount > lfCount ? "CRLF" : "LF";
5223
- }
5224
- function normalizeLineEndings(content) {
5225
- return content.replace(/\r\n/g, "\n");
5226
- }
5227
- function convertLineEndings(content, style) {
5228
- const normalized = content.replace(/\r\n/g, "\n");
5423
+ var REDOS_PATTERNS, MAX_REGEX_LENGTH;
5424
+ var init_regex_safety = __esm({
5425
+ "src/core/write/regex-safety.ts"() {
5426
+ "use strict";
5427
+ REDOS_PATTERNS = [
5428
+ // Nested quantifiers: (a+)+, (a*)+, (a+)*, (a*)*, etc.
5429
+ /(\([^)]*[+*][^)]*\))[+*]/,
5430
+ // Quantifiers followed by optional same-type quantifiers
5431
+ /[+*]\??\s*[+*]/,
5432
+ // Overlapping character classes with quantifiers followed by similar
5433
+ /\[[^\]]*\][+*].*\[[^\]]*\][+*]/,
5434
+ // Multiple adjacent capturing groups with quantifiers
5435
+ /(\([^)]+[+*]\)){2,}/,
5436
+ // Extremely long alternation groups
5437
+ /\([^)]{100,}\)/
5438
+ ];
5439
+ MAX_REGEX_LENGTH = 500;
5440
+ }
5441
+ });
5442
+
5443
+ // src/core/write/line-endings.ts
5444
+ function detectLineEnding(content) {
5445
+ const crlfCount = (content.match(/\r\n/g) || []).length;
5446
+ const lfCount = (content.match(/(?<!\r)\n/g) || []).length;
5447
+ return crlfCount > lfCount ? "CRLF" : "LF";
5448
+ }
5449
+ function normalizeLineEndings(content) {
5450
+ return content.replace(/\r\n/g, "\n");
5451
+ }
5452
+ function convertLineEndings(content, style) {
5453
+ const normalized = content.replace(/\r\n/g, "\n");
5229
5454
  return style === "CRLF" ? normalized.replace(/\n/g, "\r\n") : normalized;
5230
5455
  }
5231
5456
  function normalizeTrailingNewline(content) {
5232
5457
  return content.replace(/[\r\n\s]+$/, "") + "\n";
5233
5458
  }
5459
+ var init_line_endings = __esm({
5460
+ "src/core/write/line-endings.ts"() {
5461
+ "use strict";
5462
+ }
5463
+ });
5464
+
5465
+ // src/core/write/constants.ts
5466
+ function estimateTokens(content) {
5467
+ const str = typeof content === "string" ? content : JSON.stringify(content);
5468
+ return Math.ceil(str.length / 4);
5469
+ }
5470
+ var HEADING_REGEX3;
5471
+ var init_constants2 = __esm({
5472
+ "src/core/write/constants.ts"() {
5473
+ "use strict";
5474
+ HEADING_REGEX3 = /^(#{1,6})\s+(.+)$/;
5475
+ }
5476
+ });
5477
+
5478
+ // src/core/write/markdown-structure.ts
5234
5479
  function isEmptyPlaceholder(line) {
5235
5480
  const trimmed = line.trim();
5236
5481
  return EMPTY_PLACEHOLDER_PATTERNS.some((p) => p.test(trimmed));
@@ -5536,189 +5781,27 @@ function insertInSection(content, section, newContent, position, options) {
5536
5781
  }
5537
5782
  return lines.join("\n");
5538
5783
  }
5539
- function validatePath(vaultPath2, notePath) {
5540
- if (notePath.startsWith("/")) {
5541
- return false;
5542
- }
5543
- if (process.platform === "win32" && /^[a-zA-Z]:/.test(notePath)) {
5544
- return false;
5545
- }
5546
- if (notePath.startsWith("\\")) {
5547
- return false;
5548
- }
5549
- const resolvedVault = path22.resolve(vaultPath2);
5550
- const resolvedNote = path22.resolve(vaultPath2, notePath);
5551
- return resolvedNote.startsWith(resolvedVault);
5552
- }
5553
- function sanitizeNotePath(notePath) {
5554
- const dir = path22.dirname(notePath);
5555
- let filename = path22.basename(notePath);
5556
- const ext = filename.endsWith(".md") ? ".md" : "";
5557
- let stem2 = ext ? filename.slice(0, -ext.length) : filename;
5558
- stem2 = stem2.replace(/\s+/g, "-");
5559
- stem2 = stem2.replace(/[?*<>|":]/g, "");
5560
- stem2 = stem2.toLowerCase();
5561
- stem2 = stem2.replace(/-{2,}/g, "-");
5562
- stem2 = stem2.replace(/^-+|-+$/g, "");
5563
- filename = stem2 + (ext || ".md");
5564
- return dir === "." ? filename : path22.join(dir, filename).replace(/\\/g, "/");
5565
- }
5566
- async function validatePathSecure(vaultPath2, notePath) {
5567
- if (notePath.startsWith("/")) {
5568
- return {
5569
- valid: false,
5570
- reason: "Absolute paths not allowed"
5571
- };
5572
- }
5573
- if (process.platform === "win32" && /^[a-zA-Z]:/.test(notePath)) {
5574
- return {
5575
- valid: false,
5576
- reason: "Absolute paths not allowed"
5577
- };
5578
- }
5579
- if (notePath.startsWith("\\")) {
5580
- return {
5581
- valid: false,
5582
- reason: "Absolute paths not allowed"
5583
- };
5584
- }
5585
- if (notePath.startsWith("..")) {
5586
- return {
5587
- valid: false,
5588
- reason: "Path traversal not allowed"
5589
- };
5590
- }
5591
- const resolvedVault = path22.resolve(vaultPath2);
5592
- const resolvedNote = path22.resolve(vaultPath2, notePath);
5593
- if (!resolvedNote.startsWith(resolvedVault)) {
5594
- return {
5595
- valid: false,
5596
- reason: "Path traversal not allowed"
5597
- };
5598
- }
5599
- if (isSensitivePath(notePath)) {
5600
- return {
5601
- valid: false,
5602
- reason: "Cannot write to sensitive file (credentials, keys, secrets)"
5603
- };
5604
- }
5605
- try {
5606
- const fullPath = path22.join(vaultPath2, notePath);
5607
- try {
5608
- await fs20.access(fullPath);
5609
- const realPath = await fs20.realpath(fullPath);
5610
- const realVaultPath = await fs20.realpath(vaultPath2);
5611
- if (!realPath.startsWith(realVaultPath)) {
5612
- return {
5613
- valid: false,
5614
- reason: "Symlink target is outside vault"
5615
- };
5616
- }
5617
- const relativePath = path22.relative(realVaultPath, realPath);
5618
- if (isSensitivePath(relativePath)) {
5619
- return {
5620
- valid: false,
5621
- reason: "Symlink target is a sensitive file"
5622
- };
5623
- }
5624
- } catch {
5625
- const parentDir = path22.dirname(fullPath);
5626
- try {
5627
- await fs20.access(parentDir);
5628
- const realParentPath = await fs20.realpath(parentDir);
5629
- const realVaultPath = await fs20.realpath(vaultPath2);
5630
- if (!realParentPath.startsWith(realVaultPath)) {
5631
- return {
5632
- valid: false,
5633
- reason: "Parent directory symlink target is outside vault"
5634
- };
5635
- }
5636
- } catch {
5637
- }
5638
- }
5639
- } catch (error) {
5640
- return {
5641
- valid: false,
5642
- reason: `Path validation error: ${error.message}`
5643
- };
5644
- }
5645
- return { valid: true };
5646
- }
5647
- function computeContentHash(rawContent) {
5648
- return createHash2("sha256").update(rawContent).digest("hex").slice(0, 16);
5649
- }
5650
- async function readVaultFile(vaultPath2, notePath) {
5651
- if (!validatePath(vaultPath2, notePath)) {
5652
- throw new Error("Invalid path: path traversal not allowed");
5653
- }
5654
- const fullPath = path22.join(vaultPath2, notePath);
5655
- const [rawContent, stat5] = await Promise.all([
5656
- fs20.readFile(fullPath, "utf-8"),
5657
- fs20.stat(fullPath)
5658
- ]);
5659
- const contentHash2 = computeContentHash(rawContent);
5660
- const lineEnding = detectLineEnding(rawContent);
5661
- const normalizedContent = normalizeLineEndings(rawContent);
5662
- const parsed = matter5(normalizedContent);
5663
- const frontmatter = deepCloneFrontmatter(parsed.data);
5664
- return {
5665
- content: parsed.content,
5666
- frontmatter,
5667
- rawContent,
5668
- lineEnding,
5669
- mtimeMs: stat5.mtimeMs,
5670
- contentHash: contentHash2
5671
- };
5672
- }
5673
- function deepCloneFrontmatter(obj) {
5674
- if (obj === null || typeof obj !== "object") {
5675
- return obj;
5676
- }
5677
- if (obj instanceof Date) {
5678
- return new Date(obj.getTime());
5679
- }
5680
- if (Array.isArray(obj)) {
5681
- return obj.map((item) => {
5682
- if (item instanceof Date) {
5683
- return new Date(item.getTime());
5684
- }
5685
- if (item !== null && typeof item === "object") {
5686
- return deepCloneFrontmatter(item);
5687
- }
5688
- return item;
5689
- });
5690
- }
5691
- const cloned = {};
5692
- for (const key of Object.keys(obj)) {
5693
- const value = obj[key];
5694
- if (value instanceof Date) {
5695
- cloned[key] = new Date(value.getTime());
5696
- } else if (value !== null && typeof value === "object") {
5697
- cloned[key] = deepCloneFrontmatter(value);
5698
- } else {
5699
- cloned[key] = value;
5700
- }
5701
- }
5702
- return cloned;
5703
- }
5704
- async function writeVaultFile(vaultPath2, notePath, content, frontmatter, lineEnding = "LF", expectedHash) {
5705
- const validation = await validatePathSecure(vaultPath2, notePath);
5706
- if (!validation.valid) {
5707
- throw new Error(`Invalid path: ${validation.reason}`);
5708
- }
5709
- const fullPath = path22.join(vaultPath2, notePath);
5710
- if (expectedHash) {
5711
- const currentRaw = await fs20.readFile(fullPath, "utf-8");
5712
- const currentHash = computeContentHash(currentRaw);
5713
- if (currentHash !== expectedHash) {
5714
- throw new WriteConflictError(notePath);
5715
- }
5784
+ var EMPTY_PLACEHOLDER_PATTERNS;
5785
+ var init_markdown_structure = __esm({
5786
+ "src/core/write/markdown-structure.ts"() {
5787
+ "use strict";
5788
+ init_constants2();
5789
+ EMPTY_PLACEHOLDER_PATTERNS = [
5790
+ /^\d+\.\s*$/,
5791
+ // "1. " or "2. " (numbered list placeholder)
5792
+ /^-\s*$/,
5793
+ // "- " (bullet placeholder)
5794
+ /^-\s*\[\s*\]\s*$/,
5795
+ // "- [ ] " (empty task placeholder)
5796
+ /^-\s*\[x\]\s*$/i,
5797
+ // "- [x] " (completed task placeholder)
5798
+ /^\*\s*$/
5799
+ // "* " (asterisk bullet placeholder)
5800
+ ];
5716
5801
  }
5717
- let output = matter5.stringify(content, frontmatter);
5718
- output = normalizeTrailingNewline(output);
5719
- output = convertLineEndings(output, lineEnding);
5720
- await fs20.writeFile(fullPath, output, "utf-8");
5721
- }
5802
+ });
5803
+
5804
+ // src/core/write/content-mutation.ts
5722
5805
  function removeFromSection(content, section, pattern, mode = "first", useRegex = false) {
5723
5806
  const lines = content.split("\n");
5724
5807
  const removedLines = [];
@@ -5954,114 +6037,112 @@ function injectMutationMetadata(frontmatter, scoping) {
5954
6037
  frontmatter._last_modified_by = `session:${scoping.session_id}`;
5955
6038
  }
5956
6039
  }
5957
- return frontmatter;
6040
+ return frontmatter;
6041
+ }
6042
+ var DiagnosticError;
6043
+ var init_content_mutation = __esm({
6044
+ "src/core/write/content-mutation.ts"() {
6045
+ "use strict";
6046
+ init_regex_safety();
6047
+ init_levenshtein();
6048
+ DiagnosticError = class extends Error {
6049
+ diagnostic;
6050
+ constructor(message, diagnostic) {
6051
+ super(message);
6052
+ this.name = "DiagnosticError";
6053
+ this.diagnostic = diagnostic;
6054
+ }
6055
+ };
6056
+ }
6057
+ });
6058
+
6059
+ // src/core/write/file-io.ts
6060
+ import fs21 from "fs/promises";
6061
+ import path23 from "path";
6062
+ import matter5 from "gray-matter";
6063
+ import { createHash as createHash2 } from "node:crypto";
6064
+ function computeContentHash(rawContent) {
6065
+ return createHash2("sha256").update(rawContent).digest("hex").slice(0, 16);
6066
+ }
6067
+ async function readVaultFile(vaultPath2, notePath) {
6068
+ const validation = await validatePathSecure(vaultPath2, notePath);
6069
+ if (!validation.valid) {
6070
+ throw new Error(`Invalid path: ${validation.reason}`);
6071
+ }
6072
+ const fullPath = path23.join(vaultPath2, notePath);
6073
+ const [rawContent, stat4] = await Promise.all([
6074
+ fs21.readFile(fullPath, "utf-8"),
6075
+ fs21.stat(fullPath)
6076
+ ]);
6077
+ const contentHash2 = computeContentHash(rawContent);
6078
+ const lineEnding = detectLineEnding(rawContent);
6079
+ const normalizedContent = normalizeLineEndings(rawContent);
6080
+ const parsed = matter5(normalizedContent);
6081
+ const frontmatter = deepCloneFrontmatter(parsed.data);
6082
+ return {
6083
+ content: parsed.content,
6084
+ frontmatter,
6085
+ rawContent,
6086
+ lineEnding,
6087
+ mtimeMs: stat4.mtimeMs,
6088
+ contentHash: contentHash2
6089
+ };
6090
+ }
6091
+ function deepCloneFrontmatter(obj) {
6092
+ if (obj === null || typeof obj !== "object") {
6093
+ return obj;
6094
+ }
6095
+ if (obj instanceof Date) {
6096
+ return new Date(obj.getTime());
6097
+ }
6098
+ if (Array.isArray(obj)) {
6099
+ return obj.map((item) => {
6100
+ if (item instanceof Date) {
6101
+ return new Date(item.getTime());
6102
+ }
6103
+ if (item !== null && typeof item === "object") {
6104
+ return deepCloneFrontmatter(item);
6105
+ }
6106
+ return item;
6107
+ });
6108
+ }
6109
+ const cloned = {};
6110
+ for (const key of Object.keys(obj)) {
6111
+ const value = obj[key];
6112
+ if (value instanceof Date) {
6113
+ cloned[key] = new Date(value.getTime());
6114
+ } else if (value !== null && typeof value === "object") {
6115
+ cloned[key] = deepCloneFrontmatter(value);
6116
+ } else {
6117
+ cloned[key] = value;
6118
+ }
6119
+ }
6120
+ return cloned;
5958
6121
  }
5959
- var SENSITIVE_PATH_PATTERNS, REDOS_PATTERNS, MAX_REGEX_LENGTH, EMPTY_PLACEHOLDER_PATTERNS, WriteConflictError, DiagnosticError;
5960
- var init_writer = __esm({
5961
- "src/core/write/writer.ts"() {
6122
+ async function writeVaultFile(vaultPath2, notePath, content, frontmatter, lineEnding = "LF", expectedHash) {
6123
+ const validation = await validatePathSecure(vaultPath2, notePath);
6124
+ if (!validation.valid) {
6125
+ throw new Error(`Invalid path: ${validation.reason}`);
6126
+ }
6127
+ const fullPath = path23.join(vaultPath2, notePath);
6128
+ if (expectedHash) {
6129
+ const currentRaw = await fs21.readFile(fullPath, "utf-8");
6130
+ const currentHash = computeContentHash(currentRaw);
6131
+ if (currentHash !== expectedHash) {
6132
+ throw new WriteConflictError(notePath);
6133
+ }
6134
+ }
6135
+ let output = matter5.stringify(content, frontmatter);
6136
+ output = normalizeTrailingNewline(output);
6137
+ output = convertLineEndings(output, lineEnding);
6138
+ await fs21.writeFile(fullPath, output, "utf-8");
6139
+ }
6140
+ var WriteConflictError;
6141
+ var init_file_io = __esm({
6142
+ "src/core/write/file-io.ts"() {
5962
6143
  "use strict";
5963
- init_constants2();
5964
- init_levenshtein();
5965
- SENSITIVE_PATH_PATTERNS = [
5966
- // Environment files (including backups, variations, and Windows ADS)
5967
- /\.env($|\..*|~|\.swp|\.swo|:)/i,
5968
- // .env, .env.local, .env~, .env.swp, .env:$DATA (ADS), etc.
5969
- // Git credentials and config
5970
- /\.git\/config$/i,
5971
- // Git config (may contain tokens)
5972
- /\.git\/credentials$/i,
5973
- // Git credentials
5974
- // SSL/TLS certificates and private keys (including backups)
5975
- /\.pem($|\.bak|\.backup|\.old|\.orig|~)$/i,
5976
- // SSL/TLS certificates + backups
5977
- /\.key($|\.bak|\.backup|\.old|\.orig|~)$/i,
5978
- // Private keys + backups
5979
- /\.p12($|\.bak|\.backup|\.old|\.orig|~)$/i,
5980
- // PKCS#12 certificates + backups
5981
- /\.pfx($|\.bak|\.backup|\.old|\.orig|~)$/i,
5982
- // Windows certificate format + backups
5983
- /\.jks($|\.bak|\.backup|\.old|\.orig|~)$/i,
5984
- // Java keystore + backups
5985
- /\.crt($|\.bak|\.backup|\.old|\.orig|~)$/i,
5986
- // Certificate files + backups
5987
- // SSH keys
5988
- /id_rsa/i,
5989
- // SSH private key
5990
- /id_ed25519/i,
5991
- // SSH private key (ed25519)
5992
- /id_ecdsa/i,
5993
- // SSH private key (ecdsa)
5994
- /id_dsa/i,
5995
- // SSH private key (dsa)
5996
- /\.ssh\/config$/i,
5997
- // SSH config
5998
- /authorized_keys$/i,
5999
- // SSH authorized keys
6000
- /known_hosts$/i,
6001
- // SSH known hosts
6002
- // Generic credentials/secrets files (including backups)
6003
- /credentials\.json($|\.bak|\.backup|\.old|\.orig|~)$/i,
6004
- // Cloud credentials + backups
6005
- /secrets\.json($|\.bak|\.backup|\.old|\.orig|~)$/i,
6006
- // Secrets files + backups
6007
- /secrets\.ya?ml($|\.bak|\.backup|\.old|\.orig|~)$/i,
6008
- // Secrets YAML + backups
6009
- // Package manager auth
6010
- /\.npmrc$/i,
6011
- // npm config (may contain tokens)
6012
- /\.netrc$/i,
6013
- // Netrc (HTTP auth credentials)
6014
- /\.yarnrc$/i,
6015
- // Yarn config
6016
- // Cloud provider credentials
6017
- /\.aws\/credentials$/i,
6018
- // AWS credentials
6019
- /\.aws\/config$/i,
6020
- // AWS config
6021
- /gcloud\/credentials\.json/i,
6022
- // Google Cloud credentials
6023
- /\.azure\/credentials$/i,
6024
- // Azure credentials
6025
- /\.docker\/config\.json$/i,
6026
- // Docker registry auth
6027
- /\.kube\/config$/i,
6028
- // Kubernetes config
6029
- // System password files
6030
- /\.htpasswd$/i,
6031
- // Apache password file
6032
- /shadow$/,
6033
- // Unix shadow password file
6034
- /passwd$/,
6035
- // Unix password file
6036
- // Hidden credential files (starting with dot)
6037
- /^\.(credentials|secrets|tokens)$/i
6038
- // .credentials, .secrets, .tokens
6039
- ];
6040
- REDOS_PATTERNS = [
6041
- // Nested quantifiers: (a+)+, (a*)+, (a+)*, (a*)*, etc.
6042
- /(\([^)]*[+*][^)]*\))[+*]/,
6043
- // Quantifiers followed by optional same-type quantifiers
6044
- /[+*]\??\s*[+*]/,
6045
- // Overlapping character classes with quantifiers followed by similar
6046
- /\[[^\]]*\][+*].*\[[^\]]*\][+*]/,
6047
- // Multiple adjacent capturing groups with quantifiers
6048
- /(\([^)]+[+*]\)){2,}/,
6049
- // Extremely long alternation groups
6050
- /\([^)]{100,}\)/
6051
- ];
6052
- MAX_REGEX_LENGTH = 500;
6053
- EMPTY_PLACEHOLDER_PATTERNS = [
6054
- /^\d+\.\s*$/,
6055
- // "1. " or "2. " (numbered list placeholder)
6056
- /^-\s*$/,
6057
- // "- " (bullet placeholder)
6058
- /^-\s*\[\s*\]\s*$/,
6059
- // "- [ ] " (empty task placeholder)
6060
- /^-\s*\[x\]\s*$/i,
6061
- // "- [x] " (completed task placeholder)
6062
- /^\*\s*$/
6063
- // "* " (asterisk bullet placeholder)
6064
- ];
6144
+ init_path_security();
6145
+ init_line_endings();
6065
6146
  WriteConflictError = class extends Error {
6066
6147
  constructor(notePath) {
6067
6148
  super(`Write conflict on ${notePath}: file was modified externally since it was read. Re-read and retry.`);
@@ -6069,14 +6150,19 @@ var init_writer = __esm({
6069
6150
  this.name = "WriteConflictError";
6070
6151
  }
6071
6152
  };
6072
- DiagnosticError = class extends Error {
6073
- diagnostic;
6074
- constructor(message, diagnostic) {
6075
- super(message);
6076
- this.name = "DiagnosticError";
6077
- this.diagnostic = diagnostic;
6078
- }
6079
- };
6153
+ }
6154
+ });
6155
+
6156
+ // src/core/write/writer.ts
6157
+ var init_writer = __esm({
6158
+ "src/core/write/writer.ts"() {
6159
+ "use strict";
6160
+ init_path_security();
6161
+ init_regex_safety();
6162
+ init_line_endings();
6163
+ init_markdown_structure();
6164
+ init_content_mutation();
6165
+ init_file_io();
6080
6166
  }
6081
6167
  });
6082
6168
 
@@ -6106,8 +6192,8 @@ function createContext(variables = {}) {
6106
6192
  steps: {}
6107
6193
  };
6108
6194
  }
6109
- function resolvePath(obj, path39) {
6110
- const parts = path39.split(".");
6195
+ function resolvePath(obj, path40) {
6196
+ const parts = path40.split(".");
6111
6197
  let current = obj;
6112
6198
  for (const part of parts) {
6113
6199
  if (current === void 0 || current === null) {
@@ -6564,8 +6650,8 @@ __export(conditions_exports, {
6564
6650
  evaluateCondition: () => evaluateCondition,
6565
6651
  shouldStepExecute: () => shouldStepExecute
6566
6652
  });
6567
- import fs28 from "fs/promises";
6568
- import path30 from "path";
6653
+ import fs29 from "fs/promises";
6654
+ import path31 from "path";
6569
6655
  async function evaluateCondition(condition, vaultPath2, context) {
6570
6656
  const interpolatedPath = condition.path ? interpolate(condition.path, context) : void 0;
6571
6657
  const interpolatedSection = condition.section ? interpolate(condition.section, context) : void 0;
@@ -6618,9 +6704,9 @@ async function evaluateCondition(condition, vaultPath2, context) {
6618
6704
  }
6619
6705
  }
6620
6706
  async function evaluateFileExists(vaultPath2, notePath, expectExists) {
6621
- const fullPath = path30.join(vaultPath2, notePath);
6707
+ const fullPath = path31.join(vaultPath2, notePath);
6622
6708
  try {
6623
- await fs28.access(fullPath);
6709
+ await fs29.access(fullPath);
6624
6710
  return {
6625
6711
  met: expectExists,
6626
6712
  reason: expectExists ? `File exists: ${notePath}` : `File exists (expected not to): ${notePath}`
@@ -6633,9 +6719,9 @@ async function evaluateFileExists(vaultPath2, notePath, expectExists) {
6633
6719
  }
6634
6720
  }
6635
6721
  async function evaluateSectionExists(vaultPath2, notePath, sectionName, expectExists) {
6636
- const fullPath = path30.join(vaultPath2, notePath);
6722
+ const fullPath = path31.join(vaultPath2, notePath);
6637
6723
  try {
6638
- await fs28.access(fullPath);
6724
+ await fs29.access(fullPath);
6639
6725
  } catch {
6640
6726
  return {
6641
6727
  met: !expectExists,
@@ -6664,9 +6750,9 @@ async function evaluateSectionExists(vaultPath2, notePath, sectionName, expectEx
6664
6750
  }
6665
6751
  }
6666
6752
  async function evaluateFrontmatterExists(vaultPath2, notePath, fieldName, expectExists) {
6667
- const fullPath = path30.join(vaultPath2, notePath);
6753
+ const fullPath = path31.join(vaultPath2, notePath);
6668
6754
  try {
6669
- await fs28.access(fullPath);
6755
+ await fs29.access(fullPath);
6670
6756
  } catch {
6671
6757
  return {
6672
6758
  met: !expectExists,
@@ -6695,9 +6781,9 @@ async function evaluateFrontmatterExists(vaultPath2, notePath, fieldName, expect
6695
6781
  }
6696
6782
  }
6697
6783
  async function evaluateFrontmatterEquals(vaultPath2, notePath, fieldName, expectedValue) {
6698
- const fullPath = path30.join(vaultPath2, notePath);
6784
+ const fullPath = path31.join(vaultPath2, notePath);
6699
6785
  try {
6700
- await fs28.access(fullPath);
6786
+ await fs29.access(fullPath);
6701
6787
  } catch {
6702
6788
  return {
6703
6789
  met: false,
@@ -6839,9 +6925,9 @@ var init_taskHelpers = __esm({
6839
6925
  });
6840
6926
 
6841
6927
  // src/index.ts
6842
- import * as path38 from "path";
6928
+ import * as path39 from "path";
6843
6929
  import { readFileSync as readFileSync6, realpathSync, existsSync as existsSync3 } from "fs";
6844
- import { fileURLToPath as fileURLToPath2 } from "url";
6930
+ import { fileURLToPath as fileURLToPath3 } from "url";
6845
6931
  import { dirname as dirname7, join as join20 } from "path";
6846
6932
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6847
6933
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -7079,8 +7165,8 @@ function updateIndexProgress(parsed, total) {
7079
7165
  function normalizeTarget(target) {
7080
7166
  return target.toLowerCase().replace(/\.md$/, "");
7081
7167
  }
7082
- function normalizeNotePath(path39) {
7083
- return path39.toLowerCase().replace(/\.md$/, "");
7168
+ function normalizeNotePath(path40) {
7169
+ return path40.toLowerCase().replace(/\.md$/, "");
7084
7170
  }
7085
7171
  async function buildVaultIndex(vaultPath2, options = {}) {
7086
7172
  const { timeoutMs = DEFAULT_TIMEOUT_MS, onProgress } = options;
@@ -7128,6 +7214,7 @@ async function buildVaultIndexInternal(vaultPath2, startTime, onProgress) {
7128
7214
  console.error(`Parsed ${parsedCount}/${files.length} files (${elapsed}s)`);
7129
7215
  onProgress?.(parsedCount, files.length);
7130
7216
  }
7217
+ await new Promise((resolve3) => setImmediate(resolve3));
7131
7218
  }
7132
7219
  if (parseErrors.length > 0) {
7133
7220
  const msg = `Failed to parse ${parseErrors.length} file(s):`;
@@ -7253,7 +7340,7 @@ function findSimilarEntity(index, target) {
7253
7340
  }
7254
7341
  const maxDist = normalizedLen <= 10 ? 1 : 2;
7255
7342
  let bestMatch;
7256
- for (const [entity, path39] of index.entities) {
7343
+ for (const [entity, path40] of index.entities) {
7257
7344
  const lenDiff = Math.abs(entity.length - normalizedLen);
7258
7345
  if (lenDiff > maxDist) {
7259
7346
  continue;
@@ -7261,7 +7348,7 @@ function findSimilarEntity(index, target) {
7261
7348
  const dist = levenshteinDistance(normalized, entity);
7262
7349
  if (dist > 0 && dist <= maxDist) {
7263
7350
  if (!bestMatch || dist < bestMatch.distance) {
7264
- bestMatch = { path: path39, entity, distance: dist };
7351
+ bestMatch = { path: path40, entity, distance: dist };
7265
7352
  if (dist === 1) {
7266
7353
  return bestMatch;
7267
7354
  }
@@ -7685,8 +7772,8 @@ function normalizePath(filePath) {
7685
7772
  function getRelativePath(vaultPath2, filePath) {
7686
7773
  const normalizedVault = normalizePath(vaultPath2);
7687
7774
  const normalizedFile = normalizePath(filePath);
7688
- const relative3 = path5.posix.relative(normalizedVault, normalizedFile);
7689
- return relative3;
7775
+ const relative2 = path5.posix.relative(normalizedVault, normalizedFile);
7776
+ return relative2;
7690
7777
  }
7691
7778
  function shouldWatch(filePath, vaultPath2) {
7692
7779
  const normalized = normalizePath(filePath);
@@ -7820,30 +7907,30 @@ var EventQueue = class {
7820
7907
  * Add a new event to the queue
7821
7908
  */
7822
7909
  push(type, rawPath) {
7823
- const path39 = normalizePath(rawPath);
7910
+ const path40 = normalizePath(rawPath);
7824
7911
  const now = Date.now();
7825
7912
  const event = {
7826
7913
  type,
7827
- path: path39,
7914
+ path: path40,
7828
7915
  timestamp: now
7829
7916
  };
7830
- let pending = this.pending.get(path39);
7917
+ let pending = this.pending.get(path40);
7831
7918
  if (!pending) {
7832
7919
  pending = {
7833
7920
  events: [],
7834
7921
  timer: null,
7835
7922
  lastEvent: now
7836
7923
  };
7837
- this.pending.set(path39, pending);
7924
+ this.pending.set(path40, pending);
7838
7925
  }
7839
7926
  pending.events.push(event);
7840
7927
  pending.lastEvent = now;
7841
- console.error(`[flywheel] QUEUE: pushed ${type} for ${path39}, pending=${this.pending.size}`);
7928
+ console.error(`[flywheel] QUEUE: pushed ${type} for ${path40}, pending=${this.pending.size}`);
7842
7929
  if (pending.timer) {
7843
7930
  clearTimeout(pending.timer);
7844
7931
  }
7845
7932
  pending.timer = setTimeout(() => {
7846
- this.flushPath(path39);
7933
+ this.flushPath(path40);
7847
7934
  }, this.config.debounceMs);
7848
7935
  if (this.pending.size >= this.config.batchSize) {
7849
7936
  this.flush();
@@ -7864,10 +7951,10 @@ var EventQueue = class {
7864
7951
  /**
7865
7952
  * Flush a single path's events
7866
7953
  */
7867
- flushPath(path39) {
7868
- const pending = this.pending.get(path39);
7954
+ flushPath(path40) {
7955
+ const pending = this.pending.get(path40);
7869
7956
  if (!pending || pending.events.length === 0) return;
7870
- console.error(`[flywheel] QUEUE: flushing ${path39}, events=${pending.events.length}`);
7957
+ console.error(`[flywheel] QUEUE: flushing ${path40}, events=${pending.events.length}`);
7871
7958
  if (pending.timer) {
7872
7959
  clearTimeout(pending.timer);
7873
7960
  pending.timer = null;
@@ -7876,7 +7963,7 @@ var EventQueue = class {
7876
7963
  if (coalescedType) {
7877
7964
  const coalesced = {
7878
7965
  type: coalescedType,
7879
- path: path39,
7966
+ path: path40,
7880
7967
  originalEvents: [...pending.events]
7881
7968
  };
7882
7969
  this.onBatch({
@@ -7885,7 +7972,7 @@ var EventQueue = class {
7885
7972
  timestamp: Date.now()
7886
7973
  });
7887
7974
  }
7888
- this.pending.delete(path39);
7975
+ this.pending.delete(path40);
7889
7976
  }
7890
7977
  /**
7891
7978
  * Flush all pending events
@@ -7897,7 +7984,7 @@ var EventQueue = class {
7897
7984
  }
7898
7985
  if (this.pending.size === 0) return;
7899
7986
  const events = [];
7900
- for (const [path39, pending] of this.pending) {
7987
+ for (const [path40, pending] of this.pending) {
7901
7988
  if (pending.timer) {
7902
7989
  clearTimeout(pending.timer);
7903
7990
  }
@@ -7905,7 +7992,7 @@ var EventQueue = class {
7905
7992
  if (coalescedType) {
7906
7993
  events.push({
7907
7994
  type: coalescedType,
7908
- path: path39,
7995
+ path: path40,
7909
7996
  originalEvents: [...pending.events]
7910
7997
  });
7911
7998
  }
@@ -8099,8 +8186,8 @@ async function upsertNote(index, vaultPath2, notePath) {
8099
8186
  releasedKeys = removeNoteFromIndex(index, notePath);
8100
8187
  }
8101
8188
  const fullPath = path7.join(vaultPath2, notePath);
8102
- const fs35 = await import("fs/promises");
8103
- const stats = await fs35.stat(fullPath);
8189
+ const fs36 = await import("fs/promises");
8190
+ const stats = await fs36.stat(fullPath);
8104
8191
  const vaultFile = {
8105
8192
  path: notePath,
8106
8193
  absolutePath: fullPath,
@@ -8205,7 +8292,7 @@ async function processBatch(index, vaultPath2, batch, options = {}) {
8205
8292
  }
8206
8293
  onProgress?.(processed, total);
8207
8294
  if (processed % YIELD_INTERVAL === 0 && processed < total) {
8208
- await new Promise((resolve2) => setImmediate(resolve2));
8295
+ await new Promise((resolve3) => setImmediate(resolve3));
8209
8296
  }
8210
8297
  }
8211
8298
  const durationMs = Date.now() - startTime;
@@ -8297,31 +8384,31 @@ function createVaultWatcher(options) {
8297
8384
  usePolling: config2.usePolling,
8298
8385
  interval: config2.usePolling ? config2.pollInterval : void 0
8299
8386
  });
8300
- watcher.on("add", (path39) => {
8301
- console.error(`[flywheel] RAW EVENT: add ${path39}`);
8302
- if (shouldWatch(path39, vaultPath2)) {
8303
- console.error(`[flywheel] ACCEPTED: add ${path39}`);
8304
- eventQueue.push("add", path39);
8387
+ watcher.on("add", (path40) => {
8388
+ console.error(`[flywheel] RAW EVENT: add ${path40}`);
8389
+ if (shouldWatch(path40, vaultPath2)) {
8390
+ console.error(`[flywheel] ACCEPTED: add ${path40}`);
8391
+ eventQueue.push("add", path40);
8305
8392
  } else {
8306
- console.error(`[flywheel] FILTERED: add ${path39}`);
8393
+ console.error(`[flywheel] FILTERED: add ${path40}`);
8307
8394
  }
8308
8395
  });
8309
- watcher.on("change", (path39) => {
8310
- console.error(`[flywheel] RAW EVENT: change ${path39}`);
8311
- if (shouldWatch(path39, vaultPath2)) {
8312
- console.error(`[flywheel] ACCEPTED: change ${path39}`);
8313
- eventQueue.push("change", path39);
8396
+ watcher.on("change", (path40) => {
8397
+ console.error(`[flywheel] RAW EVENT: change ${path40}`);
8398
+ if (shouldWatch(path40, vaultPath2)) {
8399
+ console.error(`[flywheel] ACCEPTED: change ${path40}`);
8400
+ eventQueue.push("change", path40);
8314
8401
  } else {
8315
- console.error(`[flywheel] FILTERED: change ${path39}`);
8402
+ console.error(`[flywheel] FILTERED: change ${path40}`);
8316
8403
  }
8317
8404
  });
8318
- watcher.on("unlink", (path39) => {
8319
- console.error(`[flywheel] RAW EVENT: unlink ${path39}`);
8320
- if (shouldWatch(path39, vaultPath2)) {
8321
- console.error(`[flywheel] ACCEPTED: unlink ${path39}`);
8322
- eventQueue.push("unlink", path39);
8405
+ watcher.on("unlink", (path40) => {
8406
+ console.error(`[flywheel] RAW EVENT: unlink ${path40}`);
8407
+ if (shouldWatch(path40, vaultPath2)) {
8408
+ console.error(`[flywheel] ACCEPTED: unlink ${path40}`);
8409
+ eventQueue.push("unlink", path40);
8323
8410
  } else {
8324
- console.error(`[flywheel] FILTERED: unlink ${path39}`);
8411
+ console.error(`[flywheel] FILTERED: unlink ${path40}`);
8325
8412
  }
8326
8413
  });
8327
8414
  watcher.on("ready", () => {
@@ -11987,8 +12074,8 @@ function getNoteAccessFrequency(stateDb2, daysBack = 30) {
11987
12074
  }
11988
12075
  }
11989
12076
  }
11990
- return Array.from(noteMap.entries()).map(([path39, stats]) => ({
11991
- path: path39,
12077
+ return Array.from(noteMap.entries()).map(([path40, stats]) => ({
12078
+ path: path40,
11992
12079
  access_count: stats.access_count,
11993
12080
  last_accessed: stats.last_accessed,
11994
12081
  tools_used: Array.from(stats.tools)
@@ -12103,7 +12190,7 @@ init_recency();
12103
12190
  init_prospects();
12104
12191
  init_cooccurrence();
12105
12192
  init_retrievalCooccurrence();
12106
- import * as fs34 from "node:fs/promises";
12193
+ import * as fs35 from "node:fs/promises";
12107
12194
  import { createHash as createHash4 } from "node:crypto";
12108
12195
 
12109
12196
  // src/vault-registry.ts
@@ -12334,7 +12421,6 @@ var TOOL_CATEGORY = {
12334
12421
  get_common_neighbors: "graph",
12335
12422
  get_backlinks: "graph",
12336
12423
  get_forward_links: "graph",
12337
- get_weighted_links: "graph",
12338
12424
  get_strong_connections: "graph",
12339
12425
  // schema (7 tools) -- schema intelligence + migrations
12340
12426
  vault_schema: "schema",
@@ -12422,7 +12508,6 @@ var TOOL_TIER = {
12422
12508
  get_common_neighbors: 2,
12423
12509
  get_backlinks: 2,
12424
12510
  get_forward_links: 2,
12425
- get_weighted_links: 2,
12426
12511
  get_strong_connections: 2,
12427
12512
  suggest_wikilinks: 2,
12428
12513
  validate_links: 2,
@@ -12677,10 +12762,10 @@ Use "flywheel_config" to inspect runtime configuration and set "tool_tier_overri
12677
12762
  }
12678
12763
 
12679
12764
  // src/tool-registry.ts
12680
- import * as path37 from "path";
12765
+ import * as path38 from "path";
12681
12766
  import { dirname as dirname5, join as join18 } from "path";
12682
12767
  import { statSync as statSync6, readFileSync as readFileSync5 } from "fs";
12683
- import { fileURLToPath } from "url";
12768
+ import { fileURLToPath as fileURLToPath2 } from "url";
12684
12769
  import { z as z39 } from "zod";
12685
12770
  import { CallToolRequestSchema, ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
12686
12771
  import { getSessionId } from "@velvetmonkey/vault-core";
@@ -13029,13 +13114,13 @@ function multiHopBackfill(primaryResults, index, stateDb2, config2 = {}) {
13029
13114
  candidates.sort((a, b) => b.score - a.score);
13030
13115
  return candidates.slice(0, cfg.maxBackfill).map((c) => c.result);
13031
13116
  }
13032
- function scoreCandidate(path39, index, stateDb2) {
13033
- const note = index.notes.get(path39);
13117
+ function scoreCandidate(path40, index, stateDb2) {
13118
+ const note = index.notes.get(path40);
13034
13119
  const decay = recencyDecay(note?.modified);
13035
13120
  let hubScore = 1;
13036
13121
  if (stateDb2) {
13037
13122
  try {
13038
- const title = note?.title ?? path39.replace(/\.md$/, "").split("/").pop() ?? "";
13123
+ const title = note?.title ?? path40.replace(/\.md$/, "").split("/").pop() ?? "";
13039
13124
  const entity = getEntityByName3(stateDb2, title);
13040
13125
  if (entity) hubScore = entity.hubScore ?? 1;
13041
13126
  } catch {
@@ -13495,11 +13580,11 @@ function applyEntityBridging(results, stateDb2, maxBridgesPerResult = 5) {
13495
13580
  const linkMap = /* @__PURE__ */ new Map();
13496
13581
  try {
13497
13582
  const paths = results.map((r) => r.path).filter(Boolean);
13498
- for (const path39 of paths) {
13583
+ for (const path40 of paths) {
13499
13584
  const rows = stateDb2.db.prepare(
13500
13585
  "SELECT target FROM note_links WHERE note_path = ?"
13501
- ).all(path39);
13502
- linkMap.set(path39, new Set(rows.map((r) => r.target)));
13586
+ ).all(path40);
13587
+ linkMap.set(path40, new Set(rows.map((r) => r.target)));
13503
13588
  }
13504
13589
  } catch {
13505
13590
  return;
@@ -14639,50 +14724,6 @@ function registerGraphTools(server2, getIndex, getVaultPath, getStateDb4) {
14639
14724
  };
14640
14725
  }
14641
14726
  );
14642
- server2.tool(
14643
- "get_weighted_links",
14644
- "Use when ranking outgoing links from a note by relationship strength. Produces weighted link entries reflecting edge survival, co-session access, and source activity. Returns ranked outgoing links with weight scores. Does not include incoming links \u2014 use get_strong_connections for bidirectional.",
14645
- {
14646
- path: z2.string().describe('Path to the note (e.g., "daily/2026-02-24.md")'),
14647
- min_weight: z2.number().default(1).describe("Minimum weight threshold (default 1.0)"),
14648
- limit: z2.number().default(20).describe("Maximum number of results to return")
14649
- },
14650
- async ({ path: notePath, min_weight, limit: requestedLimit }) => {
14651
- const stateDb2 = getStateDb4?.();
14652
- if (!stateDb2) {
14653
- return { content: [{ type: "text", text: JSON.stringify({ error: "StateDb not initialized" }) }] };
14654
- }
14655
- const limit = Math.min(requestedLimit ?? 20, MAX_LIMIT);
14656
- const now = Date.now();
14657
- const rows = stateDb2.db.prepare(`
14658
- SELECT target, weight, weight_updated_at
14659
- FROM note_links
14660
- WHERE note_path = ?
14661
- ORDER BY weight DESC
14662
- `).all(notePath);
14663
- const results = rows.map((row) => {
14664
- const daysSinceUpdated = row.weight_updated_at ? (now - row.weight_updated_at) / (1e3 * 60 * 60 * 24) : 0;
14665
- const decayFactor = Math.max(0.1, 1 - daysSinceUpdated / 180);
14666
- const effectiveWeight = Math.round(row.weight * decayFactor * 1e3) / 1e3;
14667
- return {
14668
- target: row.target,
14669
- weight: row.weight,
14670
- weight_effective: effectiveWeight,
14671
- last_updated: row.weight_updated_at
14672
- };
14673
- }).filter((r) => r.weight_effective >= min_weight).slice(0, limit);
14674
- return {
14675
- content: [{
14676
- type: "text",
14677
- text: JSON.stringify({
14678
- note: notePath,
14679
- count: results.length,
14680
- links: results
14681
- }, null, 2)
14682
- }]
14683
- };
14684
- }
14685
- );
14686
14727
  server2.tool(
14687
14728
  "get_strong_connections",
14688
14729
  "Use when finding the most important relationships for a note in both directions. Produces bidirectional connections ranked by combined edge weight. Returns both incoming and outgoing links sorted by strength. Does not compute path distances \u2014 use get_link_path for shortest paths.",
@@ -15021,16 +15062,16 @@ function registerWikilinkTools(server2, getIndex, getVaultPath, getStateDb4 = ()
15021
15062
  const weightedStats = getWeightedEntityStats(stateDb3);
15022
15063
  const statsMap = new Map(weightedStats.map((s) => [s.entity.toLowerCase(), s]));
15023
15064
  for (const suggestion of scored.detailed) {
15024
- const stat5 = statsMap.get(suggestion.entity.toLowerCase());
15025
- if (stat5) {
15065
+ const stat4 = statsMap.get(suggestion.entity.toLowerCase());
15066
+ if (stat4) {
15026
15067
  const effectiveAlpha = isAiConfigEntity(suggestion.entity) ? AI_CONFIG_PRIOR_ALPHA : PRIOR_ALPHA;
15027
- const posteriorMean = computePosteriorMean(stat5.weightedCorrect, stat5.weightedFp, effectiveAlpha);
15028
- const totalObs = effectiveAlpha + stat5.weightedCorrect + PRIOR_BETA + stat5.weightedFp;
15068
+ const posteriorMean = computePosteriorMean(stat4.weightedCorrect, stat4.weightedFp, effectiveAlpha);
15069
+ const totalObs = effectiveAlpha + stat4.weightedCorrect + PRIOR_BETA + stat4.weightedFp;
15029
15070
  suggestion.suppressionContext = {
15030
15071
  posteriorMean: Math.round(posteriorMean * 1e3) / 1e3,
15031
15072
  totalObservations: Math.round(totalObs * 10) / 10,
15032
15073
  isSuppressed: totalObs >= SUPPRESSION_MIN_OBSERVATIONS && posteriorMean < SUPPRESSION_POSTERIOR_THRESHOLD,
15033
- falsePositiveRate: Math.round(stat5.weightedFpRate * 1e3) / 1e3
15074
+ falsePositiveRate: Math.round(stat4.weightedFpRate * 1e3) / 1e3
15034
15075
  };
15035
15076
  }
15036
15077
  }
@@ -15075,14 +15116,14 @@ function registerWikilinkTools(server2, getIndex, getVaultPath, getStateDb4 = ()
15075
15116
  };
15076
15117
  function findSimilarEntity2(target, entities) {
15077
15118
  const targetLower = target.toLowerCase();
15078
- for (const [name, path39] of entities) {
15119
+ for (const [name, path40] of entities) {
15079
15120
  if (name.startsWith(targetLower) || targetLower.startsWith(name)) {
15080
- return path39;
15121
+ return path40;
15081
15122
  }
15082
15123
  }
15083
- for (const [name, path39] of entities) {
15124
+ for (const [name, path40] of entities) {
15084
15125
  if (name.includes(targetLower) || targetLower.includes(name)) {
15085
- return path39;
15126
+ return path40;
15086
15127
  }
15087
15128
  }
15088
15129
  return void 0;
@@ -16102,8 +16143,8 @@ function registerHealthTools(server2, getIndex, getVaultPath, getConfig2 = () =>
16102
16143
  daily_counts: z4.record(z4.number())
16103
16144
  }).describe("Activity summary for the last 7 days")
16104
16145
  };
16105
- function isPeriodicNote3(path39) {
16106
- const filename = path39.split("/").pop() || "";
16146
+ function isPeriodicNote3(path40) {
16147
+ const filename = path40.split("/").pop() || "";
16107
16148
  const nameWithoutExt = filename.replace(/\.md$/, "");
16108
16149
  const patterns = [
16109
16150
  /^\d{4}-\d{2}-\d{2}$/,
@@ -16118,7 +16159,7 @@ function registerHealthTools(server2, getIndex, getVaultPath, getConfig2 = () =>
16118
16159
  // YYYY (yearly)
16119
16160
  ];
16120
16161
  const periodicFolders = ["daily", "weekly", "monthly", "quarterly", "yearly", "journal", "journals"];
16121
- const folder = path39.split("/")[0]?.toLowerCase() || "";
16162
+ const folder = path40.split("/")[0]?.toLowerCase() || "";
16122
16163
  return patterns.some((p) => p.test(nameWithoutExt)) || periodicFolders.includes(folder);
16123
16164
  }
16124
16165
  async function runVaultStats() {
@@ -17225,13 +17266,13 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig2 = ()
17225
17266
  max_content_chars: z6.number().default(2e4).describe("Max total chars of section content to include. Sections are truncated at paragraph boundaries.")
17226
17267
  }
17227
17268
  },
17228
- async ({ path: path39, include_content, max_content_chars }) => {
17269
+ async ({ path: path40, include_content, max_content_chars }) => {
17229
17270
  const index = getIndex();
17230
17271
  const vaultPath2 = getVaultPath();
17231
- const result = await getNoteStructure(index, path39, vaultPath2);
17272
+ const result = await getNoteStructure(index, path40, vaultPath2);
17232
17273
  if (!result) {
17233
17274
  return {
17234
- content: [{ type: "text", text: JSON.stringify({ error: "Note not found", path: path39 }, null, 2) }]
17275
+ content: [{ type: "text", text: JSON.stringify({ error: "Note not found", path: path40 }, null, 2) }]
17235
17276
  };
17236
17277
  }
17237
17278
  let totalChars = 0;
@@ -17242,7 +17283,7 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig2 = ()
17242
17283
  truncated = true;
17243
17284
  break;
17244
17285
  }
17245
- const sectionResult = await getSectionContent(index, path39, section.heading.text, vaultPath2, true);
17286
+ const sectionResult = await getSectionContent(index, path40, section.heading.text, vaultPath2, true);
17246
17287
  if (sectionResult) {
17247
17288
  let content = sectionResult.content;
17248
17289
  const remaining = max_content_chars - totalChars;
@@ -17257,13 +17298,13 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig2 = ()
17257
17298
  }
17258
17299
  }
17259
17300
  }
17260
- const note = index.notes.get(path39);
17301
+ const note = index.notes.get(path40);
17261
17302
  const enriched = { ...result };
17262
17303
  if (note) {
17263
17304
  enriched.frontmatter = note.frontmatter;
17264
17305
  enriched.tags = note.tags;
17265
17306
  enriched.aliases = note.aliases;
17266
- const normalizedPath = path39.toLowerCase().replace(/\.md$/, "");
17307
+ const normalizedPath = path40.toLowerCase().replace(/\.md$/, "");
17267
17308
  const backlinks = index.backlinks.get(normalizedPath) || [];
17268
17309
  enriched.backlink_count = backlinks.length;
17269
17310
  enriched.outlink_count = note.outlinks.length;
@@ -17301,15 +17342,15 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig2 = ()
17301
17342
  max_content_chars: z6.number().default(1e4).describe("Max chars of section content. Truncated at paragraph boundaries.")
17302
17343
  }
17303
17344
  },
17304
- async ({ path: path39, heading, include_subheadings, max_content_chars }) => {
17345
+ async ({ path: path40, heading, include_subheadings, max_content_chars }) => {
17305
17346
  const index = getIndex();
17306
17347
  const vaultPath2 = getVaultPath();
17307
- const result = await getSectionContent(index, path39, heading, vaultPath2, include_subheadings);
17348
+ const result = await getSectionContent(index, path40, heading, vaultPath2, include_subheadings);
17308
17349
  if (!result) {
17309
17350
  return {
17310
17351
  content: [{ type: "text", text: JSON.stringify({
17311
17352
  error: "Section not found",
17312
- path: path39,
17353
+ path: path40,
17313
17354
  heading
17314
17355
  }, null, 2) }]
17315
17356
  };
@@ -17370,16 +17411,16 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig2 = ()
17370
17411
  offset: z6.coerce.number().default(0).describe("Number of results to skip (for pagination)")
17371
17412
  }
17372
17413
  },
17373
- async ({ path: path39, status, has_due_date, folder, tag, limit: requestedLimit, offset }) => {
17414
+ async ({ path: path40, status, has_due_date, folder, tag, limit: requestedLimit, offset }) => {
17374
17415
  const limit = Math.min(requestedLimit ?? 25, MAX_LIMIT);
17375
17416
  const index = getIndex();
17376
17417
  const vaultPath2 = getVaultPath();
17377
17418
  const config2 = getConfig2();
17378
- if (path39) {
17379
- const result2 = await getTasksFromNote(index, path39, vaultPath2, getExcludeTags(config2));
17419
+ if (path40) {
17420
+ const result2 = await getTasksFromNote(index, path40, vaultPath2, getExcludeTags(config2));
17380
17421
  if (!result2) {
17381
17422
  return {
17382
- content: [{ type: "text", text: JSON.stringify({ error: "Note not found", path: path39 }, null, 2) }]
17423
+ content: [{ type: "text", text: JSON.stringify({ error: "Note not found", path: path40 }, null, 2) }]
17383
17424
  };
17384
17425
  }
17385
17426
  let filtered = result2;
@@ -17389,7 +17430,7 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig2 = ()
17389
17430
  const paged2 = filtered.slice(offset, offset + limit);
17390
17431
  return {
17391
17432
  content: [{ type: "text", text: JSON.stringify({
17392
- path: path39,
17433
+ path: path40,
17393
17434
  total_count: filtered.length,
17394
17435
  returned_count: paged2.length,
17395
17436
  open: result2.filter((t) => t.status === "open").length,
@@ -19371,8 +19412,8 @@ function registerNoteIntelligenceTools(server2, getIndex, getVaultPath, getConfi
19371
19412
  // src/tools/write/mutations.ts
19372
19413
  init_writer();
19373
19414
  import { z as z12 } from "zod";
19374
- import fs23 from "fs/promises";
19375
- import path25 from "path";
19415
+ import fs24 from "fs/promises";
19416
+ import path26 from "path";
19376
19417
 
19377
19418
  // src/core/write/validator.ts
19378
19419
  var TIMESTAMP_PATTERN = /^\*\*\d{2}:\d{2}\*\*/;
@@ -19590,63 +19631,63 @@ init_constants2();
19590
19631
  init_writer();
19591
19632
  init_wikilinks();
19592
19633
  init_wikilinkFeedback();
19593
- import fs22 from "fs/promises";
19594
- import path24 from "path";
19634
+ import fs23 from "fs/promises";
19635
+ import path25 from "path";
19595
19636
 
19596
19637
  // src/core/write/policy/policyPaths.ts
19597
- import fs21 from "fs/promises";
19598
- import path23 from "path";
19638
+ import fs22 from "fs/promises";
19639
+ import path24 from "path";
19599
19640
  function getPoliciesDir(vaultPath2) {
19600
- return path23.join(vaultPath2, ".flywheel", "policies");
19641
+ return path24.join(vaultPath2, ".flywheel", "policies");
19601
19642
  }
19602
19643
  function getLegacyPoliciesDir(vaultPath2) {
19603
- return path23.join(vaultPath2, ".claude", "policies");
19644
+ return path24.join(vaultPath2, ".claude", "policies");
19604
19645
  }
19605
19646
  async function ensurePoliciesDir(vaultPath2) {
19606
19647
  const dir = getPoliciesDir(vaultPath2);
19607
- await fs21.mkdir(dir, { recursive: true });
19648
+ await fs22.mkdir(dir, { recursive: true });
19608
19649
  }
19609
19650
  async function migratePoliciesIfNeeded(vaultPath2) {
19610
19651
  const legacyDir = getLegacyPoliciesDir(vaultPath2);
19611
19652
  let files;
19612
19653
  try {
19613
- files = await fs21.readdir(legacyDir);
19654
+ files = await fs22.readdir(legacyDir);
19614
19655
  } catch {
19615
19656
  return;
19616
19657
  }
19617
19658
  const yamlFiles = files.filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
19618
19659
  if (yamlFiles.length === 0) {
19619
19660
  await tryRmdir(legacyDir);
19620
- await tryRmdir(path23.join(vaultPath2, ".claude"));
19661
+ await tryRmdir(path24.join(vaultPath2, ".claude"));
19621
19662
  return;
19622
19663
  }
19623
19664
  await ensurePoliciesDir(vaultPath2);
19624
19665
  const destDir = getPoliciesDir(vaultPath2);
19625
19666
  for (const file of yamlFiles) {
19626
- const src = path23.join(legacyDir, file);
19627
- const dest = path23.join(destDir, file);
19667
+ const src = path24.join(legacyDir, file);
19668
+ const dest = path24.join(destDir, file);
19628
19669
  try {
19629
- await fs21.access(dest);
19670
+ await fs22.access(dest);
19630
19671
  } catch {
19631
- await fs21.copyFile(src, dest);
19672
+ await fs22.copyFile(src, dest);
19632
19673
  }
19633
- await fs21.unlink(src);
19674
+ await fs22.unlink(src);
19634
19675
  }
19635
19676
  await tryRmdir(legacyDir);
19636
- await tryRmdir(path23.join(vaultPath2, ".claude"));
19677
+ await tryRmdir(path24.join(vaultPath2, ".claude"));
19637
19678
  }
19638
19679
  async function tryRmdir(dir) {
19639
19680
  try {
19640
- const remaining = await fs21.readdir(dir);
19681
+ const remaining = await fs22.readdir(dir);
19641
19682
  if (remaining.length === 0) {
19642
- await fs21.rmdir(dir);
19683
+ await fs22.rmdir(dir);
19643
19684
  }
19644
19685
  } catch {
19645
19686
  }
19646
19687
  }
19647
19688
  var migrationCache = /* @__PURE__ */ new Map();
19648
19689
  async function ensureMigrated(vaultPath2) {
19649
- const key = path23.resolve(vaultPath2);
19690
+ const key = path24.resolve(vaultPath2);
19650
19691
  if (!migrationCache.has(key)) {
19651
19692
  migrationCache.set(key, migratePoliciesIfNeeded(vaultPath2));
19652
19693
  }
@@ -19702,7 +19743,7 @@ async function handleGitCommit(vaultPath2, notePath, commit, prefix) {
19702
19743
  async function getPolicyHint(vaultPath2) {
19703
19744
  try {
19704
19745
  const policiesDir = getPoliciesDir(vaultPath2);
19705
- const files = await fs22.readdir(policiesDir);
19746
+ const files = await fs23.readdir(policiesDir);
19706
19747
  const yamlFiles = files.filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
19707
19748
  if (yamlFiles.length > 0) {
19708
19749
  const names = yamlFiles.map((f) => f.replace(/\.ya?ml$/, "")).join(", ");
@@ -19713,9 +19754,9 @@ async function getPolicyHint(vaultPath2) {
19713
19754
  return "";
19714
19755
  }
19715
19756
  async function ensureFileExists(vaultPath2, notePath) {
19716
- const fullPath = path24.join(vaultPath2, notePath);
19757
+ const fullPath = path25.join(vaultPath2, notePath);
19717
19758
  try {
19718
- await fs22.access(fullPath);
19759
+ await fs23.access(fullPath);
19719
19760
  return null;
19720
19761
  } catch {
19721
19762
  const hint = await getPolicyHint(vaultPath2);
@@ -19918,17 +19959,17 @@ async function executeCreateNote(options) {
19918
19959
  if (!pathCheck.valid) {
19919
19960
  return { success: false, result: errorResult(notePath, `Path blocked: ${pathCheck.reason}`), filesWritten: [] };
19920
19961
  }
19921
- const fullPath = path24.join(vaultPath2, notePath);
19962
+ const fullPath = path25.join(vaultPath2, notePath);
19922
19963
  let fileExists = false;
19923
19964
  try {
19924
- await fs22.access(fullPath);
19965
+ await fs23.access(fullPath);
19925
19966
  fileExists = true;
19926
19967
  } catch {
19927
19968
  }
19928
19969
  if (fileExists && !overwrite) {
19929
19970
  return { success: false, result: errorResult(notePath, `File already exists: ${notePath}. Use overwrite=true to replace.`), filesWritten: [] };
19930
19971
  }
19931
- await fs22.mkdir(path24.dirname(fullPath), { recursive: true });
19972
+ await fs23.mkdir(path25.dirname(fullPath), { recursive: true });
19932
19973
  const { maybeApplyWikilinks: maybeApplyWikilinks2 } = await Promise.resolve().then(() => (init_wikilinks(), wikilinks_exports));
19933
19974
  const { content: processedContent } = maybeApplyWikilinks2(content, skipWikilinks ?? false, notePath);
19934
19975
  let finalFrontmatter = frontmatter;
@@ -19962,13 +20003,13 @@ async function executeDeleteNote(options) {
19962
20003
  if (!pathCheck.valid) {
19963
20004
  return { success: false, result: errorResult(notePath, `Path blocked: ${pathCheck.reason}`), filesWritten: [] };
19964
20005
  }
19965
- const fullPath = path24.join(vaultPath2, notePath);
20006
+ const fullPath = path25.join(vaultPath2, notePath);
19966
20007
  try {
19967
- await fs22.access(fullPath);
20008
+ await fs23.access(fullPath);
19968
20009
  } catch {
19969
20010
  return { success: false, result: errorResult(notePath, `File not found: ${notePath}`), filesWritten: [] };
19970
20011
  }
19971
- await fs22.unlink(fullPath);
20012
+ await fs23.unlink(fullPath);
19972
20013
  const result = successResult(notePath, `Deleted note: ${notePath}`, {});
19973
20014
  return { success: true, result, filesWritten: [notePath] };
19974
20015
  } catch (error) {
@@ -19986,10 +20027,10 @@ async function createNoteFromTemplate(vaultPath2, notePath, config2) {
19986
20027
  if (!validation.valid) {
19987
20028
  throw new Error(`Path blocked: ${validation.reason}`);
19988
20029
  }
19989
- const fullPath = path25.join(vaultPath2, notePath);
19990
- await fs23.mkdir(path25.dirname(fullPath), { recursive: true });
20030
+ const fullPath = path26.join(vaultPath2, notePath);
20031
+ await fs24.mkdir(path26.dirname(fullPath), { recursive: true });
19991
20032
  const templates = config2.templates || {};
19992
- const filename = path25.basename(notePath, ".md").toLowerCase();
20033
+ const filename = path26.basename(notePath, ".md").toLowerCase();
19993
20034
  let templatePath;
19994
20035
  let periodicType;
19995
20036
  const dailyPattern = /^\d{4}-\d{2}-\d{2}/;
@@ -20022,7 +20063,7 @@ async function createNoteFromTemplate(vaultPath2, notePath, config2) {
20022
20063
  ];
20023
20064
  for (const candidate of candidates) {
20024
20065
  try {
20025
- await fs23.access(path25.join(vaultPath2, candidate));
20066
+ await fs24.access(path26.join(vaultPath2, candidate));
20026
20067
  templatePath = candidate;
20027
20068
  console.error(`[Flywheel] Template not in config but found at ${candidate} \u2014 using it`);
20028
20069
  break;
@@ -20033,11 +20074,11 @@ async function createNoteFromTemplate(vaultPath2, notePath, config2) {
20033
20074
  let templateContent;
20034
20075
  if (templatePath) {
20035
20076
  try {
20036
- const absTemplatePath = path25.join(vaultPath2, templatePath);
20037
- templateContent = await fs23.readFile(absTemplatePath, "utf-8");
20077
+ const absTemplatePath = path26.join(vaultPath2, templatePath);
20078
+ templateContent = await fs24.readFile(absTemplatePath, "utf-8");
20038
20079
  } catch {
20039
20080
  console.error(`[Flywheel] Template at ${templatePath} not readable, using minimal fallback`);
20040
- const title = path25.basename(notePath, ".md");
20081
+ const title = path26.basename(notePath, ".md");
20041
20082
  templateContent = `---
20042
20083
  ---
20043
20084
 
@@ -20049,7 +20090,7 @@ async function createNoteFromTemplate(vaultPath2, notePath, config2) {
20049
20090
  if (periodicType) {
20050
20091
  console.error(`[Flywheel] No ${periodicType} template found in config or vault \u2014 using minimal fallback`);
20051
20092
  }
20052
- const title = path25.basename(notePath, ".md");
20093
+ const title = path26.basename(notePath, ".md");
20053
20094
  templateContent = `---
20054
20095
  ---
20055
20096
 
@@ -20058,7 +20099,7 @@ async function createNoteFromTemplate(vaultPath2, notePath, config2) {
20058
20099
  }
20059
20100
  const now = /* @__PURE__ */ new Date();
20060
20101
  const dateStr = now.toISOString().split("T")[0];
20061
- templateContent = templateContent.replace(/\{\{date\}\}/g, dateStr).replace(/\{\{title\}\}/g, path25.basename(notePath, ".md"));
20102
+ templateContent = templateContent.replace(/\{\{date\}\}/g, dateStr).replace(/\{\{title\}\}/g, path26.basename(notePath, ".md"));
20062
20103
  const matter9 = (await import("gray-matter")).default;
20063
20104
  const parsed = matter9(templateContent);
20064
20105
  if (!parsed.data.date) {
@@ -20097,9 +20138,9 @@ function registerMutationTools(server2, getVaultPath, getConfig2 = () => ({})) {
20097
20138
  let noteCreated = false;
20098
20139
  let templateUsed;
20099
20140
  if (create_if_missing && !dry_run) {
20100
- const fullPath = path25.join(vaultPath2, notePath);
20141
+ const fullPath = path26.join(vaultPath2, notePath);
20101
20142
  try {
20102
- await fs23.access(fullPath);
20143
+ await fs24.access(fullPath);
20103
20144
  } catch {
20104
20145
  const config2 = getConfig2();
20105
20146
  const result = await createNoteFromTemplate(vaultPath2, notePath, config2);
@@ -20108,9 +20149,9 @@ function registerMutationTools(server2, getVaultPath, getConfig2 = () => ({})) {
20108
20149
  }
20109
20150
  }
20110
20151
  if (create_if_missing && dry_run) {
20111
- const fullPath = path25.join(vaultPath2, notePath);
20152
+ const fullPath = path26.join(vaultPath2, notePath);
20112
20153
  try {
20113
- await fs23.access(fullPath);
20154
+ await fs24.access(fullPath);
20114
20155
  } catch {
20115
20156
  return {
20116
20157
  content: [{
@@ -20594,8 +20635,8 @@ function registerFrontmatterTools(server2, getVaultPath) {
20594
20635
  init_writer();
20595
20636
  init_wikilinks();
20596
20637
  import { z as z15 } from "zod";
20597
- import fs24 from "fs/promises";
20598
- import path26 from "path";
20638
+ import fs25 from "fs/promises";
20639
+ import path27 from "path";
20599
20640
  function registerNoteTools(server2, getVaultPath, getIndex) {
20600
20641
  server2.tool(
20601
20642
  "vault_create_note",
@@ -20621,23 +20662,23 @@ function registerNoteTools(server2, getVaultPath, getIndex) {
20621
20662
  if (!validatePath(vaultPath2, notePath)) {
20622
20663
  return formatMcpResult(errorResult(notePath, "Invalid path: path traversal not allowed"));
20623
20664
  }
20624
- const fullPath = path26.join(vaultPath2, notePath);
20665
+ const fullPath = path27.join(vaultPath2, notePath);
20625
20666
  const existsCheck = await ensureFileExists(vaultPath2, notePath);
20626
20667
  if (existsCheck === null && !overwrite) {
20627
20668
  return formatMcpResult(errorResult(notePath, `File already exists: ${notePath}. Use overwrite=true to replace.`));
20628
20669
  }
20629
- const dir = path26.dirname(fullPath);
20630
- await fs24.mkdir(dir, { recursive: true });
20670
+ const dir = path27.dirname(fullPath);
20671
+ await fs25.mkdir(dir, { recursive: true });
20631
20672
  let effectiveContent = content;
20632
20673
  let effectiveFrontmatter = frontmatter;
20633
20674
  if (template) {
20634
- const templatePath = path26.join(vaultPath2, template);
20675
+ const templatePath = path27.join(vaultPath2, template);
20635
20676
  try {
20636
- const raw = await fs24.readFile(templatePath, "utf-8");
20677
+ const raw = await fs25.readFile(templatePath, "utf-8");
20637
20678
  const matter9 = (await import("gray-matter")).default;
20638
20679
  const parsed = matter9(raw);
20639
20680
  const dateStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
20640
- const title = path26.basename(notePath, ".md");
20681
+ const title = path27.basename(notePath, ".md");
20641
20682
  let templateContent = parsed.content.replace(/\{\{date\}\}/g, dateStr).replace(/\{\{title\}\}/g, title);
20642
20683
  if (content) {
20643
20684
  templateContent = templateContent.trimEnd() + "\n\n" + content;
@@ -20656,7 +20697,7 @@ function registerNoteTools(server2, getVaultPath, getIndex) {
20656
20697
  effectiveFrontmatter.created = now.toISOString();
20657
20698
  }
20658
20699
  const warnings = [];
20659
- const noteName = path26.basename(notePath, ".md");
20700
+ const noteName = path27.basename(notePath, ".md");
20660
20701
  const existingAliases = Array.isArray(effectiveFrontmatter?.aliases) ? effectiveFrontmatter.aliases.filter((a) => typeof a === "string") : [];
20661
20702
  const preflight = await checkPreflightSimilarity(noteName);
20662
20703
  if (preflight.existingEntity) {
@@ -20797,8 +20838,8 @@ ${sources}`;
20797
20838
  }
20798
20839
  return formatMcpResult(errorResult(notePath, previewLines.join("\n")));
20799
20840
  }
20800
- const fullPath = path26.join(vaultPath2, notePath);
20801
- await fs24.unlink(fullPath);
20841
+ const fullPath = path27.join(vaultPath2, notePath);
20842
+ await fs25.unlink(fullPath);
20802
20843
  const gitInfo = await handleGitCommit(vaultPath2, notePath, commit, "[Flywheel:Delete]");
20803
20844
  const message = backlinkWarning ? `Deleted note: ${notePath}
20804
20845
 
@@ -20818,8 +20859,8 @@ init_writer();
20818
20859
  init_git();
20819
20860
  init_wikilinks();
20820
20861
  import { z as z16 } from "zod";
20821
- import fs25 from "fs/promises";
20822
- import path27 from "path";
20862
+ import fs26 from "fs/promises";
20863
+ import path28 from "path";
20823
20864
  import matter6 from "gray-matter";
20824
20865
  function escapeRegex(str) {
20825
20866
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -20838,16 +20879,16 @@ function extractWikilinks2(content) {
20838
20879
  return wikilinks;
20839
20880
  }
20840
20881
  function getTitleFromPath(filePath) {
20841
- return path27.basename(filePath, ".md");
20882
+ return path28.basename(filePath, ".md");
20842
20883
  }
20843
20884
  async function findBacklinks(vaultPath2, targetTitle, targetAliases) {
20844
20885
  const results = [];
20845
20886
  const allTargets = [targetTitle, ...targetAliases].map((t) => t.toLowerCase());
20846
20887
  async function scanDir(dir) {
20847
20888
  const files = [];
20848
- const entries = await fs25.readdir(dir, { withFileTypes: true });
20889
+ const entries = await fs26.readdir(dir, { withFileTypes: true });
20849
20890
  for (const entry of entries) {
20850
- const fullPath = path27.join(dir, entry.name);
20891
+ const fullPath = path28.join(dir, entry.name);
20851
20892
  if (entry.isDirectory() && !entry.name.startsWith(".")) {
20852
20893
  files.push(...await scanDir(fullPath));
20853
20894
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -20858,8 +20899,8 @@ async function findBacklinks(vaultPath2, targetTitle, targetAliases) {
20858
20899
  }
20859
20900
  const allFiles = await scanDir(vaultPath2);
20860
20901
  for (const filePath of allFiles) {
20861
- const relativePath = path27.relative(vaultPath2, filePath);
20862
- const content = await fs25.readFile(filePath, "utf-8");
20902
+ const relativePath = path28.relative(vaultPath2, filePath);
20903
+ const content = await fs26.readFile(filePath, "utf-8");
20863
20904
  const wikilinks = extractWikilinks2(content);
20864
20905
  const matchingLinks = [];
20865
20906
  for (const link of wikilinks) {
@@ -20945,10 +20986,10 @@ function registerMoveNoteTools(server2, getVaultPath) {
20945
20986
  };
20946
20987
  return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
20947
20988
  }
20948
- const oldFullPath = path27.join(vaultPath2, oldPath);
20949
- const newFullPath = path27.join(vaultPath2, newPath);
20989
+ const oldFullPath = path28.join(vaultPath2, oldPath);
20990
+ const newFullPath = path28.join(vaultPath2, newPath);
20950
20991
  try {
20951
- await fs25.access(oldFullPath);
20992
+ await fs26.access(oldFullPath);
20952
20993
  } catch {
20953
20994
  const result2 = {
20954
20995
  success: false,
@@ -20958,7 +20999,7 @@ function registerMoveNoteTools(server2, getVaultPath) {
20958
20999
  return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
20959
21000
  }
20960
21001
  try {
20961
- await fs25.access(newFullPath);
21002
+ await fs26.access(newFullPath);
20962
21003
  const result2 = {
20963
21004
  success: false,
20964
21005
  message: `Destination already exists: ${newPath}`,
@@ -20967,7 +21008,7 @@ function registerMoveNoteTools(server2, getVaultPath) {
20967
21008
  return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
20968
21009
  } catch {
20969
21010
  }
20970
- const sourceContent = await fs25.readFile(oldFullPath, "utf-8");
21011
+ const sourceContent = await fs26.readFile(oldFullPath, "utf-8");
20971
21012
  const parsed = matter6(sourceContent);
20972
21013
  const aliases = extractAliases2(parsed.data);
20973
21014
  const oldTitle = getTitleFromPath(oldPath);
@@ -21027,9 +21068,9 @@ function registerMoveNoteTools(server2, getVaultPath) {
21027
21068
  };
21028
21069
  return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
21029
21070
  }
21030
- const destDir = path27.dirname(newFullPath);
21031
- await fs25.mkdir(destDir, { recursive: true });
21032
- await fs25.rename(oldFullPath, newFullPath);
21071
+ const destDir = path28.dirname(newFullPath);
21072
+ await fs26.mkdir(destDir, { recursive: true });
21073
+ await fs26.rename(oldFullPath, newFullPath);
21033
21074
  let gitCommit;
21034
21075
  let undoAvailable;
21035
21076
  let staleLockDetected;
@@ -21103,12 +21144,12 @@ function registerMoveNoteTools(server2, getVaultPath) {
21103
21144
  if (sanitizedTitle !== newTitle) {
21104
21145
  console.error(`[Flywheel] Title sanitized: "${newTitle}" \u2192 "${sanitizedTitle}"`);
21105
21146
  }
21106
- const fullPath = path27.join(vaultPath2, notePath);
21107
- const dir = path27.dirname(notePath);
21108
- const newPath = dir === "." ? `${sanitizedTitle}.md` : path27.join(dir, `${sanitizedTitle}.md`);
21109
- const newFullPath = path27.join(vaultPath2, newPath);
21147
+ const fullPath = path28.join(vaultPath2, notePath);
21148
+ const dir = path28.dirname(notePath);
21149
+ const newPath = dir === "." ? `${sanitizedTitle}.md` : path28.join(dir, `${sanitizedTitle}.md`);
21150
+ const newFullPath = path28.join(vaultPath2, newPath);
21110
21151
  try {
21111
- await fs25.access(fullPath);
21152
+ await fs26.access(fullPath);
21112
21153
  } catch {
21113
21154
  const result2 = {
21114
21155
  success: false,
@@ -21119,7 +21160,7 @@ function registerMoveNoteTools(server2, getVaultPath) {
21119
21160
  }
21120
21161
  if (fullPath !== newFullPath) {
21121
21162
  try {
21122
- await fs25.access(newFullPath);
21163
+ await fs26.access(newFullPath);
21123
21164
  const result2 = {
21124
21165
  success: false,
21125
21166
  message: `A note with this title already exists: ${newPath}`,
@@ -21129,7 +21170,7 @@ function registerMoveNoteTools(server2, getVaultPath) {
21129
21170
  } catch {
21130
21171
  }
21131
21172
  }
21132
- const sourceContent = await fs25.readFile(fullPath, "utf-8");
21173
+ const sourceContent = await fs26.readFile(fullPath, "utf-8");
21133
21174
  const parsed = matter6(sourceContent);
21134
21175
  const aliases = extractAliases2(parsed.data);
21135
21176
  const oldTitle = getTitleFromPath(notePath);
@@ -21189,7 +21230,7 @@ function registerMoveNoteTools(server2, getVaultPath) {
21189
21230
  return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
21190
21231
  }
21191
21232
  if (fullPath !== newFullPath) {
21192
- await fs25.rename(fullPath, newFullPath);
21233
+ await fs26.rename(fullPath, newFullPath);
21193
21234
  }
21194
21235
  let gitCommit;
21195
21236
  let undoAvailable;
@@ -21237,8 +21278,8 @@ function registerMoveNoteTools(server2, getVaultPath) {
21237
21278
  init_writer();
21238
21279
  init_wikilinks();
21239
21280
  import { z as z17 } from "zod";
21240
- import fs26 from "fs/promises";
21241
- import path28 from "path";
21281
+ import fs27 from "fs/promises";
21282
+ import path29 from "path";
21242
21283
  function registerMergeTools(server2, getVaultPath) {
21243
21284
  server2.tool(
21244
21285
  "merge_entities",
@@ -21365,7 +21406,7 @@ ${trimmedSource}`;
21365
21406
  }
21366
21407
  await writeVaultFile(vaultPath2, target_path, targetContent, targetFrontmatter, "LF", targetContentHash);
21367
21408
  const fullSourcePath = `${vaultPath2}/${source_path}`;
21368
- await fs26.unlink(fullSourcePath);
21409
+ await fs27.unlink(fullSourcePath);
21369
21410
  initializeEntityIndex(vaultPath2).catch((err) => {
21370
21411
  console.error(`[Flywheel] Entity cache rebuild failed: ${err}`);
21371
21412
  });
@@ -21480,7 +21521,7 @@ ${trimmedSource}`;
21480
21521
  }
21481
21522
  let sourceDeleted = false;
21482
21523
  if (sourceNoteFile) {
21483
- await fs26.unlink(`${vaultPath2}/${sourceNoteFile}`);
21524
+ await fs27.unlink(`${vaultPath2}/${sourceNoteFile}`);
21484
21525
  sourceDeleted = true;
21485
21526
  }
21486
21527
  initializeEntityIndex(vaultPath2).catch((err) => {
@@ -21529,21 +21570,21 @@ async function findSourceNote(vaultPath2, sourceName, excludePath) {
21529
21570
  async function scanDir(dir) {
21530
21571
  let entries;
21531
21572
  try {
21532
- entries = await fs26.readdir(dir, { withFileTypes: true });
21573
+ entries = await fs27.readdir(dir, { withFileTypes: true });
21533
21574
  } catch {
21534
21575
  return null;
21535
21576
  }
21536
21577
  for (const entry of entries) {
21537
21578
  if (entry.name.startsWith(".")) continue;
21538
- const fullPath = path28.join(dir, entry.name);
21579
+ const fullPath = path29.join(dir, entry.name);
21539
21580
  if (entry.isDirectory()) {
21540
21581
  const found = await scanDir(fullPath);
21541
21582
  if (found) return found;
21542
21583
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
21543
- const basename5 = path28.basename(entry.name, ".md");
21584
+ const basename5 = path29.basename(entry.name, ".md");
21544
21585
  if (basename5.toLowerCase() === targetLower) {
21545
- const relative3 = path28.relative(vaultPath2, fullPath).replace(/\\/g, "/");
21546
- if (relative3 !== excludePath) return relative3;
21586
+ const relative2 = path29.relative(vaultPath2, fullPath).replace(/\\/g, "/");
21587
+ if (relative2 !== excludePath) return relative2;
21547
21588
  }
21548
21589
  }
21549
21590
  }
@@ -21663,7 +21704,7 @@ Message: ${undoResult.undoneCommit.message}` : void 0
21663
21704
  }
21664
21705
 
21665
21706
  // src/tools/write/policy.ts
21666
- import * as path33 from "path";
21707
+ import * as path34 from "path";
21667
21708
  import { z as z20 } from "zod";
21668
21709
 
21669
21710
  // src/core/write/policy/index.ts
@@ -21672,8 +21713,8 @@ init_schema();
21672
21713
 
21673
21714
  // src/core/write/policy/parser.ts
21674
21715
  init_schema();
21675
- import fs27 from "fs/promises";
21676
- import path29 from "path";
21716
+ import fs28 from "fs/promises";
21717
+ import path30 from "path";
21677
21718
  import matter7 from "gray-matter";
21678
21719
  function parseYaml(content) {
21679
21720
  const parsed = matter7(`---
@@ -21698,7 +21739,7 @@ function parsePolicyString(yamlContent) {
21698
21739
  }
21699
21740
  async function loadPolicyFile(filePath) {
21700
21741
  try {
21701
- const content = await fs27.readFile(filePath, "utf-8");
21742
+ const content = await fs28.readFile(filePath, "utf-8");
21702
21743
  return parsePolicyString(content);
21703
21744
  } catch (error) {
21704
21745
  if (error.code === "ENOENT") {
@@ -21724,14 +21765,14 @@ async function loadPolicyFile(filePath) {
21724
21765
  async function loadPolicy(vaultPath2, policyName) {
21725
21766
  await ensureMigrated(vaultPath2);
21726
21767
  const policiesDir = getPoliciesDir(vaultPath2);
21727
- const policyPath = path29.join(policiesDir, `${policyName}.yaml`);
21768
+ const policyPath = path30.join(policiesDir, `${policyName}.yaml`);
21728
21769
  try {
21729
- await fs27.access(policyPath);
21770
+ await fs28.access(policyPath);
21730
21771
  return loadPolicyFile(policyPath);
21731
21772
  } catch {
21732
- const ymlPath = path29.join(policiesDir, `${policyName}.yml`);
21773
+ const ymlPath = path30.join(policiesDir, `${policyName}.yml`);
21733
21774
  try {
21734
- await fs27.access(ymlPath);
21775
+ await fs28.access(ymlPath);
21735
21776
  return loadPolicyFile(ymlPath);
21736
21777
  } catch {
21737
21778
  return {
@@ -21871,8 +21912,8 @@ init_schema();
21871
21912
  init_writer();
21872
21913
  init_git();
21873
21914
  init_wikilinks();
21874
- import fs29 from "fs/promises";
21875
- import path31 from "path";
21915
+ import fs30 from "fs/promises";
21916
+ import path32 from "path";
21876
21917
  init_constants2();
21877
21918
  async function executeStep(step, vaultPath2, context, conditionResults, searchFn) {
21878
21919
  const { execute, reason } = shouldStepExecute(step.when, conditionResults);
@@ -22063,12 +22104,12 @@ async function executeCreateNote2(params, vaultPath2, context) {
22063
22104
  let frontmatter = params.frontmatter || {};
22064
22105
  if (params.template) {
22065
22106
  try {
22066
- const templatePath = path31.join(vaultPath2, String(params.template));
22067
- const raw = await fs29.readFile(templatePath, "utf-8");
22107
+ const templatePath = path32.join(vaultPath2, String(params.template));
22108
+ const raw = await fs30.readFile(templatePath, "utf-8");
22068
22109
  const matter9 = (await import("gray-matter")).default;
22069
22110
  const parsed = matter9(raw);
22070
22111
  const dateStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
22071
- const title = path31.basename(notePath, ".md");
22112
+ const title = path32.basename(notePath, ".md");
22072
22113
  let templateContent = parsed.content.replace(/\{\{date\}\}/g, dateStr).replace(/\{\{title\}\}/g, title);
22073
22114
  if (content) {
22074
22115
  templateContent = templateContent.trimEnd() + "\n\n" + content;
@@ -22101,9 +22142,9 @@ async function executeToggleTask(params, vaultPath2) {
22101
22142
  const notePath = String(params.path || "");
22102
22143
  const task = String(params.task || "");
22103
22144
  const section = params.section ? String(params.section) : void 0;
22104
- const fullPath = path31.join(vaultPath2, notePath);
22145
+ const fullPath = path32.join(vaultPath2, notePath);
22105
22146
  try {
22106
- await fs29.access(fullPath);
22147
+ await fs30.access(fullPath);
22107
22148
  } catch {
22108
22149
  return { success: false, message: `File not found: ${notePath}`, path: notePath };
22109
22150
  }
@@ -22384,15 +22425,15 @@ async function rollbackChanges(vaultPath2, originalContents, filesModified) {
22384
22425
  const pathCheck = await validatePathSecure(vaultPath2, filePath);
22385
22426
  if (!pathCheck.valid) continue;
22386
22427
  const original = originalContents.get(filePath);
22387
- const fullPath = path31.join(vaultPath2, filePath);
22428
+ const fullPath = path32.join(vaultPath2, filePath);
22388
22429
  if (original === null) {
22389
22430
  try {
22390
- await fs29.unlink(fullPath);
22431
+ await fs30.unlink(fullPath);
22391
22432
  } catch {
22392
22433
  }
22393
22434
  } else if (original !== void 0) {
22394
22435
  try {
22395
- await fs29.writeFile(fullPath, original);
22436
+ await fs30.writeFile(fullPath, original);
22396
22437
  } catch {
22397
22438
  }
22398
22439
  }
@@ -22438,27 +22479,27 @@ async function previewPolicy(policy, vaultPath2, variables) {
22438
22479
  }
22439
22480
 
22440
22481
  // src/core/write/policy/storage.ts
22441
- import fs30 from "fs/promises";
22442
- import path32 from "path";
22482
+ import fs31 from "fs/promises";
22483
+ import path33 from "path";
22443
22484
  async function listPolicies(vaultPath2) {
22444
22485
  await ensureMigrated(vaultPath2);
22445
22486
  const dir = getPoliciesDir(vaultPath2);
22446
22487
  const policies = [];
22447
22488
  try {
22448
- const files = await fs30.readdir(dir);
22489
+ const files = await fs31.readdir(dir);
22449
22490
  for (const file of files) {
22450
22491
  if (!file.endsWith(".yaml") && !file.endsWith(".yml")) {
22451
22492
  continue;
22452
22493
  }
22453
- const filePath = path32.join(dir, file);
22454
- const stat5 = await fs30.stat(filePath);
22455
- const content = await fs30.readFile(filePath, "utf-8");
22494
+ const filePath = path33.join(dir, file);
22495
+ const stat4 = await fs31.stat(filePath);
22496
+ const content = await fs31.readFile(filePath, "utf-8");
22456
22497
  const metadata = extractPolicyMetadata(content);
22457
22498
  policies.push({
22458
22499
  name: metadata.name || file.replace(/\.ya?ml$/, ""),
22459
22500
  description: metadata.description || "No description",
22460
22501
  path: file,
22461
- lastModified: stat5.mtime,
22502
+ lastModified: stat4.mtime,
22462
22503
  version: metadata.version || "1.0",
22463
22504
  requiredVariables: metadata.variables || []
22464
22505
  });
@@ -22476,10 +22517,10 @@ async function writePolicyRaw(vaultPath2, policyName, content, overwrite = false
22476
22517
  const dir = getPoliciesDir(vaultPath2);
22477
22518
  await ensurePoliciesDir(vaultPath2);
22478
22519
  const filename = `${policyName}.yaml`;
22479
- const filePath = path32.join(dir, filename);
22520
+ const filePath = path33.join(dir, filename);
22480
22521
  if (!overwrite) {
22481
22522
  try {
22482
- await fs30.access(filePath);
22523
+ await fs31.access(filePath);
22483
22524
  return {
22484
22525
  success: false,
22485
22526
  path: filename,
@@ -22496,7 +22537,7 @@ async function writePolicyRaw(vaultPath2, policyName, content, overwrite = false
22496
22537
  message: `Invalid policy: ${validation.errors.map((e) => e.message).join("; ")}`
22497
22538
  };
22498
22539
  }
22499
- await fs30.writeFile(filePath, content, "utf-8");
22540
+ await fs31.writeFile(filePath, content, "utf-8");
22500
22541
  return {
22501
22542
  success: true,
22502
22543
  path: filename,
@@ -22590,7 +22631,7 @@ function registerPolicyTools(server2, getVaultPath, getSearchFn) {
22590
22631
  const policies = await listPolicies(vaultPath2);
22591
22632
  const response = {
22592
22633
  success: true,
22593
- vault: path33.basename(vaultPath2),
22634
+ vault: path34.basename(vaultPath2),
22594
22635
  vault_path: vaultPath2,
22595
22636
  count: policies.length,
22596
22637
  policies: policies.map((p) => ({
@@ -23023,8 +23064,8 @@ function registerPolicyTools(server2, getVaultPath, getSearchFn) {
23023
23064
  import { z as z21 } from "zod";
23024
23065
 
23025
23066
  // src/core/write/tagRename.ts
23026
- import * as fs31 from "fs/promises";
23027
- import * as path34 from "path";
23067
+ import * as fs32 from "fs/promises";
23068
+ import * as path35 from "path";
23028
23069
  import matter8 from "gray-matter";
23029
23070
  import { getProtectedZones as getProtectedZones2 } from "@velvetmonkey/vault-core";
23030
23071
  function getNotesInFolder3(index, folder) {
@@ -23130,10 +23171,10 @@ async function renameTag(index, vaultPath2, oldTag, newTag, options) {
23130
23171
  const previews = [];
23131
23172
  let totalChanges = 0;
23132
23173
  for (const note of affectedNotes) {
23133
- const fullPath = path34.join(vaultPath2, note.path);
23174
+ const fullPath = path35.join(vaultPath2, note.path);
23134
23175
  let fileContent;
23135
23176
  try {
23136
- fileContent = await fs31.readFile(fullPath, "utf-8");
23177
+ fileContent = await fs32.readFile(fullPath, "utf-8");
23137
23178
  } catch {
23138
23179
  continue;
23139
23180
  }
@@ -23206,7 +23247,7 @@ async function renameTag(index, vaultPath2, oldTag, newTag, options) {
23206
23247
  previews.push(preview);
23207
23248
  if (!dryRun) {
23208
23249
  const newContent = matter8.stringify(updatedContent, fm);
23209
- await fs31.writeFile(fullPath, newContent, "utf-8");
23250
+ await fs32.writeFile(fullPath, newContent, "utf-8");
23210
23251
  }
23211
23252
  }
23212
23253
  }
@@ -24259,8 +24300,8 @@ function registerConfigTools(server2, getConfig2, setConfig, getStateDb4) {
24259
24300
  init_wikilinks();
24260
24301
  init_wikilinkFeedback();
24261
24302
  import { z as z28 } from "zod";
24262
- import * as fs32 from "fs/promises";
24263
- import * as path35 from "path";
24303
+ import * as fs33 from "fs/promises";
24304
+ import * as path36 from "path";
24264
24305
  import { scanVaultEntities as scanVaultEntities4, SCHEMA_VERSION as SCHEMA_VERSION2 } from "@velvetmonkey/vault-core";
24265
24306
  init_embeddings();
24266
24307
  function hasSkipWikilinks(content) {
@@ -24273,16 +24314,16 @@ function hasSkipWikilinks(content) {
24273
24314
  async function collectMarkdownFiles(dirPath, basePath, excludeFolders) {
24274
24315
  const results = [];
24275
24316
  try {
24276
- const entries = await fs32.readdir(dirPath, { withFileTypes: true });
24317
+ const entries = await fs33.readdir(dirPath, { withFileTypes: true });
24277
24318
  for (const entry of entries) {
24278
24319
  if (entry.name.startsWith(".")) continue;
24279
- const fullPath = path35.join(dirPath, entry.name);
24320
+ const fullPath = path36.join(dirPath, entry.name);
24280
24321
  if (entry.isDirectory()) {
24281
24322
  if (excludeFolders.some((f) => entry.name.toLowerCase() === f.toLowerCase())) continue;
24282
24323
  const sub = await collectMarkdownFiles(fullPath, basePath, excludeFolders);
24283
24324
  results.push(...sub);
24284
24325
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
24285
- results.push(path35.relative(basePath, fullPath));
24326
+ results.push(path36.relative(basePath, fullPath));
24286
24327
  }
24287
24328
  }
24288
24329
  } catch {
@@ -24312,7 +24353,7 @@ var EXCLUDE_FOLDERS = [
24312
24353
  ];
24313
24354
  function buildStatusReport(stateDb2, vaultPath2) {
24314
24355
  const recommendations = [];
24315
- const dbPath = path35.join(vaultPath2, ".flywheel", "state.db");
24356
+ const dbPath = path36.join(vaultPath2, ".flywheel", "state.db");
24316
24357
  const statedbExists = stateDb2 !== null;
24317
24358
  if (!statedbExists) {
24318
24359
  recommendations.push("StateDb not initialized \u2014 server needs restart");
@@ -24439,10 +24480,10 @@ async function executeRun(stateDb2, vaultPath2) {
24439
24480
  const allFiles = await collectMarkdownFiles(vaultPath2, vaultPath2, EXCLUDE_FOLDERS);
24440
24481
  let eligible = 0;
24441
24482
  for (const relativePath of allFiles) {
24442
- const fullPath = path35.join(vaultPath2, relativePath);
24483
+ const fullPath = path36.join(vaultPath2, relativePath);
24443
24484
  let content;
24444
24485
  try {
24445
- content = await fs32.readFile(fullPath, "utf-8");
24486
+ content = await fs33.readFile(fullPath, "utf-8");
24446
24487
  } catch {
24447
24488
  continue;
24448
24489
  }
@@ -24497,10 +24538,10 @@ async function executeEnrich(stateDb2, vaultPath2, dryRun, batchSize, offset) {
24497
24538
  const eligible = [];
24498
24539
  let notesSkipped = 0;
24499
24540
  for (const relativePath of allFiles) {
24500
- const fullPath = path35.join(vaultPath2, relativePath);
24541
+ const fullPath = path36.join(vaultPath2, relativePath);
24501
24542
  let content;
24502
24543
  try {
24503
- content = await fs32.readFile(fullPath, "utf-8");
24544
+ content = await fs33.readFile(fullPath, "utf-8");
24504
24545
  } catch {
24505
24546
  continue;
24506
24547
  }
@@ -24527,8 +24568,8 @@ async function executeEnrich(stateDb2, vaultPath2, dryRun, batchSize, offset) {
24527
24568
  match_count: result.linksAdded
24528
24569
  });
24529
24570
  if (!dryRun) {
24530
- const fullPath = path35.join(vaultPath2, relativePath);
24531
- await fs32.writeFile(fullPath, result.content, "utf-8");
24571
+ const fullPath = path36.join(vaultPath2, relativePath);
24572
+ await fs33.writeFile(fullPath, result.content, "utf-8");
24532
24573
  notesModified++;
24533
24574
  if (stateDb2) {
24534
24575
  trackWikilinkApplications(stateDb2, relativePath, entities, "enrichment");
@@ -24705,8 +24746,8 @@ function registerMetricsTools(server2, getIndex, getStateDb4) {
24705
24746
  import { z as z30 } from "zod";
24706
24747
 
24707
24748
  // src/core/read/similarity.ts
24708
- import * as fs33 from "fs";
24709
- import * as path36 from "path";
24749
+ import * as fs34 from "fs";
24750
+ import * as path37 from "path";
24710
24751
  init_embeddings();
24711
24752
 
24712
24753
  // src/core/read/mmr.ts
@@ -24776,10 +24817,10 @@ function extractKeyTerms(content, maxTerms = 15) {
24776
24817
  }
24777
24818
  function findSimilarNotes(db4, vaultPath2, index, sourcePath, options = {}) {
24778
24819
  const limit = options.limit ?? 10;
24779
- const absPath = path36.join(vaultPath2, sourcePath);
24820
+ const absPath = path37.join(vaultPath2, sourcePath);
24780
24821
  let content;
24781
24822
  try {
24782
- content = fs33.readFileSync(absPath, "utf-8");
24823
+ content = fs34.readFileSync(absPath, "utf-8");
24783
24824
  } catch {
24784
24825
  return [];
24785
24826
  }
@@ -24918,7 +24959,7 @@ function registerSimilarityTools(server2, getIndex, getVaultPath, getStateDb4) {
24918
24959
  diversity: z30.number().min(0).max(1).optional().describe("Relevance vs diversity tradeoff (0=max diversity, 1=pure relevance, default: 0.7)")
24919
24960
  }
24920
24961
  },
24921
- async ({ path: path39, limit, diversity }) => {
24962
+ async ({ path: path40, limit, diversity }) => {
24922
24963
  const index = getIndex();
24923
24964
  const vaultPath2 = getVaultPath();
24924
24965
  const stateDb2 = getStateDb4();
@@ -24927,10 +24968,10 @@ function registerSimilarityTools(server2, getIndex, getVaultPath, getStateDb4) {
24927
24968
  content: [{ type: "text", text: JSON.stringify({ error: "StateDb not available" }) }]
24928
24969
  };
24929
24970
  }
24930
- if (!index.notes.has(path39)) {
24971
+ if (!index.notes.has(path40)) {
24931
24972
  return {
24932
24973
  content: [{ type: "text", text: JSON.stringify({
24933
- error: `Note not found: ${path39}`,
24974
+ error: `Note not found: ${path40}`,
24934
24975
  hint: "Use the full relative path including .md extension"
24935
24976
  }, null, 2) }]
24936
24977
  };
@@ -24942,12 +24983,12 @@ function registerSimilarityTools(server2, getIndex, getVaultPath, getStateDb4) {
24942
24983
  };
24943
24984
  const useHybrid = hasEmbeddingsIndex();
24944
24985
  const method = useHybrid ? "hybrid" : "bm25";
24945
- const results = useHybrid ? await findHybridSimilarNotes(stateDb2.db, vaultPath2, index, path39, opts) : findSimilarNotes(stateDb2.db, vaultPath2, index, path39, opts);
24986
+ const results = useHybrid ? await findHybridSimilarNotes(stateDb2.db, vaultPath2, index, path40, opts) : findSimilarNotes(stateDb2.db, vaultPath2, index, path40, opts);
24946
24987
  return {
24947
24988
  content: [{
24948
24989
  type: "text",
24949
24990
  text: JSON.stringify({
24950
- source: path39,
24991
+ source: path40,
24951
24992
  method,
24952
24993
  count: results.length,
24953
24994
  similar: results
@@ -26821,7 +26862,7 @@ function registerVaultResources(server2, getIndex) {
26821
26862
  }
26822
26863
 
26823
26864
  // src/tool-registry.ts
26824
- var __trFilename = fileURLToPath(import.meta.url);
26865
+ var __trFilename = fileURLToPath2(import.meta.url);
26825
26866
  var __trDirname = dirname5(__trFilename);
26826
26867
  var trPkg = JSON.parse(readFileSync5(join18(__trDirname, "../package.json"), "utf-8"));
26827
26868
  var ACTIVATION_PATTERNS = [
@@ -27053,7 +27094,7 @@ function applyToolGating(targetServer, categories, getDb4, registry, getVaultPat
27053
27094
  let totalBytes = 0;
27054
27095
  for (const p of notePaths) {
27055
27096
  try {
27056
- totalBytes += statSync6(path37.join(vp, p)).size;
27097
+ totalBytes += statSync6(path38.join(vp, p)).size;
27057
27098
  } catch {
27058
27099
  }
27059
27100
  }
@@ -27227,7 +27268,7 @@ function applyToolGating(targetServer, categories, getDb4, registry, getVaultPat
27227
27268
  const serverAny = targetServer;
27228
27269
  serverAny.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
27229
27270
  try {
27230
- const tool = serverAny._registeredTools[request.params.name];
27271
+ const tool = toolHandles.get(request.params.name);
27231
27272
  if (!tool) {
27232
27273
  throw new McpError(ErrorCode.InvalidParams, `Tool ${request.params.name} not found`);
27233
27274
  }
@@ -27404,8 +27445,8 @@ function registerAllTools(targetServer, ctx, controller) {
27404
27445
  }
27405
27446
 
27406
27447
  // src/index.ts
27407
- var __filename = fileURLToPath2(import.meta.url);
27408
- var __dirname = dirname7(__filename);
27448
+ var __filename2 = fileURLToPath3(import.meta.url);
27449
+ var __dirname = dirname7(__filename2);
27409
27450
  var pkg = JSON.parse(readFileSync6(join20(__dirname, "../package.json"), "utf-8"));
27410
27451
  var vaultPath;
27411
27452
  var resolvedVaultPath;
@@ -27420,6 +27461,7 @@ var serverReady = false;
27420
27461
  var shutdownRequested = false;
27421
27462
  var lastMcpRequestAt = 0;
27422
27463
  var lastFullRebuildAt = 0;
27464
+ var startupScanFiles = null;
27423
27465
  var deferredScheduler = null;
27424
27466
  function getWatcherStatus() {
27425
27467
  if (vaultRegistry) {
@@ -27628,7 +27670,7 @@ function buildVaultScope(ctx) {
27628
27670
  pipelineActivity: ctx.pipelineActivity
27629
27671
  };
27630
27672
  }
27631
- function activateVault(ctx) {
27673
+ function activateVault(ctx, skipEmbeddingLoad = false) {
27632
27674
  globalThis.__flywheel_active_vault = ctx.name;
27633
27675
  if (ctx.stateDb) {
27634
27676
  setWriteStateDb(ctx.stateDb);
@@ -27637,7 +27679,9 @@ function activateVault(ctx) {
27637
27679
  setProspectStateDb(ctx.stateDb);
27638
27680
  setTaskCacheDatabase(ctx.stateDb.db);
27639
27681
  setEmbeddingsDatabase(ctx.stateDb.db);
27640
- loadEntityEmbeddingsToMemory();
27682
+ if (!skipEmbeddingLoad) {
27683
+ loadEntityEmbeddingsToMemory();
27684
+ }
27641
27685
  }
27642
27686
  setWikilinkConfig(ctx.flywheelConfig);
27643
27687
  setCooccurrenceIndex(ctx.cooccurrenceIndex);
@@ -27714,6 +27758,7 @@ async function bootVault(ctx, startTime) {
27714
27758
  if (sd) {
27715
27759
  try {
27716
27760
  const files = await scanVault(vp);
27761
+ startupScanFiles = files;
27717
27762
  const noteCount = files.length;
27718
27763
  serverLog("index", `[${ctx.name}] Found ${noteCount} markdown files`);
27719
27764
  const newestMtime = files.reduce((max, f) => f.modified > max ? f.modified : max, /* @__PURE__ */ new Date(0));
@@ -27799,13 +27844,13 @@ async function main() {
27799
27844
  const primaryCtx2 = await initializeVault(vaultConfigs[0].name, vaultConfigs[0].path);
27800
27845
  vaultRegistry.addContext(primaryCtx2);
27801
27846
  stateDb = primaryCtx2.stateDb;
27802
- activateVault(primaryCtx2);
27847
+ activateVault(primaryCtx2, true);
27803
27848
  } else {
27804
27849
  vaultRegistry = new VaultRegistry("default");
27805
27850
  const ctx = await initializeVault("default", vaultPath);
27806
27851
  vaultRegistry.addContext(ctx);
27807
27852
  stateDb = ctx.stateDb;
27808
- activateVault(ctx);
27853
+ activateVault(ctx, true);
27809
27854
  }
27810
27855
  await initToolRouting();
27811
27856
  if (stateDb) {
@@ -27993,37 +28038,11 @@ async function updateEntitiesInStateDb(vp, sd) {
27993
28038
  serverLog("index", `Failed to update entities in StateDb: ${e instanceof Error ? e.message : e}`, "error");
27994
28039
  }
27995
28040
  }
27996
- async function buildStartupCatchupBatch(vaultPath2, sinceMs) {
27997
- const events = [];
27998
- async function scanDir(dir) {
27999
- let entries;
28000
- try {
28001
- entries = await fs34.readdir(dir, { withFileTypes: true });
28002
- } catch {
28003
- return;
28004
- }
28005
- for (const entry of entries) {
28006
- const fullPath = path38.join(dir, entry.name);
28007
- if (entry.isDirectory()) {
28008
- if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
28009
- await scanDir(fullPath);
28010
- } else if (entry.isFile() && entry.name.endsWith(".md")) {
28011
- try {
28012
- const stat5 = await fs34.stat(fullPath);
28013
- if (stat5.mtimeMs > sinceMs) {
28014
- events.push({
28015
- type: "upsert",
28016
- path: path38.relative(vaultPath2, fullPath),
28017
- originalEvents: []
28018
- });
28019
- }
28020
- } catch {
28021
- }
28022
- }
28023
- }
28041
+ function buildStartupCatchupBatch(vaultPath2, sinceMs, preScannedFiles) {
28042
+ if (preScannedFiles) {
28043
+ return preScannedFiles.filter((f) => f.modified.getTime() > sinceMs).map((f) => ({ type: "upsert", path: f.path, originalEvents: [] }));
28024
28044
  }
28025
- await scanDir(vaultPath2);
28026
- return events;
28045
+ return [];
28027
28046
  }
28028
28047
  var lastPurgeAt = Date.now();
28029
28048
  function runPeriodicMaintenance(db4) {
@@ -28205,7 +28224,7 @@ async function runPostIndexWork(ctx) {
28205
28224
  if (attempt < MAX_BUILD_RETRIES) {
28206
28225
  const delay = 1e4;
28207
28226
  serverLog("semantic", `Build failed (attempt ${attempt}/${MAX_BUILD_RETRIES}): ${msg}. Retrying in ${delay / 1e3}s...`, "error");
28208
- await new Promise((resolve2) => setTimeout(resolve2, delay));
28227
+ await new Promise((resolve3) => setTimeout(resolve3, delay));
28209
28228
  return attemptBuild(attempt + 1);
28210
28229
  }
28211
28230
  serverLog("semantic", `Embeddings build failed after ${MAX_BUILD_RETRIES} attempts: ${msg}`, "error");
@@ -28261,8 +28280,8 @@ async function runPostIndexWork(ctx) {
28261
28280
  }
28262
28281
  } catch {
28263
28282
  try {
28264
- const dir = path38.dirname(rawPath);
28265
- const base = path38.basename(rawPath);
28283
+ const dir = path39.dirname(rawPath);
28284
+ const base = path39.basename(rawPath);
28266
28285
  const resolvedDir = realpathSync(dir).replace(/\\/g, "/");
28267
28286
  for (const prefix of vaultPrefixes) {
28268
28287
  if (resolvedDir.startsWith(prefix + "/") || resolvedDir === prefix) {
@@ -28294,7 +28313,7 @@ async function runPostIndexWork(ctx) {
28294
28313
  continue;
28295
28314
  }
28296
28315
  try {
28297
- const content = await fs34.readFile(path38.join(vp, event.path), "utf-8");
28316
+ const content = await fs35.readFile(path39.join(vp, event.path), "utf-8");
28298
28317
  const hash = createHash4("sha256").update(content).digest("hex").slice(0, 16);
28299
28318
  if (lastContentHashes.get(event.path) === hash) {
28300
28319
  serverLog("watcher", `Hash unchanged, skipping: ${event.path}`);
@@ -28403,7 +28422,7 @@ async function runPostIndexWork(ctx) {
28403
28422
  if (sd) {
28404
28423
  const lastPipelineEvent = getRecentPipelineEvent(sd);
28405
28424
  if (lastPipelineEvent) {
28406
- const catchupEvents = await buildStartupCatchupBatch(vp, lastPipelineEvent.timestamp);
28425
+ const catchupEvents = buildStartupCatchupBatch(vp, lastPipelineEvent.timestamp, startupScanFiles);
28407
28426
  if (catchupEvents.length > 0) {
28408
28427
  console.error(`[Flywheel] Startup catch-up: ${catchupEvents.length} file(s) modified while offline`);
28409
28428
  await handleBatch({ events: catchupEvents, renames: [], timestamp: Date.now() });
@@ -28423,6 +28442,7 @@ async function runPostIndexWork(ctx) {
28423
28442
  watcher.start();
28424
28443
  serverLog("watcher", "File watcher started");
28425
28444
  }
28445
+ startupScanFiles = null;
28426
28446
  if (process.env.FLYWHEEL_WATCH !== "false") {
28427
28447
  startSweepTimer(() => ctx.vaultIndex, void 0, () => {
28428
28448
  if (sd) runPeriodicMaintenance(sd);