@bitbonsai/mcpvault 0.11.0 → 0.11.3
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/README.md +9 -3
- package/dist/src/createServer.d.ts.map +1 -1
- package/dist/src/createServer.js +5 -3
- package/dist/src/filesystem.d.ts.map +1 -1
- package/dist/src/filesystem.js +81 -27
- package/dist/src/frontmatter.d.ts +1 -0
- package/dist/src/frontmatter.d.ts.map +1 -1
- package/dist/src/frontmatter.js +31 -3
- package/dist/src/pathfilter.d.ts.map +1 -1
- package/dist/src/pathfilter.js +6 -0
- package/dist/src/types.d.ts +2 -0
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -122,7 +122,7 @@ MCP is an open protocol. You're not tied to any specific vendor or platform. You
|
|
|
122
122
|
|
|
123
123
|
## Features
|
|
124
124
|
|
|
125
|
-
- ✅ Safe frontmatter parsing and validation using gray-matter
|
|
125
|
+
- ✅ Safe frontmatter parsing and validation using gray-matter with AST-aware updates that preserve raw formatting for unmodified fields
|
|
126
126
|
- ✅ Path filtering to exclude `.obsidian` directory and other system files
|
|
127
127
|
- ✅ **Complete MCP toolkit**: 14 methods covering all vault operations
|
|
128
128
|
- File operations: `read_note`, `write_note`, `patch_note`, `delete_note`, `move_note`, `move_file`
|
|
@@ -595,7 +595,8 @@ Delete a note from the vault (requires confirmation for safety).
|
|
|
595
595
|
"name": "delete_note",
|
|
596
596
|
"arguments": {
|
|
597
597
|
"path": "old-draft.md",
|
|
598
|
-
"confirmPath": "old-draft.md"
|
|
598
|
+
"confirmPath": "old-draft.md",
|
|
599
|
+
"trashMode": "local"
|
|
599
600
|
}
|
|
600
601
|
}
|
|
601
602
|
```
|
|
@@ -606,10 +607,15 @@ Delete a note from the vault (requires confirmation for safety).
|
|
|
606
607
|
{
|
|
607
608
|
"success": true,
|
|
608
609
|
"path": "old-draft.md",
|
|
609
|
-
"message": "Successfully
|
|
610
|
+
"message": "Successfully moved note to vault trash: old-draft.md"
|
|
610
611
|
}
|
|
611
612
|
```
|
|
612
613
|
|
|
614
|
+
**Trash modes:**
|
|
615
|
+
- `none` (default): permanent delete
|
|
616
|
+
- `local`: move to `.trash` inside the vault, preserving folder structure
|
|
617
|
+
- `system`: move to the OS trash/recycle bin
|
|
618
|
+
|
|
613
619
|
**Response (Confirmation Failed):**
|
|
614
620
|
|
|
615
621
|
```json
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createServer.d.ts","sourceRoot":"","sources":["../../src/createServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAMnE,OAAO,EAAE,kBAAkB,EAAoB,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAI7C,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;CACzC;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"createServer.d.ts","sourceRoot":"","sources":["../../src/createServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAMnE,OAAO,EAAE,kBAAkB,EAAoB,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAI7C,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;CACzC;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAgZzF"}
|
package/dist/src/createServer.js
CHANGED
|
@@ -69,12 +69,13 @@ export function createServer(vaultPath, options = {}) {
|
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
71
|
name: "delete_note",
|
|
72
|
-
description: "Delete a note from the Obsidian vault (requires confirmation)",
|
|
72
|
+
description: "Delete a note from the Obsidian vault (requires confirmation). Supports permanent delete, vault trash, or system trash.",
|
|
73
73
|
inputSchema: {
|
|
74
74
|
type: "object",
|
|
75
75
|
properties: {
|
|
76
76
|
path: { type: "string", description: "Path to the note relative to vault root" },
|
|
77
|
-
confirmPath: { type: "string", description: "Confirmation: must exactly match the path parameter to proceed with deletion" }
|
|
77
|
+
confirmPath: { type: "string", description: "Confirmation: must exactly match the path parameter to proceed with deletion" },
|
|
78
|
+
trashMode: { type: "string", enum: ["none", "local", "system"], description: "Deletion mode: 'none' = permanent delete (default), 'local' = move to .trash inside vault, 'system' = move to OS trash", default: "none" }
|
|
78
79
|
},
|
|
79
80
|
required: ["path", "confirmPath"]
|
|
80
81
|
}
|
|
@@ -257,7 +258,8 @@ export function createServer(vaultPath, options = {}) {
|
|
|
257
258
|
case "delete_note": {
|
|
258
259
|
const result = await fileSystem.deleteNote({
|
|
259
260
|
path: trimmedArgs.path,
|
|
260
|
-
confirmPath: trimmedArgs.confirmPath
|
|
261
|
+
confirmPath: trimmedArgs.confirmPath,
|
|
262
|
+
trashMode: trimmedArgs.trashMode
|
|
261
263
|
});
|
|
262
264
|
return {
|
|
263
265
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../../src/filesystem.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../../src/filesystem.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,uBAAuB,EAAE,QAAQ,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,eAAe,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEzT,qBAAa,iBAAiB;IAK1B,OAAO,CAAC,SAAS;IAJnB,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,UAAU,CAAa;gBAGrB,SAAS,EAAE,MAAM,EACzB,UAAU,CAAC,EAAE,UAAU,EACvB,kBAAkB,CAAC,EAAE,kBAAkB;IAazC,OAAO,CAAC,WAAW;IA6Db,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAgC3C,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAmFjD,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;IA2F5D,aAAa,CAAC,IAAI,GAAE,MAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA8D3D,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAetC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAe3C,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAyG3D,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IAoFrD,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC;IA6HrD,iBAAiB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;IAgDpE,iBAAiB,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqCjE,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IA2ClD,UAAU,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAsG3E,YAAY,IAAI,MAAM;IAIhB,aAAa,CAAC,WAAW,GAAE,MAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAyD3D,WAAW,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAkDpE"}
|
package/dist/src/filesystem.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { join, resolve, relative, dirname } from 'path';
|
|
2
2
|
import { readdir, stat, readFile, writeFile, unlink, mkdir, access, rename, copyFile } from 'node:fs/promises';
|
|
3
3
|
import { constants, realpathSync } from 'node:fs';
|
|
4
|
+
import trash from 'trash';
|
|
4
5
|
import { FrontmatterHandler } from './frontmatter.js';
|
|
5
6
|
import { PathFilter } from './pathfilter.js';
|
|
6
7
|
import { generateObsidianUri } from './uri.js';
|
|
@@ -152,11 +153,15 @@ export class FileSystemService {
|
|
|
152
153
|
const mergedFrontmatter = frontmatter
|
|
153
154
|
? { ...existingNote.frontmatter, ...frontmatter }
|
|
154
155
|
: existingNote.frontmatter;
|
|
155
|
-
|
|
156
|
-
|
|
156
|
+
const mergedContent = mode === 'append'
|
|
157
|
+
? existingNote.content + content
|
|
158
|
+
: content + existingNote.content;
|
|
159
|
+
if (existingNote.matter && existingNote.matter.trim() !== '') {
|
|
160
|
+
// Preserve raw formatting for unmodified fields by only applying explicit updates
|
|
161
|
+
finalContent = this.frontmatterHandler.preserveStringify(existingNote.matter, frontmatter || {}, mergedContent);
|
|
157
162
|
}
|
|
158
|
-
else
|
|
159
|
-
finalContent = this.frontmatterHandler.stringify(mergedFrontmatter,
|
|
163
|
+
else {
|
|
164
|
+
finalContent = this.frontmatterHandler.stringify(mergedFrontmatter, mergedContent);
|
|
160
165
|
}
|
|
161
166
|
}
|
|
162
167
|
}
|
|
@@ -193,11 +198,11 @@ export class FileSystemService {
|
|
|
193
198
|
message: 'oldString cannot be empty'
|
|
194
199
|
};
|
|
195
200
|
}
|
|
196
|
-
if (
|
|
201
|
+
if (newString === undefined || newString === null) {
|
|
197
202
|
return {
|
|
198
203
|
success: false,
|
|
199
204
|
path,
|
|
200
|
-
message: 'newString
|
|
205
|
+
message: 'newString is required'
|
|
201
206
|
};
|
|
202
207
|
}
|
|
203
208
|
// Validate that oldString and newString are different
|
|
@@ -342,7 +347,7 @@ export class FileSystemService {
|
|
|
342
347
|
}
|
|
343
348
|
}
|
|
344
349
|
async deleteNote(params) {
|
|
345
|
-
const { path, confirmPath } = params;
|
|
350
|
+
const { path, confirmPath, trashMode = 'none' } = params;
|
|
346
351
|
// Confirmation check - paths must match exactly
|
|
347
352
|
if (path !== confirmPath) {
|
|
348
353
|
return {
|
|
@@ -369,6 +374,39 @@ export class FileSystemService {
|
|
|
369
374
|
message: `Cannot delete: ${path} is not a file`
|
|
370
375
|
};
|
|
371
376
|
}
|
|
377
|
+
if (trashMode === 'local') {
|
|
378
|
+
const trashDir = join(this.vaultPath, '.trash');
|
|
379
|
+
const trashPath = join(trashDir, path);
|
|
380
|
+
// Ensure trash directory exists
|
|
381
|
+
await mkdir(dirname(trashPath), { recursive: true });
|
|
382
|
+
// Handle collisions by appending a timestamp
|
|
383
|
+
let finalTrashPath = trashPath;
|
|
384
|
+
try {
|
|
385
|
+
await access(finalTrashPath, constants.F_OK);
|
|
386
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
387
|
+
const ext = path.endsWith('.md') ? '.md' : '';
|
|
388
|
+
const base = ext ? path.slice(0, -ext.length) : path;
|
|
389
|
+
const collidedPath = `${base}-${timestamp}${ext}`;
|
|
390
|
+
finalTrashPath = join(trashDir, collidedPath);
|
|
391
|
+
}
|
|
392
|
+
catch {
|
|
393
|
+
// File does not exist in trash, no collision
|
|
394
|
+
}
|
|
395
|
+
await rename(fullPath, finalTrashPath);
|
|
396
|
+
return {
|
|
397
|
+
success: true,
|
|
398
|
+
path: path,
|
|
399
|
+
message: `Successfully moved note to vault trash: ${path}`
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
if (trashMode === 'system') {
|
|
403
|
+
await trash(fullPath);
|
|
404
|
+
return {
|
|
405
|
+
success: true,
|
|
406
|
+
path: path,
|
|
407
|
+
message: `Successfully moved note to system trash: ${path}`
|
|
408
|
+
};
|
|
409
|
+
}
|
|
372
410
|
// Perform the deletion using Node.js native API
|
|
373
411
|
await unlink(fullPath);
|
|
374
412
|
return {
|
|
@@ -652,12 +690,20 @@ export class FileSystemService {
|
|
|
652
690
|
if (!validation.isValid) {
|
|
653
691
|
throw new Error(`Invalid frontmatter: ${validation.errors.join(', ')}`);
|
|
654
692
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
}
|
|
693
|
+
const fullPath = this.resolvePath(path);
|
|
694
|
+
if (merge && note.matter && note.matter.trim() !== '') {
|
|
695
|
+
// Preserve raw formatting for unmodified fields
|
|
696
|
+
const updatedContent = this.frontmatterHandler.preserveStringify(note.matter, frontmatter, note.content);
|
|
697
|
+
await writeFile(fullPath, updatedContent, 'utf-8');
|
|
698
|
+
}
|
|
699
|
+
else {
|
|
700
|
+
// Replace frontmatter entirely (or no existing matter to preserve)
|
|
701
|
+
await this.writeNote({
|
|
702
|
+
path,
|
|
703
|
+
content: note.content,
|
|
704
|
+
frontmatter: newFrontmatter
|
|
705
|
+
});
|
|
706
|
+
}
|
|
661
707
|
}
|
|
662
708
|
async getNotesInfo(paths) {
|
|
663
709
|
const results = await Promise.allSettled(paths.map(async (path) => {
|
|
@@ -740,23 +786,31 @@ export class FileSystemService {
|
|
|
740
786
|
else if (operation === 'remove') {
|
|
741
787
|
newTags = newTags.filter(tag => !tags.includes(tag));
|
|
742
788
|
}
|
|
743
|
-
//
|
|
744
|
-
const
|
|
745
|
-
...note.frontmatter
|
|
746
|
-
};
|
|
789
|
+
// Build tag updates for preserveStringify
|
|
790
|
+
const tagUpdates = {};
|
|
747
791
|
if (newTags.length > 0) {
|
|
748
|
-
|
|
792
|
+
tagUpdates.tags = newTags;
|
|
749
793
|
}
|
|
750
|
-
else
|
|
751
|
-
|
|
794
|
+
else {
|
|
795
|
+
tagUpdates.tags = undefined;
|
|
752
796
|
}
|
|
753
|
-
// Write back the note with updated frontmatter
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
797
|
+
// Write back the note with updated frontmatter, preserving raw formatting for unmodified fields
|
|
798
|
+
let updatedContent;
|
|
799
|
+
if (note.matter && note.matter.trim() !== '') {
|
|
800
|
+
updatedContent = this.frontmatterHandler.preserveStringify(note.matter, tagUpdates, note.content);
|
|
801
|
+
}
|
|
802
|
+
else {
|
|
803
|
+
const updatedFrontmatter = { ...note.frontmatter };
|
|
804
|
+
if (newTags.length > 0) {
|
|
805
|
+
updatedFrontmatter.tags = newTags;
|
|
806
|
+
}
|
|
807
|
+
else {
|
|
808
|
+
delete updatedFrontmatter.tags;
|
|
809
|
+
}
|
|
810
|
+
updatedContent = this.frontmatterHandler.stringify(updatedFrontmatter, note.content);
|
|
811
|
+
}
|
|
812
|
+
const fullPath = this.resolvePath(path);
|
|
813
|
+
await writeFile(fullPath, updatedContent, 'utf-8');
|
|
760
814
|
return {
|
|
761
815
|
path,
|
|
762
816
|
operation,
|
|
@@ -10,6 +10,7 @@ export declare class FrontmatterHandler {
|
|
|
10
10
|
stringify(frontmatterData: Record<string, any>, content: string): string;
|
|
11
11
|
validate(frontmatterData: Record<string, any>): FrontmatterValidationResult;
|
|
12
12
|
private checkForProblematicValues;
|
|
13
|
+
preserveStringify(rawMatter: string, updates: Record<string, any>, content: string): string;
|
|
13
14
|
extractFrontmatter(content: string): Record<string, any>;
|
|
14
15
|
updateFrontmatter(content: string, updates: Record<string, any>): string;
|
|
15
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/frontmatter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/frontmatter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAE1E;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAmB5E;AAED,qBAAa,kBAAkB;IAC7B,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU;IAoBlC,SAAS,CAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAaxE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,2BAA2B;IAqB3E,OAAO,CAAC,yBAAyB;IAmDjC,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM;IAyB3F,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAKxD,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM;CAWzE"}
|
package/dist/src/frontmatter.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import matter from 'gray-matter';
|
|
2
|
+
import { parseDocument } from 'yaml';
|
|
2
3
|
/**
|
|
3
4
|
* Parse a frontmatter value that may be a JSON string (LLM clients sometimes
|
|
4
5
|
* pass frontmatter as a serialized JSON string instead of an object).
|
|
@@ -32,7 +33,8 @@ export class FrontmatterHandler {
|
|
|
32
33
|
return {
|
|
33
34
|
frontmatter: parsed.data,
|
|
34
35
|
content: parsed.content,
|
|
35
|
-
originalContent: content
|
|
36
|
+
originalContent: content,
|
|
37
|
+
matter: parsed.matter
|
|
36
38
|
};
|
|
37
39
|
}
|
|
38
40
|
catch (error) {
|
|
@@ -40,7 +42,8 @@ export class FrontmatterHandler {
|
|
|
40
42
|
return {
|
|
41
43
|
frontmatter: {},
|
|
42
44
|
content: content,
|
|
43
|
-
originalContent: content
|
|
45
|
+
originalContent: content,
|
|
46
|
+
matter: ''
|
|
44
47
|
};
|
|
45
48
|
}
|
|
46
49
|
}
|
|
@@ -113,6 +116,31 @@ export class FrontmatterHandler {
|
|
|
113
116
|
}
|
|
114
117
|
}
|
|
115
118
|
}
|
|
119
|
+
preserveStringify(rawMatter, updates, content) {
|
|
120
|
+
try {
|
|
121
|
+
if (!rawMatter || rawMatter.trim() === '') {
|
|
122
|
+
// No existing frontmatter to preserve - fall back to regular stringify
|
|
123
|
+
if (!updates || Object.keys(updates).length === 0) {
|
|
124
|
+
return content;
|
|
125
|
+
}
|
|
126
|
+
return matter.stringify(content, updates);
|
|
127
|
+
}
|
|
128
|
+
const doc = parseDocument(rawMatter.trimStart());
|
|
129
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
130
|
+
if (value === undefined) {
|
|
131
|
+
doc.delete(key);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
doc.set(key, value);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const yamlContent = doc.toString();
|
|
138
|
+
return `---\n${yamlContent}---\n${content}`;
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
throw new Error(`Failed to stringify frontmatter: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
116
144
|
extractFrontmatter(content) {
|
|
117
145
|
const parsed = this.parse(content);
|
|
118
146
|
return parsed.frontmatter;
|
|
@@ -124,6 +152,6 @@ export class FrontmatterHandler {
|
|
|
124
152
|
if (!validation.isValid) {
|
|
125
153
|
throw new Error(`Invalid frontmatter: ${validation.errors.join(', ')}`);
|
|
126
154
|
}
|
|
127
|
-
return this.
|
|
155
|
+
return this.preserveStringify(parsed.matter || '', updates, parsed.content);
|
|
128
156
|
}
|
|
129
157
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pathfilter.d.ts","sourceRoot":"","sources":["../../src/pathfilter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,qBAAa,UAAU;IACrB,OAAO,CAAC,eAAe,CAAW;IAClC,OAAO,CAAC,iBAAiB,CAAW;gBAExB,MAAM,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC;IAuB9C,OAAO,CAAC,eAAe;IAkBvB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;
|
|
1
|
+
{"version":3,"file":"pathfilter.d.ts","sourceRoot":"","sources":["../../src/pathfilter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,qBAAa,UAAU;IACrB,OAAO,CAAC,eAAe,CAAW;IAClC,OAAO,CAAC,iBAAiB,CAAW;gBAExB,MAAM,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC;IAuB9C,OAAO,CAAC,eAAe;IAkBvB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAyBhC,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAY1C,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,MAAM;IA0Bd,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE;CAGvC"}
|
package/dist/src/pathfilter.js
CHANGED
|
@@ -37,6 +37,9 @@ export class PathFilter {
|
|
|
37
37
|
return regex.test(path);
|
|
38
38
|
}
|
|
39
39
|
isAllowed(path) {
|
|
40
|
+
if (typeof path !== "string") {
|
|
41
|
+
throw new Error("path is required and must be a string");
|
|
42
|
+
}
|
|
40
43
|
// Normalize path separators
|
|
41
44
|
const normalizedPath = path.replace(/\\/g, '/');
|
|
42
45
|
if (this.isIgnoredPath(normalizedPath)) {
|
|
@@ -52,6 +55,9 @@ export class PathFilter {
|
|
|
52
55
|
return true;
|
|
53
56
|
}
|
|
54
57
|
isAllowedForListing(path) {
|
|
58
|
+
if (typeof path !== "string") {
|
|
59
|
+
throw new Error("path is required and must be a string");
|
|
60
|
+
}
|
|
55
61
|
// Normalize path separators
|
|
56
62
|
const normalizedPath = path.replace(/\\/g, '/');
|
|
57
63
|
// Listing includes non-note files, but still blocks restricted system paths
|
package/dist/src/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export interface ParsedNote {
|
|
|
2
2
|
frontmatter: Record<string, any>;
|
|
3
3
|
content: string;
|
|
4
4
|
originalContent: string;
|
|
5
|
+
matter?: string;
|
|
5
6
|
}
|
|
6
7
|
export interface NoteWriteParams {
|
|
7
8
|
path: string;
|
|
@@ -24,6 +25,7 @@ export interface PatchNoteResult {
|
|
|
24
25
|
export interface DeleteNoteParams {
|
|
25
26
|
path: string;
|
|
26
27
|
confirmPath: string;
|
|
28
|
+
trashMode?: 'none' | 'local' | 'system';
|
|
27
29
|
}
|
|
28
30
|
export interface DeleteResult {
|
|
29
31
|
success: boolean;
|
package/dist/src/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitbonsai/mcpvault",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.3",
|
|
4
4
|
"description": "Universal AI bridge for Obsidian vaults - connect any MCP-compatible assistant",
|
|
5
5
|
"homepage": "https://mcpvault.org",
|
|
6
6
|
"author": "bitbonsai",
|
|
@@ -37,12 +37,14 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@modelcontextprotocol/sdk": "^1.20.0",
|
|
40
|
-
"gray-matter": "^4.0.3"
|
|
40
|
+
"gray-matter": "^4.0.3",
|
|
41
|
+
"trash": "^10.1.1",
|
|
42
|
+
"yaml": "^2.8.3"
|
|
41
43
|
},
|
|
42
44
|
"devDependencies": {
|
|
43
45
|
"@types/node": "^25.3.3",
|
|
44
46
|
"tsx": "^4.20.6",
|
|
45
|
-
"typescript": "^
|
|
47
|
+
"typescript": "^6.0.2",
|
|
46
48
|
"vitest": "^4.0.15"
|
|
47
49
|
},
|
|
48
50
|
"engines": {
|