patch-note.ts•2.56 kB
import { z } from "zod";
import { ObsidianAPI } from "../api/obsidian-api.js";
import { formatErrorResponse, formatSuccessResponse } from "../utils/response-utils.js";
import { ToolDefinition, ToolHandler, ToolResponse, PatchNoteOptions } from "../types.js";
// Schema for patch-note tool parameters
export const PatchNoteSchema = {
path: z.string().min(1, "Note path is required"),
operation: z.enum(["append", "prepend", "replace"], {
description: "Operation to perform (append, prepend, or replace)",
}),
targetType: z.enum(["heading", "block", "frontmatter"], {
description: "Type of target to patch (heading, block, or frontmatter)",
}),
target: z
.string()
.min(1, "Target is required")
.describe(`Target identifier
- For heading: Use a heading path string. For nested headings, use '::' as a delimiter (e.g., '## Heading 1 ### Subheading 1' must be 'Heading 1::Subheading 1'). The path should match the exact heading text. For headings with special characters, use URL encoding.
- For block: Use the block ID (e.g., '2d9b4a').
- For frontmatter: Use the frontmatter field name (e.g., 'tags', 'date', 'title').`),
content: z
.string()
.min(1, "Content is required")
.describe("Content to be inserted or used for replacement"),
targetDelimiter: z.string().optional(),
trimTargetWhitespace: z.boolean().optional(),
contentType: z.string().optional(),
};
/**
* Tool definition for patching a note
*/
export const patchNoteDefinition: ToolDefinition = {
name: "patchNote",
description: "Inserts content into an existing note relative to a heading, block reference, or frontmatter field.",
schema: PatchNoteSchema
};
/**
* Creates a tool handler for patching a note
* @param api ObsidianAPI instance
* @returns Tool handler function
*/
export function createPatchNoteTool(api: ObsidianAPI): ToolHandler {
return async (params: {
path: string;
operation: "append" | "prepend" | "replace";
targetType: "heading" | "block" | "frontmatter";
target: string;
content: string;
targetDelimiter?: string;
trimTargetWhitespace?: boolean;
contentType?: string;
}): Promise<ToolResponse> => {
try {
const { path, content, ...patchOptions } = params;
await api.patchNote(path, content, patchOptions as PatchNoteOptions);
return formatSuccessResponse({ success: true, message: "Note patched successfully" });
} catch (error) {
return formatErrorResponse(`Error patching note: ${(error as Error).message}`);
}
};
}