@bitbonsai/mcpvault 0.18.1 → 0.18.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 CHANGED
@@ -998,7 +998,7 @@ Only grant write access to clients and conversations you trust. Use `--read-only
998
998
  - `server.ts` - MCP server entry point
999
999
  - `src/cli.ts` - CLI option parsing for vault path, read-only mode, and default exclusions
1000
1000
  - `src/createServer.ts` - MCP tool registration, request routing, and discovery defaults
1001
- - `src/frontmatter.ts` - YAML frontmatter handling with gray-matter
1001
+ - `src/frontmatter.ts` - YAML frontmatter handling with gray-matter, preserving formatting and CRLF line endings; executable JavaScript frontmatter stays inert as note content
1002
1002
  - `src/filesystem.ts` - File operations with path validation
1003
1003
  - `src/pathfilter.ts` - Directory and file filtering
1004
1004
  - `src/search.ts` - Note search functionality with content and frontmatter support
@@ -896,7 +896,7 @@ export class FileSystemService {
896
896
  // Quick check for frontmatter without reading full content
897
897
  const file = await readFile(fullPath, 'utf-8');
898
898
  const firstChunk = file.slice(0, 100);
899
- const hasFrontmatter = firstChunk.startsWith('---\n');
899
+ const hasFrontmatter = /^---\r?\n/.test(firstChunk);
900
900
  return {
901
901
  path,
902
902
  size,
@@ -1 +1 @@
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;AAkB1E;;;;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,CAkBjC;IAED,SAAS,CAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAWvE;IAED,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,2BAA2B,CAmB1E;IAED,OAAO,CAAC,yBAAyB;IAmDjC,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAuB1F;IAED,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAGvD;IAED,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAUvE;CACF"}
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;AA0C1E;;;;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,CAkBjC;IAED,SAAS,CAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAcvE;IAED,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,2BAA2B,CAmB1E;IAED,OAAO,CAAC,yBAAyB;IAmDjC,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAyB1F;IAED,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAGvD;IAED,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAUvE;CACF"}
@@ -8,11 +8,32 @@ const yamlEngine = {
8
8
  // YAML 1.2 schema (default). Dates stay as strings, but this avoids the
9
9
  // yaml-1.1 bug where single-letter keys like 'y'/'n' become booleans.
10
10
  // Merge keys (<<) are not resolved, which is fine for Obsidian frontmatter.
11
- parse: (str) => parse(str),
11
+ parse: (str) => parse(toLf(str)),
12
12
  stringify: (data) => stringify(data),
13
13
  };
14
14
  function withYamlEngine(options = {}) {
15
- return { ...options, engines: { yaml: yamlEngine } };
15
+ return {
16
+ ...options,
17
+ engines: {
18
+ yaml: yamlEngine,
19
+ // gray-matter merges default engines; override JavaScript to prevent eval, including its js alias.
20
+ javascript: {
21
+ parse: () => { throw new Error('JavaScript frontmatter is not supported'); },
22
+ },
23
+ },
24
+ };
25
+ }
26
+ /** Use CRLF when present, otherwise LF. */
27
+ function detectEol(text) {
28
+ return text.includes('\r\n') ? '\r\n' : '\n';
29
+ }
30
+ // gray-matter leaves a trailing CR before the closing delimiter; normalize before YAML parsing.
31
+ function toLf(text) {
32
+ return text.replace(/\r\n?/g, '\n');
33
+ }
34
+ /** Re-apply CRLF to LF-only text. */
35
+ function applyEol(text, eol) {
36
+ return eol === '\r\n' ? text.replace(/\n/g, '\r\n') : text;
16
37
  }
17
38
  /**
18
39
  * Parse a frontmatter value that may be a JSON string (LLM clients sometimes
@@ -67,7 +88,10 @@ export class FrontmatterHandler {
67
88
  if (!frontmatterData || Object.keys(frontmatterData).length === 0) {
68
89
  return content;
69
90
  }
70
- return matter.stringify(content, frontmatterData, withYamlEngine());
91
+ const eol = detectEol(content);
92
+ // Serialize only the header so body bytes stay untouched; drop gray-matter's empty-body newline.
93
+ const header = matter.stringify('', frontmatterData, withYamlEngine()).slice(0, -1);
94
+ return applyEol(header, eol) + content + (content.endsWith('\n') ? '' : eol);
71
95
  }
72
96
  catch (error) {
73
97
  throw new Error(`Failed to stringify frontmatter: ${error instanceof Error ? error.message : 'Unknown error'}`);
@@ -137,9 +161,11 @@ export class FrontmatterHandler {
137
161
  if (!updates || Object.keys(updates).length === 0) {
138
162
  return content;
139
163
  }
140
- return matter.stringify(content, updates, withYamlEngine());
164
+ return this.stringify(updates, content);
141
165
  }
142
- const doc = parseDocument(rawMatter.trimStart());
166
+ // Normalize only YAML; preserve the body's original bytes.
167
+ const eol = rawMatter.includes('\r\n') ? '\r\n' : detectEol(content);
168
+ const doc = parseDocument(toLf(rawMatter).trimStart());
143
169
  for (const [key, value] of Object.entries(updates)) {
144
170
  if (value === undefined) {
145
171
  doc.delete(key);
@@ -148,8 +174,8 @@ export class FrontmatterHandler {
148
174
  doc.set(key, value);
149
175
  }
150
176
  }
151
- const yamlContent = doc.toString();
152
- return `---\n${yamlContent}---\n${content}`;
177
+ const yamlContent = applyEol(doc.toString(), eol);
178
+ return `---${eol}${yamlContent}---${eol}${content}`;
153
179
  }
154
180
  catch (error) {
155
181
  throw new Error(`Failed to stringify frontmatter: ${error instanceof Error ? error.message : 'Unknown error'}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitbonsai/mcpvault",
3
- "version": "0.18.1",
3
+ "version": "0.18.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",