@augmnt-sh/mindcache 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +101 -101
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,107 +1,107 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio.js';import {McpServer}from'@modelcontextprotocol/sdk/server/mcp.js';import {existsSync,mkdirSync,writeFileSync,readFileSync,readdirSync,appendFileSync,unlinkSync}from'fs';import {dirname,join,relative,basename,extname,resolve}from'path';import {z as z$1}from'zod';import {fileURLToPath}from'url';import {homedir}from'os';import {createInterface}from'readline';function
|
|
3
|
-
`),t=false,e=0,
|
|
4
|
-
`).trim():null}function
|
|
5
|
-
`),e=[],
|
|
6
|
-
`)}function
|
|
7
|
-
`)){let e=t.indexOf(":");if(e>0){let
|
|
8
|
-
`);for(let t=0;t<
|
|
9
|
-
`),a=t.targetHeading.toLowerCase(),
|
|
10
|
-
`),"utf-8");else throw new Error(`Heading "${t.targetHeading}" not found`)}}else if(t?.targetLine!==void 0){let r=
|
|
11
|
-
`);r.splice(t.targetLine,0,
|
|
12
|
-
`),"utf-8");}else appendFileSync(e,
|
|
13
|
-
`);return `${
|
|
2
|
+
import {StdioServerTransport}from'@modelcontextprotocol/sdk/server/stdio.js';import {McpServer}from'@modelcontextprotocol/sdk/server/mcp.js';import {existsSync,mkdirSync,writeFileSync,readFileSync,watch,readdirSync,statSync,appendFileSync,unlinkSync}from'fs';import {dirname,join,relative,basename,extname,resolve}from'path';import {z as z$1}from'zod';import {fileURLToPath}from'url';import {homedir}from'os';import {createInterface}from'readline';function A(s,o){let i=s.split(`
|
|
3
|
+
`),t=false,e=0,n=[];for(let r of i){let c=r.match(/^(#{1,6})\s+(.+)$/);if(c){let a=c[1].length,l=c[2].trim();if(t){if(a<=e)break;n.push(r);}else l.toLowerCase()===o.toLowerCase()&&(t=true,e=a,n.push(r));}else t&&n.push(r);}return n.length>0?n.join(`
|
|
4
|
+
`).trim():null}function L(s,o,i){let t=s.split(`
|
|
5
|
+
`),e=[],n=false,r=0;for(let c of t){let a=c.match(/^(#{1,6})\s+(.+)$/);if(a){let l=a[1].length,m=a[2].trim();n&&l<=r?(n=false,e.push(c)):m.toLowerCase()===o.toLowerCase()?(n=true,r=l,e.push(c),e.push(""),e.push(i),e.push("")):e.push(c);}else n||e.push(c);}return e.join(`
|
|
6
|
+
`)}function M(s){let o=s.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);if(!o)return {frontmatter:{},body:s};let i={};for(let t of o[1].split(`
|
|
7
|
+
`)){let e=t.indexOf(":");if(e>0){let n=t.slice(0,e).trim(),r=t.slice(e+1).trim();i[n]=r;}}return {frontmatter:i,body:o[2]}}function C(s){return [...s.matchAll(/\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/g)].map(i=>i[1])}function $(s){let o=s.matchAll(/(?:^|\s)#([a-zA-Z0-9_/-]+)/g);return [...new Set([...o].map(i=>i[1]))]}function B(s){let o=[],i=s.split(`
|
|
8
|
+
`);for(let t=0;t<i.length;t++){let e=i[t].match(/^[\s]*-\s+\[([ xX])\]\s+(.+)$/);e&&o.push({text:e[2],done:e[1]!==" ",line:t+1});}return o}function J(s){let{body:o}=M(s);return o.split(/\s+/).filter(i=>i.length>0).length}var E=class{vaultPath;fileCache=null;fileCacheTime=0;CACHE_TTL=5e3;watcher=null;constructor(o){this.vaultPath=o.vault,this.vaultPath&&existsSync(this.vaultPath)&&this.startWatcher();}startWatcher(){try{this.watcher=watch(this.vaultPath,{recursive:!0},(o,i)=>{i&&!i.startsWith(".")&&(this.fileCache=null);}),this.watcher.on("error",()=>{});}catch{}}resolve(o){let i=join(this.vaultPath,o);if(!i.startsWith(this.vaultPath))throw new Error("Path traversal not allowed");return i}ensureDir(o){let i=dirname(o);existsSync(i)||mkdirSync(i,{recursive:true});}walkDir(o){let i=[],t;try{t=readdirSync(o,{withFileTypes:!0});}catch{return i}for(let e of t){if(e.name.startsWith(".")||e.name==="node_modules")continue;let n=join(o,e.name);if(e.isDirectory())i.push(...this.walkDir(n));else try{let r=statSync(n);i.push({fullPath:n,mtime:r.mtimeMs});}catch{i.push({fullPath:n,mtime:0});}}return i}tokenize(o){return o.toLowerCase().split(/\s+/).filter(i=>i.length>1)}scoreMatch(o,i,t,e){let n=i.toLowerCase(),r=o.toLowerCase(),c=this.tokenize(o),a=[],l=0;if(n.indexOf(r)>=0){l+=100;let p=0,h=0;for(;(p=n.indexOf(r,p))!==-1&&h<5;){let y=Math.max(0,p-80),w=Math.min(i.length,p+o.length+80);a.push({start:p,end:p+o.length,context:i.slice(y,w).replace(/\n/g," ").trim()}),p+=r.length,h++;}l+=h*10;}if(c.length>1){let p=0;for(let y of c)if(n.includes(y)){p++;let w=0,_=0;for(;(w=n.indexOf(y,w))!==-1;)_++,w+=y.length;l+=_*3;}let h=p/c.length;if(l+=h*50,a.length===0&&p>0)for(let y of c){let w=n.indexOf(y);if(w>=0){let _=Math.max(0,w-80),$t=Math.min(i.length,w+y.length+80);a.push({start:w,end:w+y.length,context:i.slice(_,$t).replace(/\n/g," ").trim()});break}}}let u=t.toLowerCase();if(u.includes(r))l+=80;else for(let p of c)u.includes(p)&&(l+=25);let d=(Date.now()-e)/(1e3*60*60*24);return d<1?l+=20:d<7?l+=10:d<30&&(l+=5),{score:l,matchPositions:a}}async ping(){return existsSync(this.vaultPath)}async search(o){let t=(await this.listFiles()).filter(n=>n.extension==="md"),e=[];for(let n of t)try{let r=readFileSync(this.resolve(n.path),"utf-8"),{score:c,matchPositions:a}=this.scoreMatch(o,r,n.name,n.mtime);c>0&&a.length>0&&e.push({filename:n.path,score:c,matches:a.map(l=>({match:{start:l.start,end:l.end},context:l.context}))});}catch{}return e.sort((n,r)=>r.score-n.score)}async readNote(o){let i=this.resolve(o);if(!existsSync(i))throw new Error(`Note not found: ${o}`);return readFileSync(i,"utf-8")}async writeNote(o,i){let t=this.resolve(o);this.ensureDir(t),writeFileSync(t,i,"utf-8"),this.fileCache=null;}async appendToNote(o,i){let t=this.resolve(o);if(!existsSync(t))throw new Error(`Note not found: ${o}`);appendFileSync(t,i,"utf-8");}async patchNote(o,i,t){let e=this.resolve(o),n=readFileSync(e,"utf-8");if(t?.targetHeading){if(!A(n,t.targetHeading))throw new Error(`Heading "${t.targetHeading}" not found`);if(t.operation==="replace"){let c=L(n,t.targetHeading,i);writeFileSync(e,c,"utf-8");}else {let c=n.split(`
|
|
9
|
+
`),a=t.targetHeading.toLowerCase(),l=-1;for(let m=0;m<c.length;m++){let u=c[m].match(/^#{1,6}\s+(.+)$/);if(u&&u[1].trim().toLowerCase()===a){let f=c[m].indexOf(" ");l=m+1;for(let d=m+1;d<c.length;d++){let p=c[d].match(/^(#{1,6})\s/);if(p&&p[1].length<=f)break;l=d+1;}break}}if(l>=0)c.splice(l,0,i),writeFileSync(e,c.join(`
|
|
10
|
+
`),"utf-8");else throw new Error(`Heading "${t.targetHeading}" not found`)}}else if(t?.targetLine!==void 0){let r=n.split(`
|
|
11
|
+
`);r.splice(t.targetLine,0,i),writeFileSync(e,r.join(`
|
|
12
|
+
`),"utf-8");}else appendFileSync(e,i,"utf-8");}async deleteNote(o){let i=this.resolve(o);if(!existsSync(i))throw new Error(`Note not found: ${o}`);unlinkSync(i),this.fileCache=null;}async listFiles(){let o=Date.now();if(this.fileCache&&o-this.fileCacheTime<this.CACHE_TTL)return this.fileCache;let i=this.walkDir(this.vaultPath);return this.fileCache=i.map(({fullPath:t,mtime:e})=>{let n=relative(this.vaultPath,t),r=basename(n,extname(n)),c=extname(n).slice(1);return {path:n,name:r,extension:c,mtime:e}}).sort((t,e)=>e.mtime-t.mtime),this.fileCacheTime=o,this.fileCache}async getActiveNote(){throw new Error("Active note detection requires Obsidian to be running. Use search or read_note instead.")}async getActiveNotePath(){throw new Error("Active note detection requires Obsidian to be running. Use search or read_note instead.")}async searchWithContext(o,i=100){let e=(await this.listFiles()).filter(a=>a.extension==="md"),n=this.tokenize(o),r=o.toLowerCase(),c=[];for(let a of e)try{let l=readFileSync(this.resolve(a.path),"utf-8"),{score:m}=this.scoreMatch(o,l,a.name,a.mtime);if(m>0){let u=l.toLowerCase(),f=[],d=0;for(;(d=u.indexOf(r,d))!==-1&&f.length<5;){let p=Math.max(0,d-i),h=Math.min(l.length,d+o.length+i);f.push({match:{start:d,end:d+o.length},context:l.slice(p,h).replace(/\n/g," ").trim()}),d+=r.length;}if(f.length===0)for(let p of n){let h=u.indexOf(p);if(h>=0&&f.length<3){let y=Math.max(0,h-i),w=Math.min(l.length,h+p.length+i);f.push({match:{start:h,end:h+p.length},context:l.slice(y,w).replace(/\n/g," ").trim()});}}f.length>0&&c.push({filename:a.path,score:m,matches:f});}}catch{}return c.sort((a,l)=>l.score-a.score)}async health(){if(!this.vaultPath)return {ok:false,error:"No vault path configured. Run: mindcache init"};if(!existsSync(this.vaultPath))return {ok:false,error:`Vault not found at: ${this.vaultPath}`};try{return {ok:!0,noteCount:(await this.listFiles()).filter(t=>t.extension==="md").length}}catch(o){return {ok:false,error:`Cannot read vault: ${o instanceof Error?o.message:String(o)}`}}}close(){this.watcher&&(this.watcher.close(),this.watcher=null);}};function tt(s){let o=s.getFullYear(),i=String(s.getMonth()+1).padStart(2,"0"),t=String(s.getDate()).padStart(2,"0");return `${o}-${i}-${t}`}function x(){return tt(new Date)}function z(s=new Date){let o=new Date(s),i=o.getDay(),t=o.getDate()-i+(i===0?-6:1);return o.setDate(t),o.setHours(0,0,0,0),o}function et(s=new Date){let o=z(s),i=[];for(let t=0;t<7;t++){let e=new Date(o);e.setDate(o.getDate()+t),i.push(tt(e));}return i}function nt(s){let o=new Date,i=s.toLowerCase().trim();if(i==="today"){let r=new Date(o);r.setHours(0,0,0,0);let c=new Date(o);return c.setHours(23,59,59,999),{from:r,to:c}}if(i==="yesterday"){let r=new Date(o);r.setDate(r.getDate()-1),r.setHours(0,0,0,0);let c=new Date(r);return c.setHours(23,59,59,999),{from:r,to:c}}if(i==="this week")return {from:z(o),to:o};if(i==="last week"){let r=z(o),c=new Date(r);c.setDate(c.getDate()-7);let a=new Date(r);return a.setMilliseconds(-1),{from:c,to:a}}if(i==="this month")return {from:new Date(o.getFullYear(),o.getMonth(),1),to:o};if(i==="last month"){let r=new Date(o.getFullYear(),o.getMonth()-1,1),c=new Date(o.getFullYear(),o.getMonth(),0,23,59,59,999);return {from:r,to:c}}let t=i.match(/(\d{4}-\d{2}-\d{2})\s+to\s+(\d{4}-\d{2}-\d{2})/);if(t)return {from:new Date(t[1]),to:new Date(t[2])};let e=i.match(/last\s+(\d+)\s+days?/);if(e){let r=new Date(o);return r.setDate(r.getDate()-parseInt(e[1])),r.setHours(0,0,0,0),{from:r,to:o}}let n=new Date(o);return n.setDate(n.getDate()-7),n.setHours(0,0,0,0),{from:n,to:o}}function ot(s,o,i){s.tool("search",'Full-text search across your Obsidian vault. Supports Obsidian search operators: "exact phrase", path:folder, tag:#tag, file:filename. Returns matching notes with context snippets.',{query:z$1.string().describe("Search query \u2014 supports Obsidian search operators")},async({query:t})=>{try{let e=await o.searchWithContext(t,200);if(e.length===0)return {content:[{type:"text",text:`No results found for "${t}"`}]};let n=e.slice(0,20).map((r,c)=>{let a=r.matches.slice(0,3).map(l=>` > ${l.context.trim()}`).join(`
|
|
13
|
+
`);return `${c+1}. **${r.filename}** (score: ${r.score.toFixed(1)})
|
|
14
14
|
${a}`}).join(`
|
|
15
15
|
|
|
16
16
|
`);return {content:[{type:"text",text:`Found ${e.length} results for "${t}":
|
|
17
17
|
|
|
18
|
-
${
|
|
18
|
+
${n}`}]}}catch(e){return {content:[{type:"text",text:`Search error: ${e instanceof Error?e.message:String(e)}`}],isError:true}}}),s.tool("ask","Ask a natural language question about your vault. Searches for relevant notes and returns their content so you can synthesize an answer. Use this when you need to understand what the user knows about a topic.",{question:z$1.string().describe("Natural language question to answer from vault knowledge")},async({question:t})=>{try{let e=await o.searchWithContext(t,300);if(e.length===0)return {content:[{type:"text",text:`No relevant notes found for: "${t}"`}]};let n=e.slice(0,5),r=[];for(let c of n)try{let a=await o.readNote(c.filename),{frontmatter:l}=M(a),m=$(a),u=C(a),f=a.length>2e3?a.slice(0,2e3)+`
|
|
19
19
|
...(truncated)`:a;r.push(`---
|
|
20
|
-
**${
|
|
20
|
+
**${c.filename}**`+(m.length>0?` | Tags: ${m.map(d=>`#${d}`).join(", ")}`:"")+(u.length>0?` | Links: ${u.map(d=>`[[${d}]]`).join(", ")}`:"")+(l.type?` | Type: ${l.type}`:"")+`
|
|
21
21
|
|
|
22
22
|
${f}`);}catch{}return {content:[{type:"text",text:`Found ${e.length} relevant notes for "${t}". Here are the top ${r.length}:
|
|
23
23
|
|
|
24
24
|
${r.join(`
|
|
25
25
|
|
|
26
|
-
`)}`}]}}catch(e){return {content:[{type:"text",text:`Ask error: ${e instanceof Error?e.message:String(e)}`}],isError:true}}}),s.tool("find_related","Find notes related to a given note via backlinks, shared tags, or shared wikilinks. Returns notes that are connected in the knowledge graph.",{path:z$1.string().describe('Path to the note (e.g., "Projects/My Project.md")')},async({path:t})=>{try{let e=await
|
|
26
|
+
`)}`}]}}catch(e){return {content:[{type:"text",text:`Ask error: ${e instanceof Error?e.message:String(e)}`}],isError:true}}}),s.tool("find_related","Find notes related to a given note via backlinks, shared tags, or shared wikilinks. Returns notes that are connected in the knowledge graph.",{path:z$1.string().describe('Path to the note (e.g., "Projects/My Project.md")')},async({path:t})=>{try{let e=await o.readNote(t),n=C(e),r=$(e),c=new Map;for(let f of n){let d=await o.search(`file:${f}`);for(let p of d.slice(0,3))p.filename!==t&&c.set(p.filename,{reason:`Linked from this note: [[${f}]]`,score:(c.get(p.filename)?.score??0)+2});}for(let f of r.slice(0,5)){let d=await o.search(`tag:#${f}`);for(let p of d.slice(0,5))if(p.filename!==t){let h=c.get(p.filename);c.set(p.filename,{reason:h?`${h.reason}; Shared tag: #${f}`:`Shared tag: #${f}`,score:(h?.score??0)+1});}}let a=t.replace(/\.md$/,"").split("/").pop()??t,l=await o.search(`"[[${a}]]"`);for(let f of l)if(f.filename!==t){let d=c.get(f.filename);c.set(f.filename,{reason:d?`${d.reason}; Links to this note`:"Links to this note",score:(d?.score??0)+3});}let m=[...c.entries()].sort((f,d)=>d[1].score-f[1].score).slice(0,15);if(m.length===0)return {content:[{type:"text",text:`No related notes found for "${t}"`}]};let u=m.map(([f,d],p)=>`${p+1}. **${f}** \u2014 ${d.reason}`).join(`
|
|
27
27
|
`);return {content:[{type:"text",text:`Related notes for "${t}":
|
|
28
28
|
|
|
29
|
-
${u}`}]}}catch(e){return {content:[{type:"text",text:`Find related error: ${e instanceof Error?e.message:String(e)}`}],isError:true}}}),s.tool("find_by_tag","Find all notes with specific tags. Supports multiple tags (all must match). Use without # prefix.",{tags:z$1.array(z$1.string()).describe('Tags to search for (without # prefix, e.g., ["project", "active"])'),limit:z$1.number().optional().default(20).describe("Maximum number of results")},async({tags:t,limit:e})=>{try{let
|
|
29
|
+
${u}`}]}}catch(e){return {content:[{type:"text",text:`Find related error: ${e instanceof Error?e.message:String(e)}`}],isError:true}}}),s.tool("find_by_tag","Find all notes with specific tags. Supports multiple tags (all must match). Use without # prefix.",{tags:z$1.array(z$1.string()).describe('Tags to search for (without # prefix, e.g., ["project", "active"])'),limit:z$1.number().optional().default(20).describe("Maximum number of results")},async({tags:t,limit:e})=>{try{let n=t.map(a=>`tag:#${a}`).join(" "),r=await o.search(n);if(r.length===0)return {content:[{type:"text",text:`No notes found with tags: ${t.map(a=>`#${a}`).join(", ")}`}]};let c=r.slice(0,e).map((a,l)=>`${l+1}. ${a.filename}`).join(`
|
|
30
30
|
`);return {content:[{type:"text",text:`Notes tagged ${t.map(a=>`#${a}`).join(", ")} (${r.length} total):
|
|
31
31
|
|
|
32
|
-
${
|
|
33
|
-
`);return {content:[{type:"text",text:`Notes from ${
|
|
32
|
+
${c}`}]}}catch(n){return {content:[{type:"text",text:`Tag search error: ${n instanceof Error?n.message:String(n)}`}],isError:true}}}),s.tool("find_by_date",'Find notes created or modified within a date range. Supports natural language like "today", "this week", "last month", "last 7 days", or explicit "YYYY-MM-DD to YYYY-MM-DD".',{range:z$1.string().describe('Date range \u2014 "today", "this week", "last month", "last 30 days", or "YYYY-MM-DD to YYYY-MM-DD"'),limit:z$1.number().optional().default(20).describe("Maximum results")},async({range:t,limit:e})=>{try{let{from:n,to:r}=nt(t),a=(await o.listFiles()).filter(d=>d.extension==="md"),l=n.toISOString().split("T")[0],m=r.toISOString().split("T")[0],f=(await o.search(`"${l}"`)).slice(0,e).map((d,p)=>`${p+1}. ${d.filename}`).join(`
|
|
33
|
+
`);return {content:[{type:"text",text:`Notes from ${l} to ${m} (searched by date reference):
|
|
34
34
|
|
|
35
35
|
`+(f||"No notes found in this range.")+`
|
|
36
36
|
|
|
37
|
-
Total markdown files in vault: ${a.length}`}]}}catch(
|
|
38
|
-
`);return {content:[{type:"text",text:`
|
|
37
|
+
Total markdown files in vault: ${a.length}`}]}}catch(n){return {content:[{type:"text",text:`Date search error: ${n instanceof Error?n.message:String(n)}`}],isError:true}}}),s.tool("find_recent","Get recently modified notes in the vault, sorted by modification time (newest first).",{limit:z$1.number().optional().default(10).describe("Number of recent notes to return")},async({limit:t})=>{try{let n=(await o.listFiles()).filter(a=>a.extension==="md"),c=n.slice(0,t).map((a,l)=>{let m=Date.now()-a.mtime,u=Math.floor(m/6e4),f=Math.floor(u/60),d=Math.floor(f/24),p=d>0?`${d}d ago`:f>0?`${f}h ago`:`${u}m ago`;return `${l+1}. ${a.path} \u2014 ${p}`}).join(`
|
|
38
|
+
`);return {content:[{type:"text",text:`Recently modified notes (${n.length} total):
|
|
39
39
|
|
|
40
|
-
${
|
|
41
|
-
> ${
|
|
40
|
+
${c}`}]}}catch(e){return {content:[{type:"text",text:`Recent notes error: ${e instanceof Error?e.message:String(e)}`}],isError:true}}}),s.tool("find_mentions","Find all notes that mention a specific term, concept, or person. Searches for exact text matches across the vault.",{term:z$1.string().describe("Term or concept to search for"),limit:z$1.number().optional().default(20).describe("Maximum results")},async({term:t,limit:e})=>{try{let n=await o.searchWithContext(t,150);if(n.length===0)return {content:[{type:"text",text:`"${t}" is not mentioned in any notes.`}]};let r=n.slice(0,e).map((c,a)=>{let l=c.matches[0]?.context?.trim()??"";return `${a+1}. **${c.filename}**
|
|
41
|
+
> ${l}`}).join(`
|
|
42
42
|
|
|
43
|
-
`);return {content:[{type:"text",text:`"${t}" mentioned in ${
|
|
43
|
+
`);return {content:[{type:"text",text:`"${t}" mentioned in ${n.length} notes:
|
|
44
44
|
|
|
45
|
-
${r}`}]}}catch(
|
|
46
|
-
${Object.entries(
|
|
45
|
+
${r}`}]}}catch(n){return {content:[{type:"text",text:`Mentions search error: ${n instanceof Error?n.message:String(n)}`}],isError:true}}});}function rt(s,o,i){s.tool("read_note","Read the full content of a note by its path. Returns the complete markdown including frontmatter.",{path:z$1.string().describe('Path to the note (e.g., "Projects/My Project.md")')},async({path:t})=>{try{return {content:[{type:"text",text:await o.readNote(t)}]}}catch(e){return {content:[{type:"text",text:`Could not read "${t}": ${e instanceof Error?e.message:String(e)}`}],isError:true}}}),s.tool("read_section","Read a specific section from a note, identified by its heading. Returns content from the heading to the next heading of the same or higher level.",{path:z$1.string().describe("Path to the note"),heading:z$1.string().describe('Heading text to extract (e.g., "Key Points", "Action Items")')},async({path:t,heading:e})=>{try{let n=await o.readNote(t),r=A(n,e);return r?{content:[{type:"text",text:r}]}:{content:[{type:"text",text:`No section "${e}" found in "${t}"`}]}}catch(n){return {content:[{type:"text",text:`Could not read section: ${n instanceof Error?n.message:String(n)}`}],isError:true}}}),s.tool("read_summary","Get a note with its metadata: frontmatter properties, tags, wikilinks, and word count. Useful for understanding a note without reading it fully.",{path:z$1.string().describe("Path to the note")},async({path:t})=>{try{let e=await o.readNote(t),{frontmatter:n}=M(e),r=$(e),c=C(e),a=J(e);return {content:[{type:"text",text:[`**${t}**`,"",`**Words:** ${a}`,r.length>0?`**Tags:** ${r.map(m=>`#${m}`).join(", ")}`:null,c.length>0?`**Links:** ${c.map(m=>`[[${m}]]`).join(", ")}`:null,Object.keys(n).length>0?`**Properties:**
|
|
46
|
+
${Object.entries(n).map(([m,u])=>` - ${m}: ${u}`).join(`
|
|
47
47
|
`)}`:null,"","---","",e].filter(Boolean).join(`
|
|
48
|
-
`)}]}}catch(e){return {content:[{type:"text",text:`Could not read summary: ${e instanceof Error?e.message:String(e)}`}],isError:true}}}),s.tool("read_properties","Read only the YAML frontmatter properties of a note. Fast way to check metadata without reading the full content.",{path:z$1.string().describe("Path to the note")},async({path:t})=>{try{let e=await
|
|
48
|
+
`)}]}}catch(e){return {content:[{type:"text",text:`Could not read summary: ${e instanceof Error?e.message:String(e)}`}],isError:true}}}),s.tool("read_properties","Read only the YAML frontmatter properties of a note. Fast way to check metadata without reading the full content.",{path:z$1.string().describe("Path to the note")},async({path:t})=>{try{let e=await o.readNote(t),{frontmatter:n}=M(e);if(Object.keys(n).length===0)return {content:[{type:"text",text:`No frontmatter found in "${t}"`}]};let r=Object.entries(n).map(([c,a])=>`${c}: ${a}`).join(`
|
|
49
49
|
`);return {content:[{type:"text",text:`Properties of "${t}":
|
|
50
50
|
|
|
51
|
-
${r}`}]}}catch(e){return {content:[{type:"text",text:`Could not read properties: ${e instanceof Error?e.message:String(e)}`}],isError:true}}}),s.tool("read_today","Read today's daily note. Returns the content of today's daily note based on your configured daily notes folder and format.",{},async()=>{try{let t=`${
|
|
51
|
+
${r}`}]}}catch(e){return {content:[{type:"text",text:`Could not read properties: ${e instanceof Error?e.message:String(e)}`}],isError:true}}}),s.tool("read_today","Read today's daily note. Returns the content of today's daily note based on your configured daily notes folder and format.",{},async()=>{try{let t=`${i.dailyNotes.folder}/${x()}.md`,e=await o.readNote(t);return {content:[{type:"text",text:`**Today's Daily Note (${x()}):**
|
|
52
52
|
|
|
53
|
-
${e}`}]}}catch{return {content:[{type:"text",text:`No daily note found for today (${
|
|
53
|
+
${e}`}]}}catch{return {content:[{type:"text",text:`No daily note found for today (${x()}). Expected at: ${i.dailyNotes.folder}/${x()}.md`}]}}}),s.tool("read_this_week","Read all daily notes from the current week (Monday to Sunday). Useful for getting a weekly overview of activity.",{},async()=>{try{let t=et(),e=[];for(let n of t){let r=`${i.dailyNotes.folder}/${n}.md`;try{let c=await o.readNote(r);e.push(`## ${n}
|
|
54
54
|
|
|
55
|
-
${
|
|
55
|
+
${c}`);}catch{}}return e.length===0?{content:[{type:"text",text:`No daily notes found for this week (${t[0]} to ${t[6]}).`}]}:{content:[{type:"text",text:`**This Week's Daily Notes:**
|
|
56
56
|
|
|
57
57
|
${e.join(`
|
|
58
58
|
|
|
59
59
|
---
|
|
60
60
|
|
|
61
|
-
`)}`}]}}catch(t){return {content:[{type:"text",text:`Could not read weekly notes: ${t instanceof Error?t.message:String(t)}`}],isError:true}}}),s.tool("get_active_note","Get the currently active/open note in Obsidian. Returns both the path and content of the note the user is currently viewing.",{},async()=>{try{let t=await
|
|
61
|
+
`)}`}]}}catch(t){return {content:[{type:"text",text:`Could not read weekly notes: ${t instanceof Error?t.message:String(t)}`}],isError:true}}}),s.tool("get_active_note","Get the currently active/open note in Obsidian. Returns both the path and content of the note the user is currently viewing.",{},async()=>{try{let t=await o.getActiveNote(),e="";try{e=await o.getActiveNotePath();}catch{}return {content:[{type:"text",text:e?`**Active Note: ${e}**
|
|
62
62
|
|
|
63
63
|
${t}`:`**Active Note:**
|
|
64
64
|
|
|
65
|
-
${t}`}]}}catch(t){return {content:[{type:"text",text:`Could not get active note: ${t instanceof Error?t.message:String(t)}`}],isError:true}}});}var
|
|
66
|
-
${
|
|
65
|
+
${t}`}]}}catch(t){return {content:[{type:"text",text:`Could not get active note: ${t instanceof Error?t.message:String(t)}`}],isError:true}}});}var Pt=dirname(fileURLToPath(import.meta.url)),Ot=join(Pt,"..","templates"),V=new Map;function jt(s){if(V.has(s))return V.get(s);let o=join(Ot,`${s}.md`);if(!existsSync(o))throw new Error(`Template "${s}" not found at ${o}`);let i=readFileSync(o,"utf-8");return V.set(s,i),i}function _t(s,o){let i=s,e={...{date:x(),timestamp:new Date().toISOString(),year:String(new Date().getFullYear()),month:String(new Date().getMonth()+1).padStart(2,"0"),day:String(new Date().getDate()).padStart(2,"0")},...o};for(let[n,r]of Object.entries(e))i=i.replaceAll(`{{${n}}}`,r??"");return i=i.replace(/\{\{[^}]+\}\}/g,""),i}function N(s,o={}){let i=jt(s);return _t(i,o)}function it(s,o,i){s.tool("remember","Quick capture \u2014 save a thought, note, or piece of information to the vault. Auto-saves to the inbox folder. Use this for quick, unstructured captures.",{content:z$1.string().describe("The content to save"),title:z$1.string().optional().describe("Optional title for the note. If omitted, generates from content."),tags:z$1.array(z$1.string()).optional().describe("Optional tags to add (without # prefix)"),folder:z$1.string().optional().describe("Optional folder to save to (defaults to inbox)")},async({content:t,title:e,tags:n,folder:r})=>{try{let c=e??`Quick Note - ${x()} ${new Date().toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit"})}`,l=`${r??i.inbox.folder}/${c}.md`,m=n&&n.length>0?`tags:
|
|
66
|
+
${n.map(f=>` - ${f}`).join(`
|
|
67
67
|
`)}`:`tags:
|
|
68
68
|
- inbox`,u=`---
|
|
69
|
-
date: ${
|
|
70
|
-
${
|
|
69
|
+
date: ${x()}
|
|
70
|
+
${m}
|
|
71
71
|
---
|
|
72
72
|
|
|
73
73
|
${t}
|
|
74
|
-
`;return await
|
|
75
|
-
- ${new Date().toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit"})} \u2014 ${t}`;try{await
|
|
74
|
+
`;return await o.writeNote(l,u),{content:[{type:"text",text:`Saved to "${l}"`}]}}catch(c){return {content:[{type:"text",text:`Could not save note: ${c instanceof Error?c.message:String(c)}`}],isError:true}}}),s.tool("remember_meeting","Create a structured meeting note with attendees, agenda, notes, and action items. Uses the meeting template.",{title:z$1.string().describe("Meeting title"),attendees:z$1.string().describe("Comma-separated list of attendees"),agenda:z$1.string().optional().default("").describe("Meeting agenda"),notes:z$1.string().optional().default("").describe("Meeting notes"),action_items:z$1.string().optional().default("").describe("Action items from the meeting"),follow_up:z$1.string().optional().default("").describe("Follow-up items"),folder:z$1.string().optional().describe("Folder to save to (defaults to inbox)")},async({title:t,attendees:e,agenda:n,notes:r,action_items:c,follow_up:a,folder:l})=>{try{let m=N("meeting",{title:t,attendees:e,agenda:n,notes:r,action_items:c,follow_up:a}),f=`${l??i.inbox.folder}/${t}.md`;return await o.writeNote(f,m),{content:[{type:"text",text:`Meeting note created at "${f}"`}]}}catch(m){return {content:[{type:"text",text:`Could not create meeting note: ${m instanceof Error?m.message:String(m)}`}],isError:true}}}),s.tool("remember_decision","Log a decision using the ADR (Architecture Decision Record) format. Captures the context, decision, consequences, and alternatives considered.",{title:z$1.string().describe("Decision title"),context:z$1.string().describe("Why this decision needed to be made"),decision:z$1.string().describe("What was decided"),consequences:z$1.string().optional().default("").describe("What happens as a result"),alternatives:z$1.string().optional().default("").describe("Other options that were considered"),related:z$1.string().optional().default("").describe("Related notes or concepts"),folder:z$1.string().optional().describe("Folder to save to")},async({title:t,context:e,decision:n,consequences:r,alternatives:c,related:a,folder:l})=>{try{let m=N("decision",{title:t,context:e,decision:n,consequences:r,alternatives:c,related:a}),f=`${l??i.inbox.folder}/${t}.md`;return await o.writeNote(f,m),{content:[{type:"text",text:`Decision logged at "${f}"`}]}}catch(m){return {content:[{type:"text",text:`Could not log decision: ${m instanceof Error?m.message:String(m)}`}],isError:true}}}),s.tool("remember_idea","Capture an idea with context on why it matters and potential next steps.",{title:z$1.string().describe("Idea title"),idea:z$1.string().describe("Description of the idea"),why:z$1.string().optional().default("").describe("Why this idea matters"),next_steps:z$1.string().optional().default("").describe("Potential next steps"),related:z$1.string().optional().default("").describe("Related notes or concepts"),tags:z$1.array(z$1.string()).optional().describe("Additional tags"),folder:z$1.string().optional().describe("Folder to save to")},async({title:t,idea:e,why:n,next_steps:r,related:c,folder:a})=>{try{let l=N("idea",{title:t,idea:e,why:n,next_steps:r,related:c}),u=`${a??i.inbox.folder}/${t}.md`;return await o.writeNote(u,l),{content:[{type:"text",text:`Idea captured at "${u}"`}]}}catch(l){return {content:[{type:"text",text:`Could not capture idea: ${l instanceof Error?l.message:String(l)}`}],isError:true}}}),s.tool("remember_learning","Save something new you learned \u2014 a concept, technique, insight, or skill with examples and application notes.",{title:z$1.string().describe("What was learned"),concept:z$1.string().describe("The concept or insight"),key_points:z$1.string().optional().default("").describe("Key points to remember"),examples:z$1.string().optional().default("").describe("Examples or illustrations"),application:z$1.string().optional().default("").describe("How to apply this learning"),source:z$1.string().optional().default("").describe("Where you learned this"),related:z$1.string().optional().default("").describe("Related notes"),folder:z$1.string().optional().describe("Folder to save to")},async({title:t,concept:e,key_points:n,examples:r,application:c,source:a,related:l,folder:m})=>{try{let u=N("learning",{title:t,concept:e,key_points:n,examples:r,application:c,source:a,related:l}),d=`${m??i.inbox.folder}/${t}.md`;return await o.writeNote(d,u),{content:[{type:"text",text:`Learning saved at "${d}"`}]}}catch(u){return {content:[{type:"text",text:`Could not save learning: ${u instanceof Error?u.message:String(u)}`}],isError:true}}}),s.tool("remember_person","Create or update a note about a person \u2014 their role, organization, context, and interactions.",{name:z$1.string().describe("Person's name"),role:z$1.string().optional().default("").describe("Their role or title"),organization:z$1.string().optional().default("").describe("Their organization"),contact:z$1.string().optional().default("").describe("Contact information"),context:z$1.string().optional().default("").describe("How you know them or relevant context"),interaction:z$1.string().optional().default("").describe("Notes from recent interaction"),notes:z$1.string().optional().default("").describe("Additional notes"),folder:z$1.string().optional().describe("Folder to save to")},async({name:t,role:e,organization:n,contact:r,context:c,interaction:a,notes:l,folder:m})=>{try{let u=N("person",{name:t,role:e,organization:n,contact:r,context:c,interaction:a,notes:l}),d=`${m??i.inbox.folder}/${t}.md`;return await o.writeNote(d,u),{content:[{type:"text",text:`Person note created at "${d}"`}]}}catch(u){return {content:[{type:"text",text:`Could not create person note: ${u instanceof Error?u.message:String(u)}`}],isError:true}}}),s.tool("remember_reference","Bookmark a URL or resource with a summary, tags, and personal notes. Great for saving articles, videos, tools, or documentation.",{title:z$1.string().describe("Title of the resource"),url:z$1.string().describe("URL of the resource"),source:z$1.string().optional().default("").describe('Source (e.g., "Hacker News", "Twitter")'),summary:z$1.string().optional().default("").describe("Brief summary"),takeaways:z$1.string().optional().default("").describe("Key takeaways"),thoughts:z$1.string().optional().default("").describe("Your personal thoughts"),related:z$1.string().optional().default("").describe("Related notes"),tags:z$1.array(z$1.string()).optional().describe("Tags for categorization"),folder:z$1.string().optional().describe("Folder to save to")},async({title:t,url:e,source:n,summary:r,takeaways:c,thoughts:a,related:l,folder:m})=>{try{let u=N("article",{title:t,url:e,source:n,summary:r,takeaways:c,thoughts:a,related:l}),d=`${m??i.inbox.folder}/${t}.md`;return await o.writeNote(d,u),{content:[{type:"text",text:`Reference saved at "${d}"`}]}}catch(u){return {content:[{type:"text",text:`Could not save reference: ${u instanceof Error?u.message:String(u)}`}],isError:true}}});}function at(s,o,i){s.tool("log","Append an entry to today's daily note. Creates the daily note if it doesn't exist. Adds entries under a configurable heading with timestamps.",{entry:z$1.string().describe("The entry to add to the daily note"),heading:z$1.string().optional().default("Log").describe('Heading to add the entry under (default: "Log")')},async({entry:t,heading:e})=>{try{let n=`${i.dailyNotes.folder}/${x()}.md`,c=`
|
|
75
|
+
- ${new Date().toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit"})} \u2014 ${t}`;try{await o.readNote(n);try{await o.patchNote(n,c,{operation:"append",targetHeading:e});}catch{await o.appendToNote(n,`
|
|
76
76
|
## ${e}
|
|
77
|
-
${
|
|
77
|
+
${c}
|
|
78
78
|
`);}}catch{let a=`---
|
|
79
|
-
date: ${
|
|
79
|
+
date: ${x()}
|
|
80
80
|
tags:
|
|
81
81
|
- daily
|
|
82
82
|
---
|
|
83
83
|
|
|
84
|
-
# ${
|
|
84
|
+
# ${x()}
|
|
85
85
|
|
|
86
86
|
## ${e}
|
|
87
|
-
${
|
|
88
|
-
`;await
|
|
89
|
-
- [ ] ${t}`;try{await
|
|
87
|
+
${c}
|
|
88
|
+
`;await o.writeNote(n,a);}return {content:[{type:"text",text:`Logged to daily note (${x()}): ${t}`}]}}catch(n){return {content:[{type:"text",text:`Could not log entry: ${n instanceof Error?n.message:String(n)}`}],isError:true}}}),s.tool("log_task","Add a task (checkbox item) to today's daily note. Creates the daily note if it doesn't exist.",{task:z$1.string().describe("The task description"),heading:z$1.string().optional().default("Tasks").describe('Heading to add the task under (default: "Tasks")')},async({task:t,heading:e})=>{try{let n=`${i.dailyNotes.folder}/${x()}.md`,r=`
|
|
89
|
+
- [ ] ${t}`;try{await o.readNote(n);try{await o.patchNote(n,r,{operation:"append",targetHeading:e});}catch{await o.appendToNote(n,`
|
|
90
90
|
## ${e}
|
|
91
91
|
${r}
|
|
92
|
-
`);}}catch{let
|
|
93
|
-
date: ${
|
|
92
|
+
`);}}catch{let c=`---
|
|
93
|
+
date: ${x()}
|
|
94
94
|
tags:
|
|
95
95
|
- daily
|
|
96
96
|
---
|
|
97
97
|
|
|
98
|
-
# ${
|
|
98
|
+
# ${x()}
|
|
99
99
|
|
|
100
100
|
## ${e}
|
|
101
101
|
${r}
|
|
102
|
-
`;await
|
|
102
|
+
`;await o.writeNote(n,c);}return {content:[{type:"text",text:`Task added to daily note: ${t}`}]}}catch(n){return {content:[{type:"text",text:`Could not add task: ${n instanceof Error?n.message:String(n)}`}],isError:true}}}),s.tool("reflect","Generate reflection prompts based on recent vault activity. Reads today's and recent daily notes to suggest areas for reflection.",{},async()=>{try{let t="";try{let l=`${i.dailyNotes.folder}/${x()}.md`;t=await o.readNote(l);}catch{}let n=(await o.listFiles()).filter(l=>l.extension==="md"),c=["What was the most important thing you learned today?","What decision did you make that you want to remember?","What are you most proud of from today's work?","What would you do differently next time?","What's one thing you want to explore further?","Who helped you today, and how?","What's blocking you right now?","What's one thing you're grateful for today?"].sort(()=>Math.random()-.5).slice(0,4),a=`**Reflection Prompts for ${x()}:**
|
|
103
103
|
|
|
104
|
-
`;return a+=
|
|
104
|
+
`;return a+=c.map((l,m)=>`${m+1}. ${l}`).join(`
|
|
105
105
|
`),t&&(a+=`
|
|
106
106
|
|
|
107
107
|
---
|
|
@@ -111,89 +111,89 @@ ${t.slice(0,500)}`),a+=`
|
|
|
111
111
|
|
|
112
112
|
---
|
|
113
113
|
|
|
114
|
-
Vault stats: ${
|
|
114
|
+
Vault stats: ${n.length} notes total.`,a+="\n\nTip: Use `log` to add your reflections to today's daily note.",{content:[{type:"text",text:a}]}}catch(t){return {content:[{type:"text",text:`Reflection error: ${t instanceof Error?t.message:String(t)}`}],isError:true}}});}function ct(s,o,i){s.tool("create_note","Create a new note in the vault. Supports optional templates, folder routing, and frontmatter. Will not overwrite existing notes unless explicitly requested.",{path:z$1.string().describe('Path for the new note (e.g., "Projects/My Project.md")'),content:z$1.string().describe("Markdown content for the note"),template:z$1.enum(["decision","meeting","learning","idea","person","project","book","article","weekly-review","session"]).optional().describe("Optional template to use"),variables:z$1.record(z$1.string()).optional().describe("Template variables as key-value pairs"),overwrite:z$1.boolean().optional().default(false).describe("Whether to overwrite if note already exists")},async({path:t,content:e,template:n,variables:r,overwrite:c})=>{try{if(!c)try{return await o.readNote(t),{content:[{type:"text",text:`Note already exists at "${t}". Set overwrite=true to replace it.`}]}}catch{}let a=e;return n&&(a=N(n,{...r,content:e})),await o.writeNote(t,a),{content:[{type:"text",text:`Note created at "${t}"`}]}}catch(a){return {content:[{type:"text",text:`Could not create note: ${a instanceof Error?a.message:String(a)}`}],isError:true}}}),s.tool("append_to_note","Append content to the end of an existing note. The note must already exist.",{path:z$1.string().describe("Path to the note to append to"),content:z$1.string().describe("Content to append")},async({path:t,content:e})=>{try{return await o.appendToNote(t,`
|
|
115
115
|
${e}
|
|
116
|
-
`),{content:[{type:"text",text:`Content appended to "${t}"`}]}}catch(
|
|
117
|
-
- [[${e}]] \u2014 ${
|
|
118
|
-
- [[${e}]]`;try{await
|
|
116
|
+
`),{content:[{type:"text",text:`Content appended to "${t}"`}]}}catch(n){return {content:[{type:"text",text:`Could not append to note: ${n instanceof Error?n.message:String(n)}`}],isError:true}}}),s.tool("update_section","Replace the content under a specific heading in a note. Useful for updating a section without modifying the rest of the note.",{path:z$1.string().describe("Path to the note"),heading:z$1.string().describe("Heading text of the section to replace"),content:z$1.string().describe("New content for the section")},async({path:t,heading:e,content:n})=>{try{let r=await o.readNote(t),c=L(r,e,n);return await o.writeNote(t,c),{content:[{type:"text",text:`Section "${e}" updated in "${t}"`}]}}catch(r){return {content:[{type:"text",text:`Could not update section: ${r instanceof Error?r.message:String(r)}`}],isError:true}}});}function lt(s,o,i){s.tool("add_link",'Add a [[wikilink]] to a note, connecting it to another note in the vault. Appends the link under a "Related" heading or at the end of the note.',{path:z$1.string().describe("Path of the note to add the link to"),target:z$1.string().describe("Name of the note to link to (without .md extension)"),context:z$1.string().optional().describe("Optional context for why these notes are related")},async({path:t,target:e,context:n})=>{try{let r=await o.readNote(t);if(C(r).includes(e))return {content:[{type:"text",text:`"${t}" already links to [[${e}]]`}]};let a=n?`
|
|
117
|
+
- [[${e}]] \u2014 ${n}`:`
|
|
118
|
+
- [[${e}]]`;try{await o.patchNote(t,a,{operation:"append",targetHeading:"Related"});}catch{await o.appendToNote(t,`
|
|
119
119
|
## Related
|
|
120
120
|
${a}
|
|
121
|
-
`);}return {content:[{type:"text",text:`Added link to [[${e}]] in "${t}"`}]}}catch(r){return {content:[{type:"text",text:`Could not add link: ${r instanceof Error?r.message:String(r)}`}],isError:true}}}),s.tool("suggest_connections","Analyze a note and suggest other notes that could be linked to it. Uses shared tags, mentions, and content similarity to find connections.",{path:z$1.string().describe("Path to the note to analyze"),limit:z$1.number().optional().default(10).describe("Maximum suggestions to return")},async({path:t,limit:e})=>{try{let
|
|
122
|
-
${
|
|
121
|
+
`);}return {content:[{type:"text",text:`Added link to [[${e}]] in "${t}"`}]}}catch(r){return {content:[{type:"text",text:`Could not add link: ${r instanceof Error?r.message:String(r)}`}],isError:true}}}),s.tool("suggest_connections","Analyze a note and suggest other notes that could be linked to it. Uses shared tags, mentions, and content similarity to find connections.",{path:z$1.string().describe("Path to the note to analyze"),limit:z$1.number().optional().default(10).describe("Maximum suggestions to return")},async({path:t,limit:e})=>{try{let n=await o.readNote(t),r=C(n),c=$(n),a=new Map;for(let f of c.slice(0,5))try{let d=await o.search(`tag:#${f}`);for(let p of d)if(p.filename!==t&&!r.includes(p.filename.replace(/\.md$/,""))){let h=a.get(p.filename)??[];h.push(`Shared tag: #${f}`),a.set(p.filename,h);}}catch{}let l=n.split(/\s+/).filter(f=>f.length>5).slice(0,10);for(let f of l.slice(0,3))try{let d=await o.search(f);for(let p of d.slice(0,5))if(p.filename!==t&&!r.includes(p.filename.replace(/\.md$/,""))){let h=a.get(p.filename)??[];h.some(y=>y.startsWith("Mentions:"))||(h.push(`Mentions: "${f}"`),a.set(p.filename,h));}}catch{}let m=[...a.entries()].sort((f,d)=>d[1].length-f[1].length).slice(0,e);if(m.length===0)return {content:[{type:"text",text:`No connection suggestions found for "${t}". The note may be well-connected already!`}]};let u=m.map(([f,d],p)=>`${p+1}. **${f}**
|
|
122
|
+
${d.join(", ")}`).join(`
|
|
123
123
|
|
|
124
124
|
`);return {content:[{type:"text",text:`Suggested connections for "${t}":
|
|
125
125
|
|
|
126
126
|
${u}
|
|
127
127
|
|
|
128
|
-
Use \`add_link\` to connect any of these notes.`}]}}catch(
|
|
128
|
+
Use \`add_link\` to connect any of these notes.`}]}}catch(n){return {content:[{type:"text",text:`Could not suggest connections: ${n instanceof Error?n.message:String(n)}`}],isError:true}}}),s.tool("find_gaps","Find broken links in the vault \u2014 [[wikilinks]] that point to notes that don't exist. These represent knowledge gaps or notes waiting to be written.",{limit:z$1.number().optional().default(20).describe("Maximum gaps to return")},async({limit:t})=>{try{let e=await o.listFiles(),n=new Set(e.filter(f=>f.extension==="md").map(f=>f.name.toLowerCase())),r=new Map,c=e.filter(f=>f.extension==="md"),a=Math.min(c.length,100),l=c.sort(()=>Math.random()-.5).slice(0,a);for(let f of l)try{let d=await o.readNote(f.path),p=C(d);for(let h of p)if(!n.has(h.toLowerCase())){let y=r.get(h)??[];y.push(f.path),r.set(h,y);}}catch{}let m=[...r.entries()].sort((f,d)=>d[1].length-f[1].length).slice(0,t);return m.length===0?{content:[{type:"text",text:`No broken links found (sampled ${a} of ${c.length} notes).`}]}:{content:[{type:"text",text:`Knowledge gaps (broken links) found in vault:
|
|
129
129
|
|
|
130
|
-
${
|
|
130
|
+
${m.map(([f,d],p)=>`${p+1}. **[[${f}]]** \u2014 referenced by ${d.length} note(s): ${d.slice(0,3).join(", ")}${d.length>3?"...":""}`).join(`
|
|
131
131
|
`)}
|
|
132
132
|
|
|
133
|
-
These are concepts referenced but not yet written about. Use \`create_note\` to fill them in.`}]}}catch(e){return {content:[{type:"text",text:`Could not find gaps: ${e instanceof Error?e.message:String(e)}`}],isError:true}}}),s.tool("find_orphans","Find orphan notes \u2014 notes with no incoming or outgoing links. These are disconnected from the knowledge graph and might need connecting.",{limit:z$1.number().optional().default(20).describe("Maximum orphans to return")},async({limit:t})=>{try{let
|
|
133
|
+
These are concepts referenced but not yet written about. Use \`create_note\` to fill them in.`}]}}catch(e){return {content:[{type:"text",text:`Could not find gaps: ${e instanceof Error?e.message:String(e)}`}],isError:true}}}),s.tool("find_orphans","Find orphan notes \u2014 notes with no incoming or outgoing links. These are disconnected from the knowledge graph and might need connecting.",{limit:z$1.number().optional().default(20).describe("Maximum orphans to return")},async({limit:t})=>{try{let n=(await o.listFiles()).filter(u=>u.extension==="md"),r=new Set,c=Math.min(n.length,100),a=n.sort(()=>Math.random()-.5).slice(0,c);for(let u of a)try{let f=await o.readNote(u.path),d=C(f);if(d.length>0){r.add(u.path);for(let p of d){let h=n.find(y=>y.name.toLowerCase()===p.toLowerCase());h&&r.add(h.path);}}}catch{}let l=a.filter(u=>!r.has(u.path)).slice(0,t);return l.length===0?{content:[{type:"text",text:`No orphan notes found (sampled ${c} notes). Your vault is well-connected!`}]}:{content:[{type:"text",text:`Orphan notes (no links in or out):
|
|
134
134
|
|
|
135
|
-
${
|
|
135
|
+
${l.map((u,f)=>`${f+1}. ${u.path}`).join(`
|
|
136
136
|
`)}
|
|
137
137
|
|
|
138
|
-
Consider linking these to related notes using \`add_link\` or \`suggest_connections\`.`}]}}catch(e){return {content:[{type:"text",text:`Could not find orphans: ${e instanceof Error?e.message:String(e)}`}],isError:true}}});}function
|
|
139
|
-
`),u=Object.entries(r).filter(([
|
|
138
|
+
Consider linking these to related notes using \`add_link\` or \`suggest_connections\`.`}]}}catch(e){return {content:[{type:"text",text:`Could not find orphans: ${e instanceof Error?e.message:String(e)}`}],isError:true}}});}function dt(s,o,i){s.tool("add_tag","Add one or more tags to a note. Tags are added to the YAML frontmatter. If the note has no frontmatter, it will be created.",{path:z$1.string().describe("Path to the note"),tags:z$1.array(z$1.string()).describe("Tags to add (without # prefix)")},async({path:t,tags:e})=>{try{let n=await o.readNote(t),{frontmatter:r,body:c}=M(n),a=[];if(r.tags){let d=r.tags;d.startsWith("[")?a.push(...d.slice(1,-1).split(",").map(p=>p.trim())):a.push(d);}let m=[...new Set([...a,...e])].map(d=>` - ${d}`).join(`
|
|
139
|
+
`),u=Object.entries(r).filter(([d])=>d!=="tags").map(([d,p])=>`${d}: ${p}`).join(`
|
|
140
140
|
`),f=`---
|
|
141
141
|
${u}${u?`
|
|
142
142
|
`:""}tags:
|
|
143
|
-
${
|
|
143
|
+
${m}
|
|
144
144
|
---
|
|
145
145
|
|
|
146
|
-
${
|
|
147
|
-
${Object.entries(a).map(([f,
|
|
146
|
+
${c}`;return await o.writeNote(t,f),{content:[{type:"text",text:`Added tags ${e.map(d=>`#${d}`).join(", ")} to "${t}"`}]}}catch(n){return {content:[{type:"text",text:`Could not add tags: ${n instanceof Error?n.message:String(n)}`}],isError:true}}}),s.tool("update_properties","Update YAML frontmatter properties of a note. Can add new properties or modify existing ones.",{path:z$1.string().describe("Path to the note"),properties:z$1.record(z$1.string()).describe('Properties to set as key-value pairs (e.g., {"status": "done", "priority": "high"})')},async({path:t,properties:e})=>{try{let n=await o.readNote(t),{frontmatter:r,body:c}=M(n),a={...r,...e},m=`---
|
|
147
|
+
${Object.entries(a).map(([f,d])=>`${f}: ${d}`).join(`
|
|
148
148
|
`)}
|
|
149
149
|
---
|
|
150
150
|
|
|
151
|
-
${
|
|
151
|
+
${c}`;await o.writeNote(t,m);let u=Object.entries(e).map(([f,d])=>`${f}: ${d}`).join(", ");return {content:[{type:"text",text:`Updated properties in "${t}": ${u}`}]}}catch(n){return {content:[{type:"text",text:`Could not update properties: ${n instanceof Error?n.message:String(n)}`}],isError:true}}}),s.tool("rename_note","Rename a note by creating a copy at the new path and deleting the original. Note: Obsidian will update backlinks if the app is running.",{old_path:z$1.string().describe("Current path of the note"),new_path:z$1.string().describe("New path for the note")},async({old_path:t,new_path:e})=>{try{let n=await o.readNote(t);try{return await o.readNote(e),{content:[{type:"text",text:`A note already exists at "${e}". Choose a different name.`}]}}catch{}return await o.writeNote(e,n),await o.deleteNote(t),{content:[{type:"text",text:`Renamed "${t}" to "${e}"`}]}}catch(n){return {content:[{type:"text",text:`Could not rename note: ${n instanceof Error?n.message:String(n)}`}],isError:true}}}),s.tool("move_note","Move a note to a different folder in the vault. Preserves the filename.",{path:z$1.string().describe("Current path of the note"),destination:z$1.string().describe('Destination folder (e.g., "Projects", "Archive")')},async({path:t,destination:e})=>{try{let n=await o.readNote(t),r=t.split("/").pop()??t,c=`${e}/${r}`;try{return await o.readNote(c),{content:[{type:"text",text:`A note already exists at "${c}". Rename the note first.`}]}}catch{}return await o.writeNote(c,n),await o.deleteNote(t),{content:[{type:"text",text:`Moved "${t}" to "${c}"`}]}}catch(n){return {content:[{type:"text",text:`Could not move note: ${n instanceof Error?n.message:String(n)}`}],isError:true}}});}function ft(s,o,i){s.tool("vault_overview","Get an overview of your Obsidian vault: total notes, folder structure, tag distribution, and general statistics.",{},async()=>{try{let t=await o.listFiles(),e=t.filter(d=>d.extension==="md"),n=t.filter(d=>d.extension!=="md"),r=new Map;for(let d of e){let p=d.path.split("/"),h=p.length>1?p.slice(0,-1).join("/"):"(root)";r.set(h,(r.get(h)??0)+1);}let c=[...r.entries()].sort((d,p)=>p[1]-d[1]).slice(0,15),a=new Map,l=Math.min(e.length,50),m=e.slice(0,l);for(let d of m)try{let p=await o.readNote(d.path),h=$(p);for(let y of h)a.set(y,(a.get(y)??0)+1);}catch{}let u=[...a.entries()].sort((d,p)=>p[1]-d[1]).slice(0,15),f=`**Vault Overview**
|
|
152
152
|
|
|
153
153
|
`;return f+=`- **Total notes:** ${e.length}
|
|
154
|
-
`,f+=`- **Other files:** ${
|
|
154
|
+
`,f+=`- **Other files:** ${n.length} (images, PDFs, etc.)
|
|
155
155
|
`,f+=`- **Folders:** ${r.size}
|
|
156
156
|
|
|
157
157
|
`,f+=`**Top Folders:**
|
|
158
|
-
`,f+=
|
|
158
|
+
`,f+=c.map(([d,p])=>` - ${d}: ${p} notes`).join(`
|
|
159
159
|
`),u.length>0&&(f+=`
|
|
160
160
|
|
|
161
|
-
**Top Tags** (sampled from ${
|
|
162
|
-
`,f+=u.map(([
|
|
163
|
-
`)),{content:[{type:"text",text:f}]}}catch(t){return {content:[{type:"text",text:`Could not get vault overview: ${t instanceof Error?t.message:String(t)}`}],isError:true}}}),s.tool("list_tags","List all tags used in the vault with their occurrence counts. Samples notes to build the tag list.",{limit:z$1.number().optional().default(50).describe("Maximum tags to return")},async({limit:t})=>{try{let
|
|
164
|
-
`);return {content:[{type:"text",text:`**Tags in vault** (sampled ${
|
|
161
|
+
**Top Tags** (sampled from ${l} notes):
|
|
162
|
+
`,f+=u.map(([d,p])=>` - #${d}: ${p}`).join(`
|
|
163
|
+
`)),{content:[{type:"text",text:f}]}}catch(t){return {content:[{type:"text",text:`Could not get vault overview: ${t instanceof Error?t.message:String(t)}`}],isError:true}}}),s.tool("list_tags","List all tags used in the vault with their occurrence counts. Samples notes to build the tag list.",{limit:z$1.number().optional().default(50).describe("Maximum tags to return")},async({limit:t})=>{try{let n=(await o.listFiles()).filter(u=>u.extension==="md"),r=new Map,c=Math.min(n.length,200),a=n.slice(0,c);for(let u of a)try{let f=await o.readNote(u.path),d=$(f);for(let p of d)r.set(p,(r.get(p)??0)+1);}catch{}let l=[...r.entries()].sort((u,f)=>f[1]-u[1]).slice(0,t);if(l.length===0)return {content:[{type:"text",text:"No tags found in vault."}]};let m=l.map(([u,f])=>`#${u} (${f})`).join(`
|
|
164
|
+
`);return {content:[{type:"text",text:`**Tags in vault** (sampled ${c} of ${n.length} notes):
|
|
165
165
|
|
|
166
|
-
${
|
|
166
|
+
${m}`}]}}catch(e){return {content:[{type:"text",text:`Could not list tags: ${e instanceof Error?e.message:String(e)}`}],isError:true}}}),s.tool("get_vault_structure","Get the folder structure of the vault as a tree with note counts per folder. Useful for understanding vault organization.",{},async()=>{try{let e=(await o.listFiles()).filter(a=>a.extension==="md"),n=new Map;for(let a of e){let l=a.path.split("/");if(l.length>1)for(let m=1;m<l.length;m++){let u=l.slice(0,m).join("/");m===l.length-1?n.set(u,(n.get(u)??0)+1):n.has(u)||n.set(u,0);}else n.set("(root)",(n.get("(root)")??0)+1);}let c=[...n.entries()].sort((a,l)=>a[0].localeCompare(l[0])).map(([a,l])=>{let m=a.split("/").length-1,u=" ".repeat(m),f=a.split("/").pop()??a;return `${u}${f}/ (${l} notes)`}).join(`
|
|
167
167
|
`);return {content:[{type:"text",text:`**Vault Structure** (${e.length} total notes):
|
|
168
168
|
|
|
169
|
-
${
|
|
170
|
-
*${
|
|
169
|
+
${c}`}]}}catch(t){return {content:[{type:"text",text:`Could not get vault structure: ${t instanceof Error?t.message:String(t)}`}],isError:true}}});}function ut(s,o,i){s.tool("find_tasks","Find all checkbox tasks across the vault. Filter by status (open, done, or all). Returns tasks with their source note and line number.",{status:z$1.enum(["open","done","all"]).optional().default("open").describe("Filter by task status"),query:z$1.string().optional().describe("Optional search query to filter tasks by text"),limit:z$1.number().optional().default(30).describe("Maximum tasks to return")},async({status:t,query:e,limit:n})=>{try{let c=(await o.listFiles()).filter(d=>d.extension==="md"),a=[],l=Math.min(c.length,100),m=c.slice(0,l);for(let d of m)try{let p=await o.readNote(d.path),h=B(p);for(let y of h)e&&!y.text.toLowerCase().includes(e.toLowerCase())||t==="open"&&y.done||t==="done"&&!y.done||a.push({text:y.text,done:y.done,file:d.path,line:y.line});}catch{}if(a.length===0)return {content:[{type:"text",text:`No ${t==="all"?"":t+" "}tasks found${e?` matching "${e}"`:""}.`}]};let u=a.slice(0,n),f=u.map((d,p)=>`${p+1}. [${d.done?"x":" "}] ${d.text}
|
|
170
|
+
*${d.file}:${d.line}*`).join(`
|
|
171
171
|
|
|
172
172
|
`);return {content:[{type:"text",text:`**${t==="all"?"All":t==="open"?"Open":"Completed"} Tasks** (${a.length} found, showing ${u.length}):
|
|
173
173
|
|
|
174
|
-
${f}`}]}}catch(r){return {content:[{type:"text",text:`Could not find tasks: ${r instanceof Error?r.message:String(r)}`}],isError:true}}}),s.tool("complete_task","Mark a specific task as done by replacing [ ] with [x] at the given line in a note.",{path:z$1.string().describe("Path to the note containing the task"),line:z$1.number().describe("Line number of the task (1-based)")},async({path:t,line:e})=>{try{let r=(await
|
|
175
|
-
`);if(e<1||e>r.length)return {content:[{type:"text",text:`Line ${e} is out of range (note has ${r.length} lines)`}],isError:!0};let
|
|
176
|
-
`)),{content:[{type:"text",text:`Completed task: "${a[2].trim()}" in "${t}"`}]}):{content:[{type:"text",text:`Line ${e} is not an open task: "${
|
|
174
|
+
${f}`}]}}catch(r){return {content:[{type:"text",text:`Could not find tasks: ${r instanceof Error?r.message:String(r)}`}],isError:true}}}),s.tool("complete_task","Mark a specific task as done by replacing [ ] with [x] at the given line in a note.",{path:z$1.string().describe("Path to the note containing the task"),line:z$1.number().describe("Line number of the task (1-based)")},async({path:t,line:e})=>{try{let r=(await o.readNote(t)).split(`
|
|
175
|
+
`);if(e<1||e>r.length)return {content:[{type:"text",text:`Line ${e} is out of range (note has ${r.length} lines)`}],isError:!0};let c=r[e-1],a=c.match(/^(\s*-\s+)\[[ ]\](\s+.+)$/);return a?(r[e-1]=`${a[1]}[x]${a[2]}`,await o.writeNote(t,r.join(`
|
|
176
|
+
`)),{content:[{type:"text",text:`Completed task: "${a[2].trim()}" in "${t}"`}]}):{content:[{type:"text",text:`Line ${e} is not an open task: "${c.trim()}"`}],isError:!0}}catch(n){return {content:[{type:"text",text:`Could not complete task: ${n instanceof Error?n.message:String(n)}`}],isError:true}}});}function mt(s,o,i){s.resource("today","vault://today",{description:"Today's daily note content. Auto-updates with the current day's note.",mimeType:"text/markdown"},async t=>{try{let e=`${i.dailyNotes.folder}/${x()}.md`,n=await o.readNote(e);return {contents:[{uri:t.href,text:`# Today's Daily Note (${x()})
|
|
177
177
|
|
|
178
|
-
${
|
|
178
|
+
${n}`,mimeType:"text/markdown"}]}}catch{return {contents:[{uri:t.href,text:`No daily note for today (${x()}).`,mimeType:"text/plain"}]}}}),s.resource("recent","vault://recent",{description:"Summary of recently modified notes in the vault.",mimeType:"text/markdown"},async t=>{try{let r=(await o.listFiles()).filter(c=>c.extension==="md").slice(0,10).map((c,a)=>`${a+1}. ${c.path}`).join(`
|
|
179
179
|
`);return {contents:[{uri:t.href,text:`# Recent Notes
|
|
180
180
|
|
|
181
|
-
${r}`,mimeType:"text/markdown"}]}}catch{return {contents:[{uri:t.href,text:"Could not fetch recent notes.",mimeType:"text/plain"}]}}}),s.resource("tags","vault://tags",{description:"Tag cloud with counts from the vault.",mimeType:"text/markdown"},async t=>{try{let
|
|
181
|
+
${r}`,mimeType:"text/markdown"}]}}catch{return {contents:[{uri:t.href,text:"Could not fetch recent notes.",mimeType:"text/plain"}]}}}),s.resource("tags","vault://tags",{description:"Tag cloud with counts from the vault.",mimeType:"text/markdown"},async t=>{try{let n=(await o.listFiles()).filter(m=>m.extension==="md"),r=new Map,c=Math.min(n.length,50);for(let m of n.slice(0,c))try{let u=await o.readNote(m.path);for(let f of $(u))r.set(f,(r.get(f)??0)+1);}catch{}let l=[...r.entries()].sort((m,u)=>u[1]-m[1]).slice(0,30).map(([m,u])=>`- #${m} (${u})`).join(`
|
|
182
182
|
`);return {contents:[{uri:t.href,text:`# Vault Tags
|
|
183
183
|
|
|
184
|
-
${
|
|
184
|
+
${l||"No tags found."}`,mimeType:"text/markdown"}]}}catch{return {contents:[{uri:t.href,text:"Could not fetch tags.",mimeType:"text/plain"}]}}}),s.resource("context","vault://context",{description:"Contextual notes relevant to the current working directory or project. Auto-infers which notes may be useful.",mimeType:"text/markdown"},async t=>{try{let n=process.cwd().split("/").pop()??"",r=[];if(n)try{r=(await o.search(n)).slice(0,5).map(l=>l.filename);}catch{}if(r.length===0)return {contents:[{uri:t.href,text:`# Context
|
|
185
185
|
|
|
186
|
-
No vault notes found related to the current project "${
|
|
187
|
-
`);return {contents:[{uri:t.href,text:`# Context for "${
|
|
186
|
+
No vault notes found related to the current project "${n}".`,mimeType:"text/markdown"}]};let c=r.map((a,l)=>`${l+1}. ${a}`).join(`
|
|
187
|
+
`);return {contents:[{uri:t.href,text:`# Context for "${n}"
|
|
188
188
|
|
|
189
189
|
Relevant vault notes:
|
|
190
190
|
|
|
191
|
-
${
|
|
192
|
-
`);}function
|
|
193
|
-
`);}function
|
|
194
|
-
`);}var
|
|
195
|
-
`)){let e=t.replace(/#.*$/,"").trimEnd();if(!e.trim())continue;let
|
|
196
|
-
MindCache v${
|
|
191
|
+
${c}`,mimeType:"text/markdown"}]}}catch{return {contents:[{uri:t.href,text:"Could not determine context.",mimeType:"text/plain"}]}}});}var q="mindcache";function S(s){process.stderr.write(`[${q}] ${s}
|
|
192
|
+
`);}function O(s){process.stderr.write(`[${q}] ERROR: ${s}
|
|
193
|
+
`);}function pt(s){process.stderr.write(`[${q}] WARN: ${s}
|
|
194
|
+
`);}var D="0.2.0";function gt(s){let o=new McpServer({name:"mindcache",version:D},{instructions:["MindCache connects your Obsidian vault to AI.","Use the search and ask tools to find information in the user's personal knowledge base.","Use the remember tools to capture decisions, meetings, ideas, learnings, and references.","Use the log tool to add entries to the daily note.","Use the connect tools to build links between related notes.","Always check the vault before asking the user to repeat information they may have already documented.","When creating notes, use appropriate templates and add relevant tags."].join(" ")}),i=new E(s);return S("Registering tools..."),ot(o,i),rt(o,i,s),it(o,i,s),at(o,i,s),ct(o,i),lt(o,i),dt(o,i),ft(o,i),ut(o,i),S("Registering resources..."),mt(o,i,s),S("Server configured with 40 tools and 4 resources"),o}var H={vault:"",dailyNotes:{folder:"Daily",format:"YYYY-MM-DD"},templates:{folder:"Templates/MindCache"},inbox:{folder:"MindCache/Inbox",requireReview:false}};function It(s){let o={},i="";for(let t of s.split(`
|
|
195
|
+
`)){let e=t.replace(/#.*$/,"").trimEnd();if(!e.trim())continue;let n=e.length-e.trimStart().length,r=e.trim(),c=r.indexOf(":");if(c<0)continue;let a=r.slice(0,c).trim(),l=r.slice(c+1).trim();n===0&&!l?(i=a,o[i]||(o[i]={})):n>0&&i?o[i][a]=l:o[a]=l;}return o}function Yt(){let s=[resolve(process.cwd(),".mindcache.yml"),resolve(process.cwd(),".mindcache.yaml"),join(homedir(),".config","mindcache","config.yml"),join(homedir(),".config","mindcache","config.yaml"),join(homedir(),".mindcache.yml")];for(let o of s)if(existsSync(o))return o;return null}function j(){let s={vault:H.vault,dailyNotes:{...H.dailyNotes},templates:{...H.templates},inbox:{...H.inbox}};process.env.MINDCACHE_VAULT&&(s.vault=process.env.MINDCACHE_VAULT);let o=process.env.MINDCACHE_CONFIG||Yt();if(o&&existsSync(o)){S(`Loading config from ${o}`);try{let i=readFileSync(o,"utf-8"),t=It(i);typeof t.vault=="string"&&(s.vault=t.vault);let e=t.daily_notes??t.dailyNotes;e&&(e.folder&&(s.dailyNotes.folder=e.folder),e.format&&(s.dailyNotes.format=e.format));let n=t.templates;n&&n.folder&&(s.templates.folder=n.folder);let r=t.inbox;r&&(r.folder&&(s.inbox.folder=r.folder),r.require_review&&(s.inbox.requireReview=r.require_review==="true"));}catch(i){pt(`Failed to parse config: ${i instanceof Error?i.message:String(i)}`);}}return s.vault.startsWith("~")&&(s.vault=s.vault.replace("~",homedir())),s}var Gt=`
|
|
196
|
+
MindCache v${D} \u2014 Your Obsidian vault, connected to AI.
|
|
197
197
|
|
|
198
198
|
Usage:
|
|
199
199
|
mindcache Start the MCP server (default)
|
|
@@ -213,18 +213,18 @@ Config file locations (checked in order):
|
|
|
213
213
|
~/.mindcache.yml
|
|
214
214
|
|
|
215
215
|
Learn more: https://usemindcache.com
|
|
216
|
-
`;async function
|
|
216
|
+
`;async function wt(s){let o=createInterface({input:process.stdin,output:process.stderr});return new Promise(i=>{o.question(s,t=>{o.close(),i(t.trim());});})}async function Kt(){process.stderr.write(`
|
|
217
217
|
MindCache Setup
|
|
218
218
|
`),process.stderr.write(`===============
|
|
219
219
|
|
|
220
220
|
`),process.stderr.write(`MindCache reads your Obsidian vault directly from the filesystem.
|
|
221
221
|
`),process.stderr.write(`No plugins required \u2014 just point it at your vault folder.
|
|
222
222
|
|
|
223
|
-
`);let s=join(homedir(),"Documents","Obsidian Vault"),
|
|
224
|
-
vault: ${
|
|
223
|
+
`);let s=join(homedir(),"Documents","Obsidian Vault"),o=await wt(`Obsidian vault path [${s}]: `)||s,i=await wt("Daily notes folder [Daily]: ")||"Daily",t=`# MindCache Configuration
|
|
224
|
+
vault: ${o}
|
|
225
225
|
|
|
226
226
|
daily_notes:
|
|
227
|
-
folder: ${
|
|
227
|
+
folder: ${i}
|
|
228
228
|
format: YYYY-MM-DD
|
|
229
229
|
|
|
230
230
|
templates:
|
|
@@ -233,11 +233,11 @@ templates:
|
|
|
233
233
|
inbox:
|
|
234
234
|
folder: MindCache/Inbox
|
|
235
235
|
require_review: false
|
|
236
|
-
`,e=join(homedir(),".config","mindcache");existsSync(e)||mkdirSync(e,{recursive:true});let
|
|
237
|
-
Config saved to: ${
|
|
236
|
+
`,e=join(homedir(),".config","mindcache");existsSync(e)||mkdirSync(e,{recursive:true});let n=join(e,"config.yml");writeFileSync(n,t),process.stderr.write(`
|
|
237
|
+
Config saved to: ${n}
|
|
238
238
|
|
|
239
239
|
`),process.stderr.write(`Checking vault...
|
|
240
|
-
`);let r=j(),a=await new
|
|
240
|
+
`);let r=j(),a=await new E(r).health();a.ok?process.stderr.write(` Found ${a.noteCount} notes in vault
|
|
241
241
|
|
|
242
242
|
`):(process.stderr.write(` ${a.error}
|
|
243
243
|
`),process.stderr.write(` Check that the vault path is correct.
|
|
@@ -245,8 +245,8 @@ Config saved to: ${o}
|
|
|
245
245
|
`)),process.stderr.write(`Add MindCache to Claude Code:
|
|
246
246
|
`),process.stderr.write(` claude mcp add --scope user mindcache -- npx @augmnt-sh/mindcache
|
|
247
247
|
|
|
248
|
-
`),process.exit(0);}async function
|
|
249
|
-
MindCache Doctor v${
|
|
248
|
+
`),process.exit(0);}async function Bt(){process.stderr.write(`
|
|
249
|
+
MindCache Doctor v${D}
|
|
250
250
|
`),process.stderr.write(`==========================
|
|
251
251
|
|
|
252
252
|
`);let s=j();process.stderr.write(`Checking configuration...
|
|
@@ -257,16 +257,16 @@ MindCache Doctor v${F}
|
|
|
257
257
|
`),process.stderr.write(` [OK] Inbox: ${s.inbox.folder}/
|
|
258
258
|
`),process.stderr.write(`
|
|
259
259
|
Checking vault access...
|
|
260
|
-
`);let
|
|
261
|
-
`),process.stderr.write(` [OK] Found ${
|
|
262
|
-
`)):(process.stderr.write(` [FAIL] ${
|
|
260
|
+
`);let i=await new E(s).health();i.ok?(process.stderr.write(` [OK] Vault readable
|
|
261
|
+
`),process.stderr.write(` [OK] Found ${i.noteCount} markdown notes
|
|
262
|
+
`)):(process.stderr.write(` [FAIL] ${i.error}
|
|
263
263
|
`),process.stderr.write(`
|
|
264
264
|
Troubleshooting:
|
|
265
265
|
`),process.stderr.write(` 1. Check that the vault path is correct
|
|
266
266
|
`),process.stderr.write(` 2. Check file permissions
|
|
267
267
|
`),process.stderr.write(` 3. Run: mindcache init
|
|
268
268
|
`)),process.stderr.write(`
|
|
269
|
-
`),process.exit(
|
|
269
|
+
`),process.exit(i.ok?0:1);}function Jt(){let s=j();process.stderr.write(`
|
|
270
270
|
MindCache Configuration
|
|
271
271
|
`),process.stderr.write(`=======================
|
|
272
272
|
|
|
@@ -277,6 +277,6 @@ MindCache Configuration
|
|
|
277
277
|
`),process.stderr.write(`Inbox: ${s.inbox.folder}
|
|
278
278
|
`),process.stderr.write(`Review mode: ${s.inbox.requireReview?"on":"off"}
|
|
279
279
|
`),process.stderr.write(`
|
|
280
|
-
`),process.exit(0);}async function
|
|
281
|
-
`),process.exit(0);break;case "--help":case "-h":process.stderr.write(
|
|
280
|
+
`),process.exit(0);}async function Qt(){let s=process.version;parseInt(s.slice(1))<18&&(O(`Node.js >= 18 required, found ${s}`),process.exit(1)),S(`mindcache v${D} | Node ${s} | ${process.platform}`);let i=j();i.vault||S('WARN: No vault path configured. Run "mindcache init" for setup.');let t=gt(i),e=new StdioServerTransport,n=async()=>{S("Shutting down..."),await t.close(),process.exit(0);};process.on("SIGINT",n),process.on("SIGTERM",n),await t.connect(e);}var Xt=process.argv[2];switch(Xt){case "init":Kt().catch(s=>{O(s instanceof Error?s.message:String(s)),process.exit(1);});break;case "doctor":Bt().catch(s=>{O(s instanceof Error?s.message:String(s)),process.exit(1);});break;case "config":Jt();break;case "--version":case "-v":process.stderr.write(`mindcache v${D}
|
|
281
|
+
`),process.exit(0);break;case "--help":case "-h":process.stderr.write(Gt),process.exit(0);break;default:Qt().catch(s=>{O(`Fatal: ${s instanceof Error?s.message:String(s)}`),process.exit(1);});}//# sourceMappingURL=cli.js.map
|
|
282
282
|
//# sourceMappingURL=cli.js.map
|