neuro-vault-mcp 1.7.0 → 1.7.2

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.d.ts CHANGED
@@ -131,6 +131,7 @@ interface ReadNoteInput {
131
131
  }
132
132
  interface ReadNoteResult {
133
133
  path: string;
134
+ frontmatter: Record<string, unknown> | null;
134
135
  content: string;
135
136
  }
136
137
  interface CreateNoteInput {
@@ -151,6 +152,7 @@ interface EditNoteInput {
151
152
  }
152
153
  interface DailyNoteResult {
153
154
  path: string;
155
+ frontmatter: Record<string, unknown> | null;
154
156
  content: string;
155
157
  }
156
158
  interface AppendDailyInput {
package/dist/cli.js CHANGED
@@ -14874,9 +14874,47 @@ async function createSemanticModule(config2, deps = {}) {
14874
14874
  // src/modules/operations/obsidian-cli-provider.ts
14875
14875
  import { execFile } from "child_process";
14876
14876
  import { promisify } from "util";
14877
+
14878
+ // src/modules/operations/frontmatter.ts
14879
+ import { parse as parseYaml } from "yaml";
14880
+ var FRONTMATTER_OPEN = /^---[ \t]*\r?\n/;
14881
+ var FRONTMATTER_CLOSE = /(^|\r?\n)---[ \t]*(\r?\n|$)/;
14882
+ function splitFrontmatter(raw) {
14883
+ const openMatch = raw.match(FRONTMATTER_OPEN);
14884
+ if (!openMatch) {
14885
+ return { frontmatter: null, content: raw };
14886
+ }
14887
+ const afterOpen = raw.slice(openMatch[0].length);
14888
+ const closeMatch = afterOpen.match(FRONTMATTER_CLOSE);
14889
+ if (!closeMatch || closeMatch.index === void 0) {
14890
+ return { frontmatter: null, content: raw };
14891
+ }
14892
+ const yamlBody = afterOpen.slice(0, closeMatch.index);
14893
+ const content = afterOpen.slice(closeMatch.index + closeMatch[0].length);
14894
+ let parsed;
14895
+ try {
14896
+ parsed = parseYaml(yamlBody);
14897
+ } catch (err) {
14898
+ console.warn(
14899
+ `[neuro-vault] frontmatter YAML parse failed: ${err.message}; returning raw content`
14900
+ );
14901
+ return { frontmatter: null, content: raw };
14902
+ }
14903
+ if (parsed === null || parsed === void 0) {
14904
+ return { frontmatter: {}, content };
14905
+ }
14906
+ if (typeof parsed !== "object" || Array.isArray(parsed)) {
14907
+ console.warn(
14908
+ `[neuro-vault] frontmatter parsed to non-object (${typeof parsed}); returning raw content`
14909
+ );
14910
+ return { frontmatter: null, content: raw };
14911
+ }
14912
+ return { frontmatter: parsed, content };
14913
+ }
14914
+
14915
+ // src/modules/operations/obsidian-cli-provider.ts
14877
14916
  var DEFAULT_BINARY = "obsidian";
14878
14917
  var DEFAULT_TIMEOUT_MS = 1e4;
14879
- var SEPARATOR = "\n---\n";
14880
14918
  var execFileAsync = promisify(execFile);
14881
14919
  var defaultExec = async (binary, args, options) => {
14882
14920
  const result = await execFileAsync(binary, args, {
@@ -14903,8 +14941,10 @@ var ObsidianCLIProvider = class {
14903
14941
  this.exec = opts.exec ?? defaultExec;
14904
14942
  }
14905
14943
  async readNote(input) {
14944
+ const path5 = await this.resolvePath(input.identifier);
14906
14945
  const { stdout } = await this.runCommand("read", [identifierToArg(input.identifier)]);
14907
- return this.parseReadOutput(stdout);
14946
+ const { frontmatter, content } = splitFrontmatter(stdout);
14947
+ return { path: path5, frontmatter, content };
14908
14948
  }
14909
14949
  async createNote(input) {
14910
14950
  if (input.name === void 0 && input.path === void 0) {
@@ -14926,8 +14966,11 @@ var ObsidianCLIProvider = class {
14926
14966
  ]);
14927
14967
  }
14928
14968
  async readDaily() {
14969
+ const { stdout: pathStdout } = await this.runCommand("daily:path", []);
14970
+ const path5 = pathStdout.trim();
14929
14971
  const { stdout } = await this.runCommand("daily:read", []);
14930
- return this.parseReadOutput(stdout);
14972
+ const { frontmatter, content } = splitFrontmatter(stdout);
14973
+ return { path: path5, frontmatter, content };
14931
14974
  }
14932
14975
  async appendDaily(input) {
14933
14976
  await this.runCommand("daily:append", [`content=${input.content}`]);
@@ -15108,15 +15151,21 @@ var ObsidianCLIProvider = class {
15108
15151
  if (this.vaultName) args.push(`vault=${this.vaultName}`);
15109
15152
  return args;
15110
15153
  }
15111
- parseReadOutput(stdout) {
15112
- const sepIndex = stdout.indexOf(SEPARATOR);
15113
- if (sepIndex === -1) {
15114
- return { path: "", content: stdout };
15154
+ async resolvePath(identifier) {
15155
+ if (identifier.kind === "path") return identifier.value;
15156
+ const { stdout } = await this.runCommand("file", [identifierToArg(identifier)]);
15157
+ for (const line of stdout.split(/\r?\n/)) {
15158
+ const idx = line.indexOf(" ");
15159
+ if (idx === -1) continue;
15160
+ if (line.slice(0, idx).trim() === "path") {
15161
+ return line.slice(idx + 1).trim();
15162
+ }
15115
15163
  }
15116
- return {
15117
- path: stdout.slice(0, sepIndex),
15118
- content: stdout.slice(sepIndex + SEPARATOR.length)
15119
- };
15164
+ throw new ToolHandlerError(
15165
+ "CLI_ERROR",
15166
+ `Could not resolve path for name '${identifier.value}': 'path' not found in obsidian file output`,
15167
+ { details: { name: identifier.value, stdout: stdout.slice(0, 500) } }
15168
+ );
15120
15169
  }
15121
15170
  };
15122
15171
 
@@ -15371,7 +15420,7 @@ function buildOperationsTools(handlers) {
15371
15420
  name: "read_note",
15372
15421
  spec: {
15373
15422
  title: "Read Note",
15374
- description: "Read a note's contents. Provide either `name` (wikilink-style, resolves like Obsidian) or `path` (vault-relative, exact). Returns `{ path, content }`.",
15423
+ description: "Read a note's contents. Provide either `name` (wikilink-style, resolves like Obsidian) or `path` (vault-relative, exact). Returns `{ path, frontmatter, content }` where `frontmatter` is the parsed YAML object (or `null` if absent/malformed) and `content` is the body without the YAML block.",
15375
15424
  inputSchema: readNoteSchema
15376
15425
  },
15377
15426
  handler: async (args) => invokeTool(() => handlers.readNote(readNoteSchema.parse(args)))
@@ -15398,7 +15447,7 @@ function buildOperationsTools(handlers) {
15398
15447
  name: "read_daily",
15399
15448
  spec: {
15400
15449
  title: "Read Daily",
15401
- description: "Read today's daily note. Returns `{ path, content }`. Useful for 'what's on my agenda?' questions.",
15450
+ description: "Read today's daily note. Returns `{ path, frontmatter, content }` where `frontmatter` is the parsed YAML object (or `null` if absent/malformed) and `content` is the body without the YAML block. Useful for 'what's on my agenda?' questions.",
15402
15451
  inputSchema: readDailySchema
15403
15452
  },
15404
15453
  handler: async () => invokeTool(() => handlers.readDaily({}))