diff --git a/src/adapters/interfaces.ts b/src/adapters/interfaces.ts index 3e5163a..cefd99c 100644 --- a/src/adapters/interfaces.ts +++ b/src/adapters/interfaces.ts @@ -25,6 +25,13 @@ export interface IVaultAdapter { // File creation create(path: string, data: string): Promise; + + // File modification + modify(file: TFile, data: string): Promise; + + // File deletion + delete(file: TAbstractFile): Promise; + trash(file: TAbstractFile, system: boolean): Promise; } /** diff --git a/src/adapters/vault-adapter.ts b/src/adapters/vault-adapter.ts index 18ee541..4bd61d6 100644 --- a/src/adapters/vault-adapter.ts +++ b/src/adapters/vault-adapter.ts @@ -38,4 +38,16 @@ export class VaultAdapter implements IVaultAdapter { async create(path: string, data: string): Promise { return this.vault.create(path, data); } + + async modify(file: TFile, data: string): Promise { + await this.vault.modify(file, data); + } + + async delete(file: TAbstractFile): Promise { + await this.vault.delete(file); + } + + async trash(file: TAbstractFile, system: boolean): Promise { + await this.vault.trash(file, system); + } } \ No newline at end of file diff --git a/src/tools/index.ts b/src/tools/index.ts index cc4d8bb..59a2a28 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -2,6 +2,7 @@ import { App } from 'obsidian'; import { Tool, CallToolResult } from '../types/mcp-types'; import { NoteTools } from './note-tools'; import { VaultTools } from './vault-tools'; +import { createNoteTools } from './note-tools-factory'; import { createVaultTools } from './vault-tools-factory'; import { NotificationManager } from '../ui/notifications'; @@ -11,7 +12,7 @@ export class ToolRegistry { private notificationManager: NotificationManager | null = null; constructor(app: App) { - this.noteTools = new NoteTools(app); + this.noteTools = createNoteTools(app); this.vaultTools = createVaultTools(app); } diff --git a/src/tools/note-tools-factory.ts b/src/tools/note-tools-factory.ts new file mode 100644 index 0000000..879968e --- /dev/null +++ b/src/tools/note-tools-factory.ts @@ -0,0 +1,15 @@ +import { App } from 'obsidian'; +import { NoteTools } from './note-tools'; +import { VaultAdapter } from '../adapters/vault-adapter'; +import { FileManagerAdapter } from '../adapters/file-manager-adapter'; + +/** + * Factory function to create NoteTools with concrete adapters + */ +export function createNoteTools(app: App): NoteTools { + return new NoteTools( + new VaultAdapter(app.vault), + new FileManagerAdapter(app.fileManager), + app + ); +} \ No newline at end of file diff --git a/src/tools/note-tools.ts b/src/tools/note-tools.ts index 81ae01d..8f37039 100644 --- a/src/tools/note-tools.ts +++ b/src/tools/note-tools.ts @@ -1,7 +1,7 @@ import { App, TFile } from 'obsidian'; -import { - CallToolResult, - ParsedNote, +import { + CallToolResult, + ParsedNote, ExcalidrawMetadata, UpdateFrontmatterResult, UpdateSectionsResult, @@ -16,9 +16,14 @@ import { ErrorMessages } from '../utils/error-messages'; import { FrontmatterUtils } from '../utils/frontmatter-utils'; import { WaypointUtils } from '../utils/waypoint-utils'; import { VersionUtils } from '../utils/version-utils'; +import { IVaultAdapter, IFileManagerAdapter } from '../adapters/interfaces'; export class NoteTools { - constructor(private app: App) {} + constructor( + private vault: IVaultAdapter, + private fileManager: IFileManagerAdapter, + private app: App // Keep temporarily for methods not yet migrated + ) {} async readNote( path: string, @@ -67,7 +72,7 @@ export class NoteTools { } try { - const content = await this.app.vault.read(file); + const content = await this.vault.read(file); // If no special options, return simple content if (!parseFrontmatter) { @@ -145,7 +150,7 @@ export class NoteTools { // Delete existing file before creating const existingFile = PathUtils.resolveFile(this.app, normalizedPath); if (existingFile) { - await this.app.vault.delete(existingFile); + await this.vault.delete(existingFile); } } else if (onConflict === 'rename') { // Generate a unique name @@ -198,7 +203,7 @@ export class NoteTools { // Proceed with file creation try { - const file = await this.app.vault.create(finalPath, content); + const file = await this.vault.create(finalPath, content); const result: CreateNoteResult = { success: true, @@ -252,7 +257,7 @@ export class NoteTools { // Create the current folder if it doesn't exist if (!PathUtils.pathExists(this.app, path)) { - await this.app.vault.createFolder(path); + await this.vault.createFolder(path); } } @@ -292,7 +297,7 @@ export class NoteTools { try { // Check for waypoint edit protection - const currentContent = await this.app.vault.read(file); + const currentContent = await this.vault.read(file); const waypointCheck = WaypointUtils.wouldAffectWaypoint(currentContent, content); if (waypointCheck.affected) { @@ -313,7 +318,7 @@ export class NoteTools { }; } - await this.app.vault.modify(file, content); + await this.vault.modify(file, content); return { content: [{ type: "text", text: `Note updated successfully: ${file.path}` }] }; @@ -424,7 +429,7 @@ export class NoteTools { // Use Obsidian's FileManager to rename (automatically updates links) // Note: Obsidian's renameFile automatically updates all wikilinks - await this.app.fileManager.renameFile(file, normalizedNewPath); + await this.fileManager.renameFile(file, normalizedNewPath); // Get the renamed file to get version info const renamedFile = PathUtils.resolveFile(this.app, normalizedNewPath); @@ -524,11 +529,11 @@ export class NoteTools { // Perform actual deletion if (soft) { // Move to trash using Obsidian's trash method - await this.app.vault.trash(file, true); + await this.vault.trash(file, true); destination = `.trash/${file.name}`; } else { // Permanent deletion - await this.app.vault.delete(file); + await this.vault.delete(file); } const result: DeleteNoteResult = { @@ -595,7 +600,7 @@ export class NoteTools { } try { - const content = await this.app.vault.read(file); + const content = await this.vault.read(file); // Parse Excalidraw metadata (gracefully handles malformed files) const metadata = FrontmatterUtils.parseExcalidrawMetadata(content); @@ -725,7 +730,7 @@ export class NoteTools { } // Read current content - const content = await this.app.vault.read(file); + const content = await this.vault.read(file); const extracted = FrontmatterUtils.extractFrontmatter(content); // Get current frontmatter or create new @@ -767,7 +772,7 @@ export class NoteTools { } // Write back - await this.app.vault.modify(file, newContent); + await this.vault.modify(file, newContent); // Generate response with version info const result: UpdateFrontmatterResult = { @@ -851,7 +856,7 @@ export class NoteTools { } // Read current content - const content = await this.app.vault.read(file); + const content = await this.vault.read(file); const lines = content.split('\n'); // Sort edits by startLine in descending order to apply from bottom to top @@ -891,7 +896,7 @@ export class NoteTools { const newContent = lines.join('\n'); // Write back - await this.app.vault.modify(file, newContent); + await this.vault.modify(file, newContent); // Generate response with version info const result: UpdateSectionsResult = {