@velvetmonkey/flywheel-memory 2.0.85 → 2.0.86
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 +31 -30
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -7594,10 +7594,10 @@ function queryTasksFromCache(options) {
|
|
|
7594
7594
|
if (!db3) {
|
|
7595
7595
|
throw new Error("Task cache database not initialized.");
|
|
7596
7596
|
}
|
|
7597
|
-
const { status
|
|
7597
|
+
const { status, folder, tag, excludeTags = [], has_due_date, limit, offset = 0 } = options;
|
|
7598
7598
|
const conditions = [];
|
|
7599
7599
|
const params = [];
|
|
7600
|
-
if (status
|
|
7600
|
+
if (status) {
|
|
7601
7601
|
conditions.push("status = ?");
|
|
7602
7602
|
params.push(status);
|
|
7603
7603
|
}
|
|
@@ -9774,11 +9774,11 @@ function sortNotes(notes, sortBy, order) {
|
|
|
9774
9774
|
function registerQueryTools(server2, getIndex, getVaultPath, getStateDb) {
|
|
9775
9775
|
server2.tool(
|
|
9776
9776
|
"search",
|
|
9777
|
-
'Search the vault \u2014 always try this before reading files. Returns frontmatter, backlinks (with lines), outlinks (with lines + exists), headings, content snippet or preview, entity metadata, and timestamps for every hit.\n\
|
|
9777
|
+
'Search the vault \u2014 always try this before reading files. Returns frontmatter, backlinks (with lines), outlinks (with lines + exists), headings, content snippet or preview, entity metadata, and timestamps for every hit.\n\nSearches across metadata (frontmatter/tags/folders), content (FTS5 full-text + hybrid semantic), and entities (people/projects/technologies). Uses filters to narrow by frontmatter fields, tags, folders, or dates. Hybrid semantic results are automatically included when embeddings have been built (via init_semantic).\n\nExample: search({ query: "quarterly review", limit: 5 })\nExample: search({ where: { type: "project", status: "active" } })',
|
|
9778
9778
|
{
|
|
9779
|
-
query: z4.string().optional().describe(
|
|
9780
|
-
scope: z4.enum(["metadata", "content", "entities", "all"]).
|
|
9781
|
-
// Metadata filters
|
|
9779
|
+
query: z4.string().optional().describe("Search query text. Required unless using metadata filters (where, has_tag, folder, etc.)"),
|
|
9780
|
+
scope: z4.enum(["metadata", "content", "entities", "all"]).optional().describe('Narrow to a specific search type. Omit for best results (searches everything). Use "metadata" for frontmatter-only queries, "entities" for entity lookup.'),
|
|
9781
|
+
// Metadata filters
|
|
9782
9782
|
where: z4.record(z4.unknown()).optional().describe('Frontmatter filters as key-value pairs. Example: { "type": "project", "status": "active" }'),
|
|
9783
9783
|
has_tag: z4.string().optional().describe("Filter to notes with this tag"),
|
|
9784
9784
|
has_any_tag: z4.array(z4.string()).optional().describe("Filter to notes with any of these tags"),
|
|
@@ -9799,7 +9799,8 @@ function registerQueryTools(server2, getIndex, getVaultPath, getStateDb) {
|
|
|
9799
9799
|
// Context boost (edge weights)
|
|
9800
9800
|
context_note: z4.string().optional().describe("Path of the note providing context. When set, results connected to this note via weighted edges get an RRF boost.")
|
|
9801
9801
|
},
|
|
9802
|
-
async ({ query, scope, where, has_tag, has_any_tag, has_all_tags, include_children, folder, title_contains, modified_after, modified_before, sort_by, order, prefix, limit: requestedLimit, context_note }) => {
|
|
9802
|
+
async ({ query, scope: rawScope, where, has_tag, has_any_tag, has_all_tags, include_children, folder, title_contains, modified_after, modified_before, sort_by, order, prefix, limit: requestedLimit, context_note }) => {
|
|
9803
|
+
const scope = rawScope || "all";
|
|
9803
9804
|
const limit = Math.min(requestedLimit ?? 20, MAX_LIMIT);
|
|
9804
9805
|
const index = getIndex();
|
|
9805
9806
|
const vaultPath2 = getVaultPath();
|
|
@@ -10721,7 +10722,7 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig = ()
|
|
|
10721
10722
|
description: "Read the structure of a specific note. Use after search identifies a note you need more detail on. Returns headings, frontmatter, tags, word count. Set include_content: true to get the full markdown.",
|
|
10722
10723
|
inputSchema: {
|
|
10723
10724
|
path: z6.string().describe("Path to the note"),
|
|
10724
|
-
include_content: z6.boolean().default(
|
|
10725
|
+
include_content: z6.boolean().default(true).describe("Include the text content under each top-level section. Set false to get structure only.")
|
|
10725
10726
|
}
|
|
10726
10727
|
},
|
|
10727
10728
|
async ({ path: path33, include_content }) => {
|
|
@@ -10834,7 +10835,7 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig = ()
|
|
|
10834
10835
|
description: 'Query tasks from the vault. Use path to scope to a single note. Use status to filter (default: "open"). Use has_due_date to find tasks with due dates.',
|
|
10835
10836
|
inputSchema: {
|
|
10836
10837
|
path: z6.string().optional().describe("Scope to tasks from this specific note path"),
|
|
10837
|
-
status: z6.enum(["open", "completed", "cancelled"
|
|
10838
|
+
status: z6.enum(["open", "completed", "cancelled"]).default("open").describe("Filter by task status"),
|
|
10838
10839
|
has_due_date: z6.boolean().optional().describe("If true, only return tasks with due dates (sorted by date)"),
|
|
10839
10840
|
folder: z6.string().optional().describe("Limit to tasks in notes within this folder"),
|
|
10840
10841
|
tag: z6.string().optional().describe("Filter to tasks with this tag"),
|
|
@@ -10855,7 +10856,7 @@ function registerPrimitiveTools(server2, getIndex, getVaultPath, getConfig = ()
|
|
|
10855
10856
|
};
|
|
10856
10857
|
}
|
|
10857
10858
|
let filtered = result2;
|
|
10858
|
-
if (status
|
|
10859
|
+
if (status) {
|
|
10859
10860
|
filtered = result2.filter((t) => t.status === status);
|
|
10860
10861
|
}
|
|
10861
10862
|
const paged2 = filtered.slice(offset, offset + limit);
|
|
@@ -13508,19 +13509,19 @@ Example: vault_add_to_section({ path: "daily/2026-02-15.md", section: "Log", con
|
|
|
13508
13509
|
format: z11.enum(["plain", "bullet", "task", "numbered", "timestamp-bullet"]).default("plain").describe("How to format the content"),
|
|
13509
13510
|
commit: z11.boolean().default(false).describe("If true, commit this change to git (creates undo point)"),
|
|
13510
13511
|
skipWikilinks: z11.boolean().default(false).describe("If true, skip auto-wikilink application (wikilinks are applied by default)"),
|
|
13511
|
-
|
|
13512
|
-
|
|
13513
|
-
suggestOutgoingLinks: z11.boolean().default(true).describe('Append suggested outgoing wikilinks based on content (e.g., "\u2192 [[AI]], [[Philosophy]]"). Set false to disable.'),
|
|
13514
|
-
maxSuggestions: z11.number().min(1).max(10).default(5).describe("Maximum number of suggested wikilinks to append (1-10, default: 5)"),
|
|
13515
|
-
validate: z11.boolean().default(true).describe("Check input for common issues (double timestamps, non-markdown bullets, etc.)"),
|
|
13516
|
-
normalize: z11.boolean().default(true).describe("Auto-fix common issues before formatting (replace \u2022 with -, trim excessive whitespace, etc.)"),
|
|
13517
|
-
guardrails: z11.enum(["warn", "strict", "off"]).default("warn").describe('Output validation mode: "warn" returns issues but proceeds, "strict" blocks on errors, "off" disables'),
|
|
13512
|
+
suggestOutgoingLinks: z11.boolean().default(true).describe("Suggest related outgoing wikilinks based on content. Set false to disable."),
|
|
13513
|
+
maxSuggestions: z11.number().min(1).max(10).default(5).describe("Maximum number of suggested wikilinks (1-10, default: 5)"),
|
|
13518
13514
|
linkedEntities: z11.array(z11.string()).optional().describe("Entity names already linked in the content. When skipWikilinks=true, these are tracked for feedback without re-processing the content."),
|
|
13519
13515
|
dry_run: z11.boolean().optional().default(false).describe("Preview changes without writing to disk"),
|
|
13520
13516
|
agent_id: z11.string().optional().describe('Agent identifier for multi-agent scoping (e.g., "claude-opus", "planning-agent")'),
|
|
13521
13517
|
session_id: z11.string().optional().describe('Session identifier for conversation scoping (e.g., "sess-abc123")')
|
|
13522
13518
|
},
|
|
13523
|
-
async ({ path: notePath, section, content, create_if_missing, position, format, commit, skipWikilinks,
|
|
13519
|
+
async ({ path: notePath, section, content, create_if_missing, position, format, commit, skipWikilinks, suggestOutgoingLinks, maxSuggestions, linkedEntities, dry_run, agent_id, session_id }) => {
|
|
13520
|
+
const preserveListNesting = true;
|
|
13521
|
+
const bumpHeadings = true;
|
|
13522
|
+
const validate = true;
|
|
13523
|
+
const normalize = true;
|
|
13524
|
+
const guardrails = "warn";
|
|
13524
13525
|
let noteCreated = false;
|
|
13525
13526
|
let templateUsed;
|
|
13526
13527
|
if (create_if_missing) {
|
|
@@ -13652,16 +13653,16 @@ Example: vault_add_to_section({ path: "daily/2026-02-15.md", section: "Log", con
|
|
|
13652
13653
|
useRegex: z11.boolean().default(false).describe("Treat search as regex"),
|
|
13653
13654
|
commit: z11.boolean().default(false).describe("If true, commit this change to git (creates undo point)"),
|
|
13654
13655
|
skipWikilinks: z11.boolean().default(false).describe("If true, skip auto-wikilink application on replacement text"),
|
|
13655
|
-
suggestOutgoingLinks: z11.boolean().default(true).describe(
|
|
13656
|
-
maxSuggestions: z11.number().min(1).max(10).default(5).describe("Maximum number of suggested wikilinks
|
|
13657
|
-
validate: z11.boolean().default(true).describe("Check input for common issues (double timestamps, non-markdown bullets, etc.)"),
|
|
13658
|
-
normalize: z11.boolean().default(true).describe("Auto-fix common issues before formatting (replace \u2022 with -, trim excessive whitespace, etc.)"),
|
|
13659
|
-
guardrails: z11.enum(["warn", "strict", "off"]).default("warn").describe('Output validation mode: "warn" returns issues but proceeds, "strict" blocks on errors, "off" disables'),
|
|
13656
|
+
suggestOutgoingLinks: z11.boolean().default(true).describe("Suggest related outgoing wikilinks based on content. Set false to disable."),
|
|
13657
|
+
maxSuggestions: z11.number().min(1).max(10).default(5).describe("Maximum number of suggested wikilinks (1-10, default: 5)"),
|
|
13660
13658
|
dry_run: z11.boolean().optional().default(false).describe("Preview changes without writing to disk"),
|
|
13661
13659
|
agent_id: z11.string().optional().describe("Agent identifier for multi-agent scoping"),
|
|
13662
13660
|
session_id: z11.string().optional().describe("Session identifier for conversation scoping")
|
|
13663
13661
|
},
|
|
13664
|
-
async ({ path: notePath, section, search, replacement, mode, useRegex, commit, skipWikilinks, suggestOutgoingLinks, maxSuggestions,
|
|
13662
|
+
async ({ path: notePath, section, search, replacement, mode, useRegex, commit, skipWikilinks, suggestOutgoingLinks, maxSuggestions, dry_run, agent_id, session_id }) => {
|
|
13663
|
+
const validate = true;
|
|
13664
|
+
const normalize = true;
|
|
13665
|
+
const guardrails = "warn";
|
|
13665
13666
|
return withVaultFile(
|
|
13666
13667
|
{
|
|
13667
13668
|
vaultPath: vaultPath2,
|
|
@@ -17570,7 +17571,7 @@ function getEdgeWeightBoost(entityName, edgeWeightMap) {
|
|
|
17570
17571
|
async function performRecall(stateDb2, query, options = {}) {
|
|
17571
17572
|
const {
|
|
17572
17573
|
max_results = 20,
|
|
17573
|
-
focus
|
|
17574
|
+
focus,
|
|
17574
17575
|
entity,
|
|
17575
17576
|
max_tokens,
|
|
17576
17577
|
diversity = 0.7,
|
|
@@ -17580,7 +17581,7 @@ async function performRecall(stateDb2, query, options = {}) {
|
|
|
17580
17581
|
const recencyIndex2 = loadRecencyFromStateDb();
|
|
17581
17582
|
const edgeWeightMap = getEntityEdgeWeightMap(stateDb2);
|
|
17582
17583
|
const feedbackBoosts = getAllFeedbackBoosts(stateDb2);
|
|
17583
|
-
if (focus
|
|
17584
|
+
if (!focus || focus === "entities") {
|
|
17584
17585
|
try {
|
|
17585
17586
|
const entityResults = searchEntitiesDb2(stateDb2, query, max_results);
|
|
17586
17587
|
for (const e of entityResults) {
|
|
@@ -17609,7 +17610,7 @@ async function performRecall(stateDb2, query, options = {}) {
|
|
|
17609
17610
|
} catch {
|
|
17610
17611
|
}
|
|
17611
17612
|
}
|
|
17612
|
-
if (focus
|
|
17613
|
+
if (!focus || focus === "notes") {
|
|
17613
17614
|
try {
|
|
17614
17615
|
const noteResults = searchFTS5("", query, max_results);
|
|
17615
17616
|
for (const n of noteResults) {
|
|
@@ -17632,7 +17633,7 @@ async function performRecall(stateDb2, query, options = {}) {
|
|
|
17632
17633
|
} catch {
|
|
17633
17634
|
}
|
|
17634
17635
|
}
|
|
17635
|
-
if (focus
|
|
17636
|
+
if (!focus || focus === "memories") {
|
|
17636
17637
|
try {
|
|
17637
17638
|
const memResults = searchMemories(stateDb2, {
|
|
17638
17639
|
query,
|
|
@@ -17660,7 +17661,7 @@ async function performRecall(stateDb2, query, options = {}) {
|
|
|
17660
17661
|
} catch {
|
|
17661
17662
|
}
|
|
17662
17663
|
}
|
|
17663
|
-
if ((focus
|
|
17664
|
+
if ((!focus || focus === "entities") && query.length >= 20 && hasEntityEmbeddingsIndex()) {
|
|
17664
17665
|
try {
|
|
17665
17666
|
const embedding = await embedTextCached(query);
|
|
17666
17667
|
const semanticMatches = findSemanticallySimilarEntities(embedding, max_results);
|
|
@@ -17769,7 +17770,7 @@ function registerRecallTools(server2, getStateDb, getVaultPath) {
|
|
|
17769
17770
|
{
|
|
17770
17771
|
query: z24.string().describe('What to recall (e.g., "Project X", "meetings about auth")'),
|
|
17771
17772
|
max_results: z24.number().min(1).max(100).optional().describe("Max results (default: 20)"),
|
|
17772
|
-
focus: z24.enum(["entities", "notes", "memories"
|
|
17773
|
+
focus: z24.enum(["entities", "notes", "memories"]).optional().describe("Limit to a specific result type. Omit for best results (searches everything)."),
|
|
17773
17774
|
entity: z24.string().optional().describe("Filter memories by entity association"),
|
|
17774
17775
|
max_tokens: z24.number().optional().describe("Token budget for response (truncates lower-ranked results)"),
|
|
17775
17776
|
diversity: z24.number().min(0).max(1).optional().describe("Relevance vs diversity tradeoff (0=max diversity, 1=pure relevance, default: 0.7)")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velvetmonkey/flywheel-memory",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.86",
|
|
4
4
|
"description": "MCP server that gives Claude full read/write access to your Obsidian vault. Select from 51 tools for search, backlinks, graph queries, mutations, agent memory, and hybrid semantic search.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
56
|
-
"@velvetmonkey/vault-core": "^2.0.
|
|
56
|
+
"@velvetmonkey/vault-core": "^2.0.86",
|
|
57
57
|
"better-sqlite3": "^11.0.0",
|
|
58
58
|
"chokidar": "^4.0.0",
|
|
59
59
|
"gray-matter": "^4.0.3",
|