aaronsb_obsidian-mcp-plugin/src/utils/content-buffer.ts
Aaron Bockelie 16476026a6 feat: Complete semantic MCP integration with direct Obsidian API
🎉 MAJOR RELEASE: Full semantic MCP server integration with direct plugin API access

 Semantic Tools Integrated (5 tools):
- **vault**: File operations (list, read, create, update, delete, search, fragments)
- **edit**: Smart editing (window, append, patch, at_line, from_buffer)
- **view**: Content viewing (file, window, active, open_in_obsidian)
- **workflow**: AI workflow guidance and suggestions
- **system**: System operations (info, commands, fetch_web)

🔧 Architecture Achievements:
- Replaced HTTP-based ObsidianAPI with direct app.vault/app.workspace calls
- Preserved exact ObsidianAPI interface - semantic router unchanged
- Integrated fragment retrieval system for large files
- Added content buffer manager for edit recovery
- Ported workflow configuration and state management

🚀 Performance & Capabilities:
- Direct vault access - no HTTP overhead
- Rich Obsidian API integration (search, commands, workspace)
- Advanced search with fallback implementation
- Image processing with Sharp integration
- Fetch tool using native fetch API

📦 MCP Resources:
- Added vault-info resource (obsidian://vault-info)
- Real-time vault metadata and file counts
- Active file tracking and plugin status

🛠️ Technical Implementation:
- Removed axios dependencies - browser-compatible
- Fixed all TypeScript type issues
- Maintained proven MCP server patterns from obsidian-semantic-mcp
- Updated to v0.3.0 with automatic version sync

This completes the core architectural vision: semantic MCP operations with
direct Obsidian plugin API integration for maximum performance and capabilities.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-27 12:33:59 -05:00

89 lines
No EOL
2 KiB
TypeScript

/**
* Content buffer manager for storing generated content between edit attempts
*/
export interface BufferedContent {
content: string;
timestamp: number;
filePath?: string;
searchText?: string;
}
export class ContentBufferManager {
private static instance: ContentBufferManager;
private buffer: Map<string, BufferedContent> = new Map();
private defaultKey = '_last_generated';
private maxAge = 30 * 60 * 1000; // 30 minutes
private constructor() {}
static getInstance(): ContentBufferManager {
if (!ContentBufferManager.instance) {
ContentBufferManager.instance = new ContentBufferManager();
}
return ContentBufferManager.instance;
}
/**
* Store content in buffer
*/
store(content: string, key?: string, metadata?: { filePath?: string; searchText?: string }): void {
const bufferKey = key || this.defaultKey;
this.buffer.set(bufferKey, {
content,
timestamp: Date.now(),
...metadata
});
// Clean old entries
this.cleanOldEntries();
}
/**
* Retrieve content from buffer
*/
retrieve(key?: string): BufferedContent | null {
const bufferKey = key || this.defaultKey;
const entry = this.buffer.get(bufferKey);
if (!entry) return null;
// Check if entry is too old
if (Date.now() - entry.timestamp > this.maxAge) {
this.buffer.delete(bufferKey);
return null;
}
return entry;
}
/**
* Clear specific buffer or all buffers
*/
clear(key?: string): void {
if (key) {
this.buffer.delete(key);
} else {
this.buffer.clear();
}
}
/**
* Get all buffer keys
*/
getKeys(): string[] {
return Array.from(this.buffer.keys());
}
/**
* Clean entries older than maxAge
*/
private cleanOldEntries(): void {
const now = Date.now();
for (const [key, entry] of this.buffer.entries()) {
if (now - entry.timestamp > this.maxAge) {
this.buffer.delete(key);
}
}
}
}