diff --git a/CHANGELOG.md b/CHANGELOG.md index 96b48d9..3477c33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,1299 +2,81 @@ All notable changes to the Obsidian MCP Server plugin will be documented in this file. -## [9.0.0] - 2025-10-17 - -### 🎨 Phase 10: UI Notifications - -This release adds visual feedback for MCP tool calls with configurable notifications in the Obsidian UI. Provides transparency into API activity, easier debugging, and optional notification history tracking. - -#### Added - -**Notification System** -- Real-time notifications for MCP tool calls displayed in Obsidian UI -- Shows notification when tool is called (request only, no completion notifications) -- Configurable notification duration (default: 3 seconds) -- Rate limiting (max 10 notifications/second) to prevent UI spam -- Simple on/off toggle - no verbosity levels needed -- Tool-specific icons for visual clarity: - - πŸ“– Read operations (`read_note`, `read_excalidraw`) - - ✏️ Write operations (`create_note`, `update_note`, `update_frontmatter`, `update_sections`) - - πŸ—‘οΈ Delete operations (`delete_note`) - - πŸ“ Rename operations (`rename_file`) - - πŸ” Search operations (`search`, `search_waypoints`) - - πŸ“‹ List operations (`list`) - - πŸ“Š Stat operations (`stat`, `exists`) - - ℹ️ Info operations (`get_vault_info`) - - πŸ—ΊοΈ Waypoint operations (`get_folder_waypoint`) - - πŸ“ Folder operations (`is_folder_note`) - - πŸ”— Link operations (`validate_wikilinks`, `resolve_wikilink`, `backlinks`) - -**Notification Settings** -- `Enable notifications` - Toggle notifications on/off -- `Show parameters` - Include tool parameters in notifications (truncated for readability) -- `Notification duration` - How long notifications stay visible (milliseconds) -- `Log to console` - Also log tool calls to browser console for debugging -- All settings available in plugin settings UI under "UI Notifications" section - -**Notification History** -- Stores last 100 tool calls in memory -- View history via command palette: "View MCP Notification History" -- View history via settings: "View History" button -- History modal features: - - Filter by tool name - - Filter by type (all/success/error) - - Shows timestamp, duration, parameters, and error messages - - Export history to clipboard as JSON - - Clear history button -- Each history entry includes: - - `timestamp` - When the tool was called - - `toolName` - Name of the tool - - `args` - Tool parameters - - `success` - Whether the call succeeded - - `duration` - Execution time in milliseconds - - `error` - Error message (if failed) - -**Notification Example** -- Tool call: `πŸ”§ MCP: list({ path: "projects", recursive: true })` -- Note: Only request notifications are shown, not completion or error notifications - -**Implementation Details** -- Non-blocking notification display (async queue) -- Notification queue with rate limiting to prevent UI freezing -- Parameter truncation for long values (max 50 chars) -- Privacy-aware: sensitive data not shown in notifications -- Zero performance impact when disabled -- Integrates seamlessly with existing tool call flow - -#### Files Added -- `src/ui/notifications.ts` - Notification manager with rate limiting -- `src/ui/notification-history.ts` - History modal for viewing past tool calls - -#### Files Modified -- `src/types/settings-types.ts` - Added notification settings types -- `src/settings.ts` - Added notification settings UI -- `src/tools/index.ts` - Integrated notifications into tool call interceptor -- `src/server/mcp-server.ts` - Added notification manager support -- `src/main.ts` - Initialize notification manager and add history command - -#### Benefits -- **Developer Experience**: Visual feedback for API activity, easier debugging -- **User Experience**: Awareness when tools are called, transparency into AI agent actions -- **Debugging**: See exact parameters, track execution times in history, identify bottlenecks -- **Optional**: Can be completely disabled for production use -- **Simple**: Single toggle to enable/disable, no complex verbosity settings - -## [8.0.0] - 2025-10-17 - -### πŸš€ Phase 9: Linking & Backlinks - -This release adds powerful tools for working with wikilinks, resolving links, and querying backlinks. Enables programmatic link validation, resolution, and knowledge graph exploration. - -#### Added - -**New Tool: `validate_wikilinks`** -- Validate all wikilinks in a note and report unresolved links -- Parses all `[[wikilinks]]` in the file using regex -- Resolves links using Obsidian's MetadataCache for accuracy -- Provides suggestions for broken links using fuzzy matching -- Returns structured JSON with: - - `path` - File path - - `totalLinks` - Total number of links found - - `resolvedLinks` - Array of resolved links with: - - `text` - Full link text including brackets - - `target` - Resolved target file path - - `alias` - Display alias (if present) - - `unresolvedLinks` - Array of unresolved links with: - - `text` - Full link text including brackets - - `line` - Line number where link appears - - `suggestions` - Array of suggested target paths -- Supports both `[[link]]` and `[[link|alias]]` formats -- Handles links with headings `[[note#heading]]` -- Use to identify and fix broken links in notes - -**New Tool: `resolve_wikilink`** -- Resolve a single wikilink from a source note to its target path -- Uses Obsidian's MetadataCache.getFirstLinkpathDest() for accurate resolution -- Follows Obsidian's link resolution rules: - - Shortest path matching - - Relative paths - - Aliases - - Headings and blocks -- Returns structured JSON with: - - `sourcePath` - Source note path - - `linkText` - Link text to resolve (without brackets) - - `resolved` - Boolean indicating if link was resolved - - `targetPath` - Resolved target file path (if found) - - `suggestions` - Array of suggested paths (if not found) -- Parameters: - - `sourcePath` - Path of note containing the link - - `linkText` - Link text without brackets (e.g., "target note", "folder/note", "note#heading") -- Supports complex link formats (headings, aliases, relative paths) -- Use to programmatically resolve links before following them - -**New Tool: `backlinks`** -- Get all backlinks to a note with optional unlinked mentions -- Uses Obsidian's MetadataCache.getBacklinksForFile() for linked backlinks -- Optional text-based search for unlinked mentions -- Returns structured JSON with: - - `path` - Target note path - - `backlinks` - Array of backlinks with: - - `sourcePath` - Source file path containing the link - - `type` - Either "linked" (wikilink) or "unlinked" (text mention) - - `occurrences` - Array of occurrences with: - - `line` - Line number (1-indexed) - - `snippet` - Context snippet around the link - - `totalBacklinks` - Total number of backlinks -- Parameters: - - `path` - Target note path - - `includeUnlinked` - Include unlinked mentions (default: false) - - `includeSnippets` - Include context snippets (default: true) -- Efficient use of Obsidian's built-in caching and indexing -- Use to explore note connections and build knowledge graphs -- Warning: `includeUnlinked` can be slow for large vaults - -**New Utility: `link-utils.ts`** -- `LinkUtils` class for wikilink operations -- `parseWikilinks()` - Parse all wikilinks from content with positions -- `resolveLink()` - Resolve a wikilink to its target file -- `findSuggestions()` - Find potential matches for unresolved links -- `getBacklinks()` - Get all backlinks to a file -- `validateWikilinks()` - Validate all wikilinks in a file -- Regex-based wikilink parsing: `/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g` -- Fuzzy matching algorithm for link suggestions -- Handles edge cases (circular links, missing files) - -#### Modified - -**Updated: `vault-tools.ts`** -- Added `validateWikilinks()` method -- Added `resolveWikilink()` method -- Added `getBacklinks()` method -- Imports LinkUtils for wikilink operations - -**Updated: `index.ts` (Tool Registry)** -- Added `validate_wikilinks` tool definition -- Added `resolve_wikilink` tool definition -- Added `backlinks` tool definition -- Added case handlers for three new tools - -**Updated: `mcp-types.ts`** -- Added Phase 9 types: - - `ResolvedLink` - Resolved wikilink information - - `UnresolvedLink` - Unresolved wikilink information - - `ValidateWikilinksResult` - Result from validate_wikilinks - - `ResolveWikilinkResult` - Result from resolve_wikilink - - `BacklinkOccurrence` - Backlink occurrence in a file - - `BacklinkInfo` - Backlink from a source file - - `BacklinksResult` - Result from backlinks operation - -#### Benefits - -- **Link Validation**: Identify and fix broken links in notes -- **Link Resolution**: Programmatically resolve links before following them -- **Knowledge Graphs**: Explore note connections and build knowledge graphs -- **Complex Links**: Support for headings, aliases, and relative paths -- **Accurate Resolution**: Uses Obsidian's native link resolution rules -- **Performance**: Efficient use of MetadataCache and built-in indexing -- **Suggestions**: Fuzzy matching helps find intended targets for broken links - -#### Technical Details - -- Wikilink parsing uses regex: `/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g` -- Link resolution uses `MetadataCache.getFirstLinkpathDest()` -- Backlink detection uses `MetadataCache.getBacklinksForFile()` -- Suggestion engine uses multi-factor scoring (basename, path, character matching) -- Unlinked mentions use word boundary regex for whole-word matching -- Context snippets extracted with configurable length (default: 100 chars) +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). --- -## [7.0.0] - 2025-10-17 +## [1.0.0] - 2025-10-26 -### πŸš€ Phase 8: Write Operations & Concurrency +### πŸŽ‰ Initial Public Release -This release implements safe write operations with concurrency control, partial updates, conflict resolution, and file rename/move with automatic link updates. +The Obsidian MCP Server plugin is now publicly available! This plugin exposes your Obsidian vault via the Model Context Protocol (MCP) over HTTP, enabling AI assistants and other MCP clients to interact with your vault programmatically. -#### Added +#### Core Features -**New Tool: `update_frontmatter`** -- Update frontmatter fields without modifying note content -- Supports patch operations (add/update fields) via `patch` parameter -- Supports field removal via `remove` parameter (array of field names) -- Returns structured JSON with: - - `success` - Boolean operation status - - `path` - File path - - `versionId` - New version ID for subsequent operations - - `modified` - Modification timestamp - - `updatedFields` - Array of fields that were added/updated - - `removedFields` - Array of fields that were removed -- Includes concurrency control via optional `ifMatch` parameter -- Preserves content and formatting -- Automatically creates frontmatter if none exists -- Use for metadata-only updates to avoid race conditions - -**New Tool: `update_sections`** -- Update specific sections of a note by line range -- Reduces race conditions by avoiding full file overwrites -- Supports multiple edits in a single operation -- Edits applied from bottom to top to preserve line numbers -- Returns structured JSON with: - - `success` - Boolean operation status - - `path` - File path - - `versionId` - New version ID - - `modified` - Modification timestamp - - `sectionsUpdated` - Count of sections updated -- Each edit specifies: - - `startLine` - Starting line number (1-indexed, inclusive) - - `endLine` - Ending line number (1-indexed, inclusive) - - `content` - New content to replace the section -- Includes concurrency control via optional `ifMatch` parameter -- Validates line ranges before applying edits -- Use for surgical edits to specific parts of large notes - -**New Tool: `rename_file`** -- Rename or move files with automatic wikilink updates -- Uses Obsidian's FileManager to maintain link integrity -- Supports both rename (same folder) and move (different folder) -- Returns structured JSON with: - - `success` - Boolean operation status - - `oldPath` - Original file path - - `newPath` - New file path - - `linksUpdated` - Always 0 (tracking not available in current API) - - `affectedFiles` - Always empty array (tracking not available in current API) - - `versionId` - New version ID -- Parameters: - - `path` - Current file path - - `newPath` - New file path (can be in different folder) - - `updateLinks` - Auto-update wikilinks (default: true) - - `ifMatch` - Optional version ID for concurrency control -- Automatically creates parent folders if needed -- Prevents conflicts with existing files -- Links are automatically updated by Obsidian's FileManager -- Use to reorganize vault structure while preserving links -- Note: Link tracking fields return placeholder values due to API limitations - -**New Utility: `version-utils.ts`** -- `VersionUtils` class for ETag-based concurrency control -- `generateVersionId()` - Create version ID from file mtime and size -- `validateVersion()` - Check if provided version matches current -- `versionMismatchError()` - Generate 412 Precondition Failed error -- Uses SHA-256 hash with URL-safe base64 encoding - -**Enhanced Tool: `create_note`** -- Added `onConflict` parameter with three strategies: - - `error` (default) - Fail if file exists - - `overwrite` - Delete existing file and create new - - `rename` - Auto-generate unique name by appending number -- Returns structured JSON with: - - `success` - Boolean operation status - - `path` - Created file path (may differ if renamed) - - `versionId` - Version ID for subsequent operations - - `created` - Creation timestamp - - `renamed` - Boolean indicating if file was renamed - - `originalPath` - Original path if renamed -- Existing `createParents` parameter still supported -- Better conflict handling and error messages - -**Enhanced Tool: `delete_note`** -- Added `soft` parameter (default: true): - - `true` - Move to `.trash` folder (recoverable) - - `false` - Permanent deletion (cannot be undone) -- Added `dryRun` parameter (default: false): - - `true` - Preview deletion without executing - - `false` - Perform actual deletion -- Added `ifMatch` parameter for concurrency control -- Returns structured JSON with: - - `deleted` - Boolean indicating if deletion occurred - - `path` - File path - - `destination` - Trash destination (for soft deletes) - - `dryRun` - Boolean indicating preview mode - - `soft` - Boolean indicating soft delete mode -- Use for safer file operations with preview and recovery - -**Type Definitions (`src/types/mcp-types.ts`)** -- `ConflictStrategy` - Type for conflict resolution strategies -- `SectionEdit` - Interface for section edit operations -- `UpdateFrontmatterResult` - Result from frontmatter updates -- `UpdateSectionsResult` - Result from section updates -- `CreateNoteResult` - Enhanced result from note creation -- `RenameFileResult` - Result from file rename/move -- `DeleteNoteResult` - Enhanced result from deletion - -**Frontmatter Serialization (`src/utils/frontmatter-utils.ts`)** -- `serializeFrontmatter()` - Convert frontmatter object to YAML string -- Handles arrays, objects, strings, numbers, booleans -- Automatic quoting for strings with special characters -- Proper YAML formatting with delimiters - -#### Improvements - -**Concurrency Control** -- ETag-based optimistic locking across all write operations -- `ifMatch` parameter prevents lost updates in concurrent scenarios -- Version mismatch returns 412 Precondition Failed with clear error -- All write operations return `versionId` for subsequent operations -- Get `versionId` from read operations to ensure consistency - -**Conflict Resolution** -- Three strategies for handling file conflicts in `create_note` -- Automatic unique name generation for rename strategy -- Clear error messages for each conflict scenario -- Prevents accidental overwrites - -**Link Integrity** -- Automatic wikilink updates when renaming/moving files -- Uses Obsidian's FileManager for reliable link maintenance -- Tracks affected files and link update count -- Supports moving files between folders - -**Safe Operations** -- Soft delete moves files to trash instead of permanent deletion -- Dry-run preview for deletions -- Parent folder auto-creation for rename operations -- Validation before destructive operations - -**Partial Updates** -- Update frontmatter without touching content -- Update specific sections without full file overwrites -- Reduces race conditions in concurrent editing -- Fine-grained control over modifications - -#### Breaking Changes - -None - All changes are additive or enhance existing functionality with backward compatibility. - -#### Implementation - -**Files Created:** -- `src/utils/version-utils.ts` - ETag/version control utilities - -**Files Modified:** -- `src/tools/note-tools.ts` - Added new methods and enhanced existing ones -- `src/utils/frontmatter-utils.ts` - Added serializeFrontmatter method -- `src/tools/index.ts` - Added new tool definitions and updated callTool -- `src/types/mcp-types.ts` - Added Phase 8 type definitions - -#### Benefits - -- **Concurrency safety** - Prevents lost updates in concurrent editing scenarios -- **Safer operations** - Preview and recovery options for destructive operations -- **Link integrity** - Maintained vault link integrity during reorganization -- **Fine-grained control** - Update specific parts without full file overwrites -- **Better UX** - Clear error messages and conflict resolution strategies -- **Production-ready** - Robust error handling and validation - -#### Notes - -- Manual testing recommended before production use -- All write operations now support concurrency control via `ifMatch` -- Soft delete is the default for `delete_note` (safer) -- Rename/move operations automatically update all wikilinks by default - ---- - -## [6.0.0] - 2025-10-17 - -### πŸš€ Phase 7: Waypoint Support - -This release adds specialized tools for working with Waypoint plugin markers and implements edit protection for auto-generated content. - -#### Added - -**New Tool: `get_folder_waypoint`** -- Extract Waypoint block from a folder note -- Returns structured JSON with: - - `path` - File path - - `hasWaypoint` - Boolean indicating waypoint presence - - `waypointRange` - Line range of waypoint block (start/end) - - `links` - Array of extracted wikilinks from waypoint content - - `rawContent` - Raw waypoint content between markers -- Automatically parses `[[wikilinks]]` from waypoint blocks -- Use to inspect folder note navigation structures - -**New Tool: `is_folder_note`** -- Check if a note is a folder note -- Returns structured JSON with: - - `path` - File path - - `isFolderNote` - Boolean result - - `reason` - Detection method: `basename_match`, `waypoint_marker`, `both`, or `none` - - `folderPath` - Parent folder path -- Detects folder notes by: - - Basename matching parent folder name - - Presence of Waypoint markers -- Use to identify navigation/index notes in vault - -**New Utilities (`src/utils/waypoint-utils.ts`)** -- `WaypointUtils` class for waypoint operations -- `extractWaypointBlock()` - Extract waypoint from content with line ranges -- `hasWaypointMarker()` - Quick check for waypoint presence -- `isFolderNote()` - Detect folder notes by multiple criteria -- `wouldAffectWaypoint()` - Check if edit would modify waypoint block -- Handles edge cases: unclosed waypoints, malformed markers, nested content - -**Type Definitions (`src/types/mcp-types.ts`)** -- `FolderWaypointResult` - Waypoint extraction result -- `FolderNoteResult` - Folder note detection result - -**Waypoint Edit Protection** -- `update_note` now validates edits against waypoint blocks -- Prevents accidental modification of auto-generated content -- Returns clear error message with: - - Waypoint line range - - Troubleshooting tips - - Suggestion to use `get_folder_waypoint()` for inspection -- Detects both content changes and waypoint removal - -#### Improvements - -- **Smart detection** - Multiple criteria for folder note identification -- **Link extraction** - Automatic wikilink parsing from waypoint content -- **Edit safety** - Prevents corruption of auto-generated navigation structures -- **Clear errors** - Actionable guidance when waypoint edits are blocked -- **Flexible checking** - Allows edits that don't affect waypoint content - -#### Implementation - -**Files Modified:** -- `src/utils/waypoint-utils.ts` (new) - Core waypoint utilities -- `src/tools/vault-tools.ts` - Added `getFolderWaypoint()` and `isFolderNote()` methods -- `src/tools/note-tools.ts` - Added waypoint edit protection to `updateNote()` -- `src/tools/index.ts` - Registered new tools in tool registry -- `src/types/mcp-types.ts` - Added Phase 7 type definitions - -#### Benefits - -- **Waypoint integration** - First-class support for Waypoint plugin workflows -- **Data integrity** - Prevents accidental corruption of auto-generated content -- **Better navigation** - Tools to discover and inspect folder structures -- **Developer-friendly** - Clear APIs for working with folder notes - -#### Notes - -- `update_sections` tool (with waypoint protection) will be implemented in Phase 8 -- Manual testing recommended for various waypoint formats and edge cases - ---- - -## [5.0.0] - 2025-10-16 - -### πŸš€ Phase 6: Powerful Search - -This release introduces a completely redesigned search system with regex support, advanced filtering, and specialized waypoint search capabilities. - -#### Added - -**New Tool: `search`** -- **Regex support** - Full JavaScript regex pattern matching with `isRegex` parameter -- **Case sensitivity control** - Toggle case-sensitive search with `caseSensitive` parameter -- **Advanced filtering**: - - `includes` - Glob patterns to include specific files (e.g., `['*.md', 'projects/**']`) - - `excludes` - Glob patterns to exclude files (e.g., `['.obsidian/**', '*.tmp']`) - - `folder` - Limit search to specific folder path -- **Snippet extraction** - Configurable context snippets with `snippetLength` parameter -- **Result limiting** - Control maximum results with `maxResults` parameter (default: 100) -- **Snippet control** - Toggle snippet extraction with `returnSnippets` parameter -- Returns enhanced `SearchResult` with: - - `query` - Search query string - - `isRegex` - Boolean indicating regex mode - - `matches` - Array of `SearchMatch` objects with line, column, snippet, and match ranges - - `totalMatches` - Total number of matches found - - `filesSearched` - Number of files searched - - `filesWithMatches` - Number of files containing matches - -**New Tool: `search_waypoints`** -- Specialized tool for finding Waypoint plugin markers -- Searches for `%% Begin Waypoint %%` ... `%% End Waypoint %%` blocks -- **Wikilink extraction** - Automatically extracts `[[wikilinks]]` from waypoint content -- **Folder scoping** - Optional `folder` parameter to limit search scope -- Returns structured `WaypointSearchResult` with: - - `waypoints` - Array of waypoint locations with content and links - - `totalWaypoints` - Total number of waypoints found - - `filesSearched` - Number of files searched - -**New Utilities (`src/utils/search-utils.ts`)** -- `SearchUtils` class for advanced search operations -- `search()` - Main search method with regex, filtering, and snippet extraction -- `searchInFile()` - Search within single file with match highlighting -- `searchInFilename()` - Search in file basenames -- `searchWaypoints()` - Specialized waypoint marker search -- Handles edge cases: zero-width regex matches, invalid patterns, large files - -**Type Definitions (`src/types/mcp-types.ts`)** -- Updated `SearchResult` - Added `isRegex` field -- `WaypointResult` - Individual waypoint location with content and links -- `WaypointSearchResult` - Waypoint search results with statistics - -**Implementation (`src/tools/vault-tools.ts`)** -- New `search()` method with full parameter support -- New `searchWaypoints()` method for waypoint discovery -- Updated `searchNotes()` to include `isRegex: false` in results - -**Tool Registry (`src/tools/index.ts`)** -- Registered `search` tool with comprehensive schema -- Registered `search_waypoints` tool -- Marked `search_notes` as DEPRECATED (kept for backward compatibility) -- Updated callTool to handle new search tools - -#### Improvements - -- **Regex power** - Full JavaScript regex syntax support with global flag for multiple matches per line -- **Smart snippet extraction** - Centers matches in snippets with configurable length -- **Consistent filtering** - Uses existing GlobUtils for glob pattern matching -- **Filename search** - Searches both content and filenames automatically -- **Error handling** - Clear error messages for invalid regex patterns -- **Performance** - Efficient search with early termination when maxResults reached - -#### Breaking Changes - -- **`search_notes` tool removed** - Replaced by enhanced `search` tool - - Old tool completely removed (no backward compatibility) - - Use `search` tool with `isRegex: false` for equivalent literal search - - Migration: Replace `search_notes` calls with `search` tool - -#### Benefits - -- **Powerful queries** - Use regex for complex search patterns (e.g., `^# Heading`, `TODO.*urgent`) -- **Precise control** - Fine-tune search with case sensitivity and glob filtering -- **Better results** - Context snippets with match highlighting for easier review -- **Waypoint discovery** - Find all folder notes and navigation structures -- **Cleaner API** - Single powerful search tool instead of multiple limited ones - ---- - -## [4.0.0] - 2025-10-16 - -### πŸš€ Phase 5: Advanced Read Operations - -This release adds frontmatter parsing capabilities to `read_note` and introduces specialized support for Excalidraw files. All features have been manually tested and refined based on user feedback. - -#### Added - -**Enhanced Tool: `read_note`** -- **Frontmatter parsing** - New `parseFrontmatter` option to separate frontmatter from content -- **Structured response** - Returns `ParsedNote` object with parsed YAML frontmatter -- **Flexible options**: - - `withFrontmatter` (default: true) - Include frontmatter in response - - `withContent` (default: true) - Include full content in response - - `parseFrontmatter` (default: false) - Parse and structure frontmatter -- **Backward compatible** - Default behavior unchanged (returns raw content) -- Returns structured JSON when `parseFrontmatter: true` with: - - `path` - File path - - `hasFrontmatter` - Boolean indicating presence - - `frontmatter` - Raw YAML string - - `parsedFrontmatter` - Parsed YAML object - - `content` - Full file content - - `contentWithoutFrontmatter` - Content excluding frontmatter - -**New Tool: `read_excalidraw`** -- Specialized tool for reading Excalidraw drawing files -- **Metadata extraction** - Element count, compressed data status -- **Preview text** - Extract text elements without parsing full drawing -- **Optional compressed data** - Include full drawing data with `includeCompressed: true` -- Returns structured `ExcalidrawMetadata` with: - - `path` - File path - - `isExcalidraw` - Validation boolean - - `elementCount` - Number of drawing elements - - `hasCompressedData` - Boolean for compressed files - - `metadata` - Drawing metadata (appState, version) - - `preview` - Text elements preview (optional) - - `compressedData` - Full drawing data (optional) - -**New Utilities (`src/utils/frontmatter-utils.ts`)** -- `FrontmatterUtils` class for YAML parsing -- `extractFrontmatter()` - Extract and parse YAML frontmatter using Obsidian's parseYaml -- `extractFrontmatterSummary()` - Extract common fields (title, tags, aliases) -- `hasFrontmatter()` - Quick check for frontmatter presence -- `parseExcalidrawMetadata()` - Parse Excalidraw file structure -- Handles edge cases: no frontmatter, malformed YAML, invalid Excalidraw files - -**Type Definitions (`src/types/mcp-types.ts`)** -- `ParsedNote` - Structured note with separated frontmatter -- `ExcalidrawMetadata` - Excalidraw file metadata structure - -**Implementation (`src/tools/note-tools.ts`)** -- Enhanced `readNote()` method with options parameter -- New `readExcalidraw()` method for Excalidraw files -- Integrated frontmatter parsing with FrontmatterUtils -- Maintains backward compatibility for existing clients - -**Tool Registry (`src/tools/index.ts`)** -- Updated `read_note` schema with new optional parameters -- Registered `read_excalidraw` tool with comprehensive schema -- Updated callTool to pass options to readNote and handle read_excalidraw - -#### Improvements (Post-Testing) - -- **Enhanced error handling** - Graceful handling of non-Excalidraw files with structured responses -- **Comprehensive documentation** - Detailed field descriptions in tool schema with explicit categorization -- **Full metadata exposure** - All Excalidraw metadata fields properly exposed per spec: - - `elementCount` - Number of drawing elements (always returned) - - `hasCompressedData` - Boolean for embedded images (always returned) - - `metadata` - Object with appState and version (always returned) - - `preview` - Text elements (conditional on includePreview) - - `compressedData` - Full drawing data (conditional on includeCompressed) -- **Enhanced type definitions** - JSDoc comments on all ExcalidrawMetadata fields -- **Complete specification** - New EXCALIDRAW_METADATA_SPEC.md with comprehensive documentation - -#### Bug Fixes (Post-Testing) - -- **Fixed missing metadata fields** - Resolved issue where `elementCount`, `hasCompressedData`, and `metadata` were not returned - - Added support for `compressed-json` code fence format (Excalidraw's actual format) - - Detects compressed (base64) vs uncompressed JSON data - - For compressed files: Returns `hasCompressedData: true` and `metadata.compressed: true` - - For uncompressed files: Extracts actual element count and metadata - - Multiple regex patterns to handle different Excalidraw formats - - Always return metadata fields with appropriate values -- **Known Limitation:** `elementCount` returns 0 for compressed files - - Most Excalidraw files use compressed base64 format by default - - Decompression would require pako library (not included to minimize dependencies) - - Text elements are still extracted in `preview` field - - Use `hasCompressedData: true` to identify compressed files - - This is expected behavior, not a bug - -#### Benefits - -- **Better frontmatter handling** - Separate frontmatter from content for easier processing -- **Excalidraw support** - First-class support for Excalidraw drawings with complete metadata -- **Flexible reading** - Choose what data to include in responses -- **Backward compatible** - Existing code continues to work unchanged -- **Type-safe** - Structured responses with proper TypeScript types -- **Robust** - Graceful error handling for edge cases - -## [3.0.0] - 2025-10-16 - -### πŸš€ Phase 4: Enhanced List Operations - -This release replaces `list_notes` with a powerful new `list` tool featuring advanced filtering, recursion, pagination, and frontmatter summaries. - -#### Breaking Changes - -**Removed Tools** -- `list_notes` - Replaced with the more powerful `list` tool - - **Migration:** Replace `list_notes({ path })` with `list({ path })` - - The new `list` tool is backwards compatible for basic usage - -#### Added - -**New Tool: `list`** -- Advanced file/directory listing with comprehensive filtering options -- **Recursive listing** - Traverse entire directory trees with `recursive: true` -- **Glob pattern filtering** - Include/exclude patterns supporting `*`, `**`, `?`, `[abc]`, `{a,b}` -- **Type filtering** - Filter by `files`, `directories`, or `any` -- **Cursor-based pagination** - Handle large result sets efficiently with `limit` and `cursor` -- **Frontmatter summaries** - Extract title, tags, aliases without reading full content -- Returns structured `ListResult` with items, totalCount, hasMore, and nextCursor - -**New Utilities (`src/utils/glob-utils.ts`)** -- `GlobUtils` class for pattern matching -- Supports wildcards: `*` (any chars except /), `**` (any chars including /), `?` (single char) -- Supports character classes: `[abc]`, alternatives: `{a,b,c}` -- `shouldInclude()` - Combined include/exclude filtering -- `matches()` - Test path against glob pattern - -**Type Definitions (`src/types/mcp-types.ts`)** -- `FrontmatterSummary` - Parsed frontmatter fields (title, tags, aliases, custom fields) -- `FileMetadataWithFrontmatter` - Extended file metadata with optional frontmatter -- `ListResult` - Paginated list response structure - -**Implementation (`src/tools/vault-tools.ts`)** -- `list(options)` method - Enhanced listing with all Phase 4 features -- `createFileMetadataWithFrontmatter()` - Efficient frontmatter extraction using metadata cache -- Recursive directory traversal -- Glob pattern filtering integration -- Cursor-based pagination logic - -**Tool Registry (`src/tools/index.ts`)** -- Registered `list` tool with comprehensive schema -- Removed `list_notes` tool definition -- Updated call handler to route `list` requests - -#### Features in Detail - -**Recursive Listing** -```typescript -// List all markdown files in vault recursively -list({ recursive: true, includes: ["*.md"] }) -``` - -**Glob Filtering** -```typescript -// Include only markdown files, exclude .obsidian folder -list({ - includes: ["*.md"], - excludes: [".obsidian/**"] -}) -``` - -**Type Filtering** -```typescript -// List only directories -list({ only: "directories" }) -``` - -**Pagination** -```typescript -// First page -list({ limit: 50 }) -// Next page using cursor -list({ limit: 50, cursor: "path/from/previous/response" }) -``` - -**Frontmatter Summaries** -```typescript -// Get file list with frontmatter metadata -list({ - withFrontmatterSummary: true, - includes: ["*.md"] -}) -``` - -#### Example Response - -```json -{ - "items": [ - { - "kind": "directory", - "name": "projects", - "path": "projects", - "childrenCount": 15, - "modified": 1697500800000 - }, - { - "kind": "file", - "name": "README.md", - "path": "README.md", - "extension": "md", - "size": 2048, - "modified": 1697500800000, - "created": 1697400000000, - "frontmatterSummary": { - "title": "Project Overview", - "tags": ["documentation", "readme"], - "aliases": ["index"] - } - } - ], - "totalCount": 2, - "hasMore": false -} -``` - -#### Performance - -- Frontmatter extraction uses Obsidian's metadata cache (no file reads) -- Glob matching uses efficient regex compilation -- Pagination prevents memory issues with large vaults -- Recursive listing optimized for vault structure - ---- - -## [2.1.0] - 2025-10-16 - -### ✨ Phase 3: Discovery Endpoints - -This release adds new tools for exploring vault structure and testing path validity. - -#### Added - -**New Tools** -- `stat` - Get detailed metadata for a file or folder at a specific path - - Returns existence status, kind (file/directory), and full metadata - - Includes size, dates, child count, etc. - - More detailed than `exists()` but slightly slower -- `exists` - Quickly check if a file or folder exists - - Fast path validation without fetching full metadata - - Returns existence status and kind only - - Optimized for quick existence checks - -**Type Definitions (`src/types/mcp-types.ts`)** -- `StatResult` - Structured result for stat operations (path, exists, kind, metadata) -- `ExistsResult` - Structured result for exists operations (path, exists, kind) - -**Implementation (`src/tools/vault-tools.ts`)** -- `stat(path)` method - Comprehensive path metadata retrieval -- `exists(path)` method - Fast existence checking -- Both methods use PathUtils for consistent path normalization -- Both methods validate paths and return structured JSON - -**Tool Registry (`src/tools/index.ts`)** -- Registered `stat` and `exists` tools with complete schemas -- Added call handlers for both new tools -- Comprehensive descriptions for AI agent usage - -#### Use Cases - -**`stat` Tool:** -- Verify a path exists before operations -- Get detailed file/folder information -- Check file sizes and modification dates -- Determine if a path is a file or directory - -**`exists` Tool:** -- Quick existence checks before create operations -- Validate paths in batch operations -- Fast pre-flight checks -- Minimal overhead for simple validation - -#### Example Responses - -**stat (file exists):** -```json -{ - "path": "folder/note.md", - "exists": true, - "kind": "file", - "metadata": { - "kind": "file", - "name": "note.md", - "path": "folder/note.md", - "extension": "md", - "size": 1234, - "modified": 1697500800000, - "created": 1697400000000 - } -} -``` - -**exists (folder exists):** -```json -{ - "path": "projects", - "exists": true, - "kind": "directory" -} -``` - -**stat (path doesn't exist):** -```json -{ - "path": "missing/file.md", - "exists": false -} -``` - ---- - -## [2.0.0] - 2025-10-16 - -### πŸ”§ Phase 2.1: Post-Testing Fixes - -Based on testing feedback, the following improvements were made to the Phase 2 implementation: - -#### Fixed - -**Root Listing Semantics (`src/tools/vault-tools.ts`)** -- Clarified root path handling: `undefined`, `""` (empty string), or `"."` all represent the vault root -- Root listing now correctly returns direct children only (excludes vault root itself) -- Added explicit check to skip vault root folder (path === '') -- Improved code clarity with explicit `isRootPath` check - -**Alphabetical Sorting** -- Fixed sorting to be case-insensitive for stable, consistent ordering -- Directories are sorted alphabetically (case-insensitive), then files alphabetically (case-insensitive) -- Ensures predictable order for names like "CTP Lancaster" and "Construction Game" - -**Directory Metadata** -- Added logic to populate `modified` timestamp from filesystem if available -- Falls back to `0` when filesystem metadata is not available (which is typical for directories) -- Added documentation explaining when `modified` may be `0` -- **Note:** Obsidian's TFolder API doesn't include `stat` property, so directories will typically show `modified: 0` - -**Documentation (`src/tools/index.ts`)** -- Updated `list_notes` description to document root path options (`""` or `"."`) -- Added explicit warning that leading slashes (e.g., `"/"` or `"/folder"`) are invalid -- Clarified that sorting is case-insensitive within each group -- Added note that only direct children are returned (non-recursive) - -#### Technical Details - -**Root Path Handling:** -```typescript -// All of these list the vault root: -list_notes() // undefined -list_notes({ path: "" }) // empty string -list_notes({ path: "." }) // dot -``` - -**Invalid Paths:** -```typescript -// These will error: -list_notes({ path: "/" }) // leading slash -list_notes({ path: "/folder" }) // leading slash -``` - ---- - -### πŸ”„ Phase 2: API Unification & Typed Results (BREAKING CHANGES) - -This release introduces structured, typed responses for all tools and unifies parameter naming. **Note: This is a breaking change as backwards compatibility is not maintained.** - -#### Added - -**Typed Result Interfaces (`src/types/mcp-types.ts`)** -- `FileMetadata` - Structured file information (kind, name, path, extension, size, modified, created) -- `DirectoryMetadata` - Structured directory information (kind, name, path, childrenCount, modified) -- `VaultInfo` - Structured vault information (name, path, totalFiles, totalFolders, markdownFiles, totalSize) -- `SearchMatch` - Detailed search match information (path, line, column, snippet, matchRanges) -- `SearchResult` - Comprehensive search results (query, matches, totalMatches, filesSearched, filesWithMatches) -- `ItemKind` - Type union for "file" | "directory" - -**Enhanced Tool Responses** -- All tools now return structured JSON instead of plain text -- Consistent response format across all operations -- Machine-readable data for better integration - -#### Changed - -**`list_notes` Tool (BREAKING)** -- Parameter: `folder` β†’ `path` (breaking change - `folder` parameter removed) -- Response: Now returns array of `FileMetadata` and `DirectoryMetadata` objects -- Behavior: Lists direct children only (non-recursive) -- Includes both files AND directories (not just markdown files) -- Sorted: directories first, then files, alphabetically -- Each item includes detailed metadata (size, dates, child count) - -**`search_notes` Tool (BREAKING)** -- Response: Now returns structured `SearchResult` object -- Includes line numbers, column positions, and context snippets -- Provides match ranges for highlighting -- Tracks files searched and files with matches -- Filename matches indicated with line: 0 - -**`get_vault_info` Tool (BREAKING)** -- Response: Now returns structured `VaultInfo` object -- Added: `totalFolders` count -- Added: `totalSize` in bytes -- Renamed: `rootPath` β†’ `path` - -**Tool Descriptions** -- Updated all tool descriptions to reflect structured JSON responses -- Clarified return value formats -- Removed deprecated `folder` parameter - -#### Implementation Details - -**`src/tools/vault-tools.ts`** -- `searchNotes()` - Complete rewrite with line-by-line search and snippet extraction -- `getVaultInfo()` - Added folder counting and size calculation -- `listNotes()` - Rewritten to return structured metadata for files and directories -- Added `createFileMetadata()` helper method -- Added `createDirectoryMetadata()` helper method - -**`src/tools/index.ts`** -- Updated tool schemas to use `path` parameter only -- Updated tool descriptions to document structured responses -- Modified `callTool()` to pass `path` parameter - -#### Migration Guide - -**Before (v1.x):** -```javascript -// list_notes returned plain text -"Found 3 notes:\nfile1.md\nfile2.md\nfile3.md" - -// search_notes returned plain text -"Found 2 notes:\npath/to/note1.md\npath/to/note2.md" - -// get_vault_info returned simple object -{ "name": "MyVault", "totalFiles": 100, "markdownFiles": 80, "rootPath": "/path" } -``` - -**After (v2.x):** -```javascript -// list_notes returns structured array -[ - { "kind": "directory", "name": "folder1", "path": "folder1", "childrenCount": 5, "modified": 0 }, - { "kind": "file", "name": "note.md", "path": "note.md", "extension": "md", "size": 1024, "modified": 1697472000000, "created": 1697472000000 } -] - -// search_notes returns detailed matches -{ - "query": "TODO", - "matches": [ - { "path": "note.md", "line": 5, "column": 10, "snippet": "...context around TODO item...", "matchRanges": [{ "start": 15, "end": 19 }] } - ], - "totalMatches": 1, - "filesSearched": 100, - "filesWithMatches": 1 -} - -// get_vault_info returns comprehensive info -{ "name": "MyVault", "path": "/path", "totalFiles": 100, "totalFolders": 20, "markdownFiles": 80, "totalSize": 5242880 } -``` - -#### Benefits -- **Machine-readable**: Structured JSON for easy parsing and integration -- **Detailed metadata**: Rich information for each file and directory -- **Search precision**: Line numbers, columns, and snippets for exact match location -- **Consistency**: Unified response format across all tools -- **Type safety**: Well-defined TypeScript interfaces - -## [1.2.0] - 2025-10-16 - -### πŸ“ Enhanced Parent Folder Detection (Phase 1.5) - -Improved `create_note` tool with explicit parent folder validation and optional automatic folder creation. - -#### Added - -**Parent Folder Validation (`src/tools/note-tools.ts`)** -- Explicit parent folder detection before file creation (fail-fast) -- New `createParents` parameter for automatic folder creation -- Recursive parent folder creation for deeply nested paths -- Validates parent is a folder (not a file) -- Clear error messages with actionable guidance - -**Tool Schema Updates (`src/tools/index.ts`)** -- Added `createParents` boolean parameter to `create_note` tool -- Default: `false` (safe behavior - requires parent folders to exist) -- Optional: `true` (convenience - auto-creates missing parent folders) -- Updated tool description with usage examples - -**Enhanced Error Messages (`src/utils/error-messages.ts`)** -- `parentFolderNotFound()` now suggests using `createParents: true` -- Provides example usage with auto-creation -- Computes grandparent path for better `list_notes()` suggestions -- Clear troubleshooting steps for missing parent folders - -**Comprehensive Test Suite (`tests/parent-folder-detection.test.ts`)** -- 15 test cases covering all scenarios -- Tests explicit parent folder detection -- Tests recursive folder creation -- Tests error handling and edge cases -- Validates error message content - -#### Changed -- `createNote()` signature: added optional `createParents` parameter -- Parent folder validation now happens before file creation attempt -- Error messages include `createParents` usage examples - -#### Benefits -- **Fail-fast behavior**: Errors detected before attempting file creation -- **Flexibility**: Optional auto-creation with `createParents: true` -- **Robustness**: Handles deeply nested paths and all edge cases -- **Backward compatible**: Existing code continues to work (default: `false`) - -### πŸ” Enhanced Authentication & Security (Phase 1.5) - -This update significantly improves authentication security and user experience with automatic key generation and enhanced UI. - -#### Added - -**Automatic API Key Generation (`src/utils/auth-utils.ts`)** -- `generateApiKey()` - Cryptographically secure random key generation (32 characters) -- `validateApiKey()` - API key validation with strength requirements -- Uses `crypto.getRandomValues()` for secure randomness -- Alphanumeric + special characters (`-`, `_`) for URL-safe keys - -**Enhanced Settings UI (`src/settings.ts`)** -- Auto-generate API key when authentication is enabled -- Copy to clipboard button for API key -- Regenerate key button with instant refresh -- Static, selectable API key display (full width) -- MCP client configuration snippet generator - - Dynamically includes/excludes Authorization header based on auth status - - Correct `mcpServers` format with `serverUrl` field - - Copy configuration button for one-click copying - - Partially selectable text for easy copying -- Restart warnings when authentication settings change -- Selectable connection information URLs - -**Security Improvements (`src/server/middleware.ts`)** -- Defensive authentication check: rejects requests if auth enabled but no key set -- Improved error messages for authentication failures -- Fail-secure design: blocks access when misconfigured - -**Server Validation (`src/main.ts`)** -- Prevents server start if authentication enabled without API key -- Clear error message guiding users to fix configuration -- Validation runs before server initialization - -#### Changed -- API key field changed from user-editable to auto-generated display -- Configuration snippet now shows for both authenticated and non-authenticated setups -- Connection information URLs are now selectable - -#### Security -- Fixed vulnerability where enabling authentication without API key allowed unrestricted access -- Three-layer defense: UI validation, server start validation, and middleware enforcement -- API keys are now always cryptographically secure (no weak user-chosen keys) - -## [1.1.0] - 2025-10-16 - -### 🎯 Phase 1.1: Path Normalization & Error Handling - -This release focuses on robustness, cross-platform compatibility, and significantly improved error messages. - -#### Added - -**Path Utilities (`src/utils/path-utils.ts`)** -- `PathUtils.normalizePath()` - Cross-platform path normalization (Windows/macOS/Linux) -- `PathUtils.isValidVaultPath()` - Path validation with security checks -- `PathUtils.resolveFile()` / `resolveFolder()` - Type-safe path resolution -- `PathUtils.fileExists()` / `folderExists()` - Existence checking -- `PathUtils.getPathType()` - Determine if path is file or folder -- `PathUtils.ensureMarkdownExtension()` - Auto-add .md extension -- `PathUtils.getParentPath()` / `getBasename()` - Path manipulation -- `PathUtils.joinPath()` - Safe path joining -- Handles backslashes, drive letters, trailing slashes automatically -- Prevents directory traversal attacks (`..` paths) - -**Enhanced Error Messages (`src/utils/error-messages.ts`)** -- Context-aware error messages with troubleshooting tips -- Dynamic `list_notes()` suggestions based on path context -- Operation-specific guidance (read, create, update, delete) -- Clear examples of correct path formats -- Platform-specific notes (case sensitivity on macOS/Linux) -- `ErrorMessages.fileNotFound()` - File not found with discovery tips -- `ErrorMessages.folderNotFound()` - Folder not found with navigation tips -- `ErrorMessages.invalidPath()` - Invalid path with format examples -- `ErrorMessages.pathAlreadyExists()` - Conflict resolution guidance -- `ErrorMessages.parentFolderNotFound()` - Parent folder missing with verification steps -- `ErrorMessages.cannotDeleteFolder()` - Folder deletion attempt with alternatives -- `ErrorMessages.notAFile()` / `notAFolder()` - Type mismatch errors -- `ErrorMessages.operationFailed()` - Generic operation failures - -**Testing Infrastructure** -- Jest testing framework configured -- 43 unit tests for PathUtils (all passing) -- Mock Obsidian API for testing (`tests/__mocks__/obsidian.ts`) -- Test coverage for cross-platform path handling -- Integration tests with mock App/Vault -- `npm test` / `npm run test:watch` / `npm run test:coverage` scripts - -**Documentation** -- `docs/TOOL_SELECTION_GUIDE.md` - Comprehensive 400+ line guide - - Decision table for tool selection - - Path format guidelines (correct vs incorrect) - - Common scenarios with step-by-step examples - - Troubleshooting decision tree - - Best practices checklist - - Quick reference card -- `docs/ERROR_MESSAGE_IMPROVEMENTS.md` - Error message enhancement documentation -- `docs/TOOL_DESCRIPTION_IMPROVEMENTS.md` - AI agent tool description improvements -- `tests/README.md` - Testing setup and guidelines -- `PHASE_1.1_IMPLEMENTATION.md` - Complete implementation summary - -#### Changed - -**All Tool Implementations Enhanced** -- `readNote()` - Path validation, better error messages, folder detection -- `createNote()` - Path normalization, conflict detection, parent folder validation -- `updateNote()` - Enhanced validation, clearer error messages -- `deleteNote()` - Folder detection with specific error message -- `listNotes()` - Path validation, folder verification, better errors - -**Tool Descriptions for AI Agents** -- All 7 MCP tool descriptions significantly enhanced -- Critical constraints stated upfront (e.g., "only files, NOT folders") -- Workflow guidance (e.g., "use list_notes() first if unsure") -- Path requirements clearly documented in every parameter -- Multiple concrete examples per tool -- Failure modes explicitly stated -- Self-documenting for AI agents without external docs - -**Error Message Consistency** -- All errors now include vault-relative path reminders -- Case sensitivity noted for macOS/Linux -- Context-specific `list_notes()` commands -- Operation-appropriate tool suggestions -- Consistent formatting across all tools - -#### Fixed - -- **Cross-platform paths** - Windows backslashes now handled correctly -- **Path validation** - Prevents invalid characters and directory traversal -- **Delete folder error** - Now clearly states "cannot delete folders" instead of confusing message -- **Parent folder detection** - Clear message when parent folder missing during create -- **Error message contradictions** - All error headers and bodies now consistent - -#### Technical Details - -**New Dependencies** -- jest: ^29.x (dev) -- @types/jest: ^29.x (dev) -- ts-jest: ^29.x (dev) - -**Test Coverage** -- 43 unit tests passing -- PathUtils: 100% coverage -- Cross-platform scenarios tested -- Mock Obsidian API for isolated testing - -**Build** -- All TypeScript compilation successful -- No breaking changes to existing APIs -- Backward compatible with v1.0.0 - -#### Developer Experience - -- Centralized path handling logic -- Type-safe path operations -- Comprehensive test suite -- Clear error messages reduce support burden -- Self-documenting code - ---- - -## [1.0.0] - 2025-10-16 - -### πŸŽ‰ Initial Release - -#### Added - -**Core Features** -- MCP (Model Context Protocol) server implementation -- HTTP transport with Express.js +**MCP Server** +- HTTP server implementing MCP protocol version 2024-11-05 - JSON-RPC 2.0 message handling -- Protocol version 2024-11-05 support - -**MCP Tools** -- `read_note` - Read note content from vault -- `create_note` - Create new notes -- `update_note` - Update existing notes -- `delete_note` - Delete notes -- `search_notes` - Search notes by content or filename -- `list_notes` - List all notes or notes in specific folder -- `get_vault_info` - Get vault metadata and statistics - -**Server Features** -- Configurable HTTP server (default port: 3000) -- Localhost-only binding (127.0.0.1) -- Health check endpoint (`/health`) -- MCP endpoint (`/mcp`) +- Localhost-only binding (127.0.0.1) for security +- Configurable port (default: 3000) - Auto-start option +**Note Operations** +- `read_note` - Read note content with optional frontmatter parsing +- `create_note` - Create notes with conflict handling (error/overwrite/rename) +- `update_note` - Update existing notes with concurrency control +- `delete_note` - Delete notes (soft delete to .trash or permanent) +- `update_frontmatter` - Update frontmatter fields without modifying content +- `update_sections` - Update specific sections by line range +- `rename_file` - Rename or move files with automatic wikilink updates +- `read_excalidraw` - Read Excalidraw drawing files with metadata + +**Vault Operations** +- `search` - Advanced search with regex, glob filtering, and snippets +- `search_waypoints` - Find Waypoint plugin markers +- `list` - List files/directories with filtering and pagination +- `stat` - Get detailed file/folder metadata +- `exists` - Quick existence check +- `get_vault_info` - Vault metadata and statistics + +**Waypoint Integration** +- `get_folder_waypoint` - Extract Waypoint blocks from folder notes +- `is_folder_note` - Detect folder notes +- Automatic waypoint edit protection + +**Link Management** +- `validate_wikilinks` - Validate all links in a note +- `resolve_wikilink` - Resolve single wikilink to target path +- `backlinks` - Get backlinks with optional unlinked mentions + **Security** -- Origin header validation (DNS rebinding protection) -- Optional Bearer token authentication -- CORS configuration with allowed origins -- Request validation and error handling +- Mandatory Bearer token authentication +- Auto-generated, cryptographically secure API keys (32 characters) +- API keys encrypted using system keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service) +- Host header validation (DNS rebinding protection) +- CORS policy fixed to localhost-only origins +- Desktop-only (requires Node.js HTTP server) **User Interface** - Settings panel with full configuration - Status bar indicator showing server state - Ribbon icon for quick server toggle - Start/Stop/Restart commands -- Real-time server status display -- Connection information display +- Real-time connection information +- Copy API key and configuration snippets +- Notification system for tool calls (optional) +- Notification history viewer -**Documentation** -- Comprehensive README with examples -- Quick Start Guide -- Implementation Summary -- Test client script -- Example MCP requests -- Security considerations +**Developer Experience** +- Cross-platform path handling (Windows/macOS/Linux) +- Comprehensive error messages with troubleshooting tips +- Path validation and normalization utilities +- Concurrency control via ETag-based versioning +- Type-safe TypeScript implementation +- Extensive test coverage +- Well-documented codebase -**Developer Tools** -- TypeScript implementation -- esbuild bundler -- Test client for validation -- Health check endpoint - -### Technical Details +#### Technical Details **Dependencies** - express: ^4.18.2 @@ -1304,108 +86,68 @@ This release focuses on robustness, cross-platform compatibility, and significan **Build** - TypeScript 4.7.4 - esbuild 0.17.3 -- Output: 828KB bundled +- Jest 30.2.0 for testing **Compatibility** - Obsidian minimum version: 0.15.0 -- Desktop only (requires Node.js HTTP server) +- Desktop only (not available on mobile) - Protocol: MCP 2024-11-05 -### Known Limitations +#### Known Limitations -- Desktop only (not available on mobile) +- Desktop only (requires Node.js HTTP server) - Single vault per server instance -- No WebSocket support (HTTP only) -- No SSL/TLS (localhost only) +- HTTP only (no WebSocket support) +- Localhost-only (no SSL/TLS) +- Excalidraw support limited to uncompressed format (compressed format planned) --- ## Future Roadmap -See [ROADMAP.md](ROADMAP.md) for detailed implementation plans. +### Planned Features -### Phase 1: Foundation (P0-P1) -- **Path Normalization** - Consistent path handling across platforms -- **Error Message Improvements** - Clear, actionable error messages with troubleshooting tips -- **Enhanced Authentication** - Secure API key management, multiple keys with labels, expiration, rate limiting, audit logging, and permission scopes -- **API Unification** - Standardize parameter naming and return structured, typed results -- **Discovery Endpoints** - Add `stat` and `exists` tools for exploring vault structure +**Resources API** +- Expose notes as MCP resources +- Real-time resource updates -### Phase 2: Enhanced Operations (P1-P2) -- **Write Operations & Concurrency** - ETag-based version control, partial updates (frontmatter, sections) -- **Conflict Resolution** - Create notes with conflict strategies (error, overwrite, rename) -- **File Rename/Move** - Rename or move files with automatic wikilink updates -- **Enhanced List Operations** - Filtering, recursion control, pagination, frontmatter summaries -- **Advanced Search** - Regex search, snippet extraction, glob filtering +**Prompts API** +- Templated prompts for common operations +- Custom prompt registration -### Phase 3: Advanced Features (P2-P3) -- **Frontmatter Parsing** - Read and update frontmatter without modifying content -- **Linking & Backlinks** - Wikilink validation, resolution, and backlink queries -- **Waypoint Support** - Tools for working with Waypoint plugin markers -- **Excalidraw Support** - Specialized tool for reading Excalidraw drawings +**Batch Operations** +- Multiple operations in single request +- Transactional batching -### Future Considerations -- **Resources API** - Expose notes as MCP resources -- **Prompts API** - Templated prompts for common operations -- **Batch Operations** - Multiple operations in single request -- **WebSocket Transport** - Real-time updates and notifications -- **Graph API** - Enhanced graph visualization and traversal -- **Tag & Canvas APIs** - Query tags and manipulate canvas files -- **Dataview Integration** - Query vault using Dataview syntax -- **Performance Enhancements** - Indexing, caching, streaming for large vaults +**WebSocket Transport** +- Real-time updates and notifications +- Bidirectional communication ---- +**Enhanced Graph API** +- Graph visualization data +- Advanced graph traversal -## Version History +**Tag & Canvas APIs** +- Query and manage tags +- Manipulate canvas files -| Version | Date | Notes | -|---------|------|-------| -| 1.1.0 | 2025-10-16 | Phase 1.1: Path normalization, enhanced error messages, testing infrastructure | -| 1.0.0 | 2025-10-16 | Initial release | +**Dataview Integration** +- Query vault using Dataview syntax +- Advanced data queries ---- - -## Upgrade Guide - -### From 1.0.0 to 1.1.0 - -This is a backward-compatible update. Simply update the plugin: - -1. Backup your settings (optional, but recommended) -2. Update the plugin files -3. Restart Obsidian or reload the plugin - -**What's New:** -- Better error messages with troubleshooting tips -- Improved cross-platform path handling -- Enhanced tool descriptions for AI agents -- No configuration changes required - -**Breaking Changes:** None - fully backward compatible - -### From Development to 1.0.0 - -If you were using a development version: - -1. Backup your settings -2. Disable the plugin -3. Delete the old plugin folder -4. Install version 1.0.0 -5. Re-enable and reconfigure - -### Breaking Changes - -None (initial release) +**Performance Enhancements** +- Indexing for faster searches +- Caching for frequently accessed notes +- Streaming for large files --- ## Support For issues, questions, or contributions: -- Check the README.md for documentation -- Review QUICKSTART.md for setup help -- Check existing issues before creating new ones -- Include version number in bug reports +- GitHub Issues: [Report bugs and request features] +- Documentation: See README.md and CLAUDE.md +- Include version number (1.0.0) in bug reports --- @@ -1413,4 +155,4 @@ For issues, questions, or contributions: - MCP Protocol: https://modelcontextprotocol.io - Obsidian API: https://github.com/obsidianmd/obsidian-api -- Built with TypeScript, Express.js, and ❀️ +- Built with TypeScript, Express.js, and dedication to quality diff --git a/TOOLS_COVERAGE_SUMMARY.md b/TOOLS_COVERAGE_SUMMARY.md deleted file mode 100644 index a4aff66..0000000 --- a/TOOLS_COVERAGE_SUMMARY.md +++ /dev/null @@ -1,70 +0,0 @@ -# Implementation Summary: 100% Tool Coverage - -**Date:** 2025-01-20 -**Branch:** feature/tools-coverage -**Goal:** Achieve 100% line coverage on note-tools.ts and vault-tools.ts - -## Achievement Summary - -βœ… **All objectives met - Both tools at 100% line coverage** - -### Coverage Improvements - -| Tool | Before | After | Improvement | -|------|--------|-------|-------------| -| note-tools.ts | 96.01% | **100%** | +3.99% | -| vault-tools.ts | 94.22% | **100%** | +5.78% | - -### Test Metrics - -**Before:** -- Total tests: 485 -- note-tools tests: 66 -- vault-tools tests: 72 - -**After:** -- Total tests: 505 (+20) -- note-tools tests: 74 (+8) -- vault-tools tests: 84 (+12) - -### Tasks Completed - -1. **Note-Tools Conflict Resolution** - Added 1 test covering lines 238-239 -2. **Note-Tools Folder-Not-File Errors** - Added 5 tests covering lines 377, 408, 590, 710, 836 -3. **Note-Tools Excalidraw & Frontmatter** - Added 2 tests covering lines 647, 771 -4. **Vault-Tools Invalid Path & Glob** - Added 3 tests covering lines 76, 272, 596-597 -5. **Vault-Tools Edge Cases** - Added 7 tests covering lines 267, 325, 374, 608, 620, 650 -6. **Vault-Tools Defensive Code** - Added 1 test + documented unreachable code (lines 452-456, 524-528, 777) - -### Commits - -1. `f6ec8d1` - test: add note-tools conflict resolution test -2. `4a17bdc` - test: add note-tools folder-not-file error tests -3. `dca6c34` - test: add note-tools Excalidraw and frontmatter tests -4. `73d4409` - test: add vault-tools invalid path and glob tests -5. `cf84f04` - test: add vault-tools edge case tests -6. `9e2a314` - test: add vault-tools defensive code coverage - -### Build Status - -βœ… **All tests passing:** 505/505 -βœ… **Build successful:** No type errors -βœ… **Coverage goals met:** 100% line coverage on both tools - -### Code Quality - -**Defensive Code Documentation:** -- Lines 452-456 (vault-tools stat method): Documented as unreachable, added istanbul ignore -- Lines 524-528 (vault-tools exists method): Documented as unreachable, added istanbul ignore -- Analysis shows these are unreachable because all TAbstractFile types are exhaustively handled - -**Test Quality:** -- All new tests use existing mock patterns -- Clear, descriptive test names -- Comprehensive error path coverage -- No flaky tests introduced - ---- - -**Status:** βœ… COMPLETE - Ready for merge -**Coverage:** note-tools 100%, vault-tools 100% diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md deleted file mode 100644 index e090626..0000000 --- a/TROUBLESHOOTING.md +++ /dev/null @@ -1,308 +0,0 @@ -# Troubleshooting Guide - -## Plugin Won't Load - -### Check Required Files - -Ensure these files exist in the plugin directory: -```bash -ls -la /path/to/vault/.obsidian/plugins/obsidian-mcp-server/ -``` - -Required files: -- βœ… `main.js` (should be ~846KB) -- βœ… `manifest.json` -- βœ… `styles.css` - -### Check Obsidian Console - -1. Open Obsidian -2. Press `Ctrl+Shift+I` (Windows/Linux) or `Cmd+Option+I` (Mac) -3. Go to the **Console** tab -4. Look for errors related to `obsidian-mcp-server` - -Common errors: -- **Module not found**: Rebuild the plugin with `npm run build` -- **Syntax error**: Check the build completed successfully -- **Permission error**: Ensure files are readable - -### Verify Plugin is Enabled - -1. Go to **Settings** β†’ **Community Plugins** -2. Find **MCP Server** in the list -3. Ensure the toggle is **ON** -4. If not visible, click **Reload** or restart Obsidian - -### Check Manifest - -Verify `manifest.json` contains: -```json -{ - "id": "obsidian-mcp-server", - "name": "MCP Server", - "version": "1.0.0", - "minAppVersion": "0.15.0", - "description": "Exposes Obsidian vault operations via Model Context Protocol (MCP) over HTTP", - "author": "", - "authorUrl": "", - "isDesktopOnly": true -} -``` - -### Rebuild from Source - -If the plugin still won't load: - -```bash -cd /path/to/vault/.obsidian/plugins/obsidian-mcp-server -npm install -npm run build -``` - -Then restart Obsidian. - -### Check Obsidian Version - -This plugin requires: -- **Minimum Obsidian version**: 0.15.0 -- **Desktop only** (not mobile) - -Check your version: -1. **Settings** β†’ **About** -2. Look for "Current version" - -### Verify Node.js Built-ins - -The plugin uses Node.js modules (http, express). Ensure you're running on desktop Obsidian, not mobile. - -## Plugin Loads But Shows No Info - -### Check Plugin Description - -If the plugin appears in the list but shows no description: - -1. Check `manifest.json` has a `description` field -2. Restart Obsidian -3. Try disabling and re-enabling the plugin - -### Check for Errors on Load - -1. Open Console (`Ctrl+Shift+I`) -2. Disable the plugin -3. Re-enable it -4. Watch for errors in console - -## Server Won't Start - -### Port Already in Use - -**Error**: "Port 3000 is already in use" - -**Solution**: -1. Go to **Settings** β†’ **MCP Server** -2. Change port to something else (e.g., 3001, 3002) -3. Try starting again - -Or find and kill the process using port 3000: -```bash -# Linux/Mac -lsof -i :3000 -kill -9 - -# Windows -netstat -ano | findstr :3000 -taskkill /PID /F -``` - -### Module Not Found - -**Error**: "Cannot find module 'express'" or similar - -**Solution**: -```bash -cd /path/to/vault/.obsidian/plugins/obsidian-mcp-server -npm install -npm run build -``` - -Restart Obsidian. - -### Permission Denied - -**Error**: "EACCES" or "Permission denied" - -**Solution**: -- Try a different port (above 1024) -- Check firewall settings -- Run Obsidian with appropriate permissions - -## Server Starts But Can't Connect - -### Check Server is Running - -Look at the status bar (bottom of Obsidian): -- Should show: `MCP: Running (3000)` -- If shows: `MCP: Stopped` - server isn't running - -### Test Health Endpoint - -Open browser or use curl: -```bash -curl http://127.0.0.1:3000/health -``` - -Should return: -```json -{"status":"ok","timestamp":1234567890} -``` - -### Check Localhost Binding - -The server only binds to `127.0.0.1` (localhost). You cannot connect from: -- Other computers on the network -- External IP addresses -- Public internet - -This is by design for security. - -### Test MCP Endpoint - -```bash -curl -X POST http://127.0.0.1:3000/mcp \ - -H "Content-Type: application/json" \ - -d '{"jsonrpc":"2.0","id":1,"method":"ping"}' -``` - -Should return: -```json -{"jsonrpc":"2.0","id":1,"result":{}} -``` - -## Authentication Issues - -### Wrong API Key - -**Error**: 401 Unauthorized - -**Solution**: -- Check API key in settings matches what you're sending -- Ensure format is: `Authorization: Bearer YOUR_API_KEY` -- Try disabling authentication temporarily to test - -### CORS Errors - -**Error**: "CORS policy" in browser console - -**Solution**: -1. Go to **Settings** β†’ **MCP Server** -2. Ensure "Enable CORS" is **ON** -3. Check "Allowed Origins" includes your origin or `*` -4. Restart server - -## Tools Not Working - -### Path Errors - -**Error**: "Note not found" - -**Solution**: -- Use relative paths from vault root -- Example: `folder/note.md` not `/full/path/to/note.md` -- Don't include vault name in path - -### Permission Errors - -**Error**: "EACCES" or "Permission denied" - -**Solution**: -- Check file permissions in vault -- Ensure Obsidian has file system access -- Check vault is not read-only - -### Search Returns Nothing - -**Issue**: `search_notes` returns no results - -**Solution**: -- Check query is not empty -- Search is case-insensitive -- Searches both filename and content -- Try simpler query - -## Getting Help - -### Collect Debug Information - -When reporting issues, include: - -1. **Obsidian version**: Settings β†’ About -2. **Plugin version**: Check manifest.json -3. **Operating System**: Windows/Mac/Linux -4. **Error messages**: From console (Ctrl+Shift+I) -5. **Steps to reproduce**: What you did before the error - -### Console Logs - -Enable detailed logging: -1. Open Console (`Ctrl+Shift+I`) -2. Try the failing operation -3. Copy all red error messages -4. Include in your report - -### Test Client Output - -Run the test client and include output: -```bash -node test-client.js -``` - -### Check GitHub Issues - -Before creating a new issue: -1. Search existing issues -2. Check if it's already reported -3. See if there's a workaround - -## Common Solutions - -### "Have you tried turning it off and on again?" - -Seriously, this fixes many issues: -1. Stop the server -2. Disable the plugin -3. Restart Obsidian -4. Enable the plugin -5. Start the server - -### Clean Reinstall - -If all else fails: -```bash -# Backup settings first! -cd /path/to/vault/.obsidian/plugins -rm -rf obsidian-mcp-server -# Re-install plugin -cd obsidian-mcp-server -npm install -npm run build -``` - -Restart Obsidian. - -### Reset Settings - -If settings are corrupted: -1. Stop server -2. Disable plugin -3. Delete `/path/to/vault/.obsidian/plugins/obsidian-mcp-server/data.json` -4. Re-enable plugin -5. Reconfigure settings - -## Still Having Issues? - -1. Check the README.md for documentation -2. Review QUICKSTART.md for setup steps -3. Run the test client to verify server -4. Check Obsidian console for errors -5. Try a clean rebuild -6. Create a GitHub issue with debug info diff --git a/UTILS_COVERAGE_SUMMARY.md b/UTILS_COVERAGE_SUMMARY.md deleted file mode 100644 index 99406b2..0000000 --- a/UTILS_COVERAGE_SUMMARY.md +++ /dev/null @@ -1,167 +0,0 @@ -# Utils Coverage Completion Summary - -**Date:** 2025-01-20 -**Branch:** feature/utils-coverage -**Objective:** Achieve 100% line coverage on all utils modules - -## Achievement Summary - -βœ… **Goal Achieved:** All 4 target utils modules now at 100% line coverage - -### Coverage Improvements - -| Module | Before | After | Improvement | Method | -|--------|--------|-------|-------------|--------| -| **error-messages.ts** | 82.6% | **100%** | +17.4% | Dead code removal | -| **version-utils.ts** | 88.88% | **100%** | +11.12% | Dead code removal | -| **path-utils.ts** | 98.18% | **100%** | +1.82% | Test addition + code fix | -| **frontmatter-utils.ts** | 96.55% | **98.34%** | +1.79% | Bug fix + test addition | - -**Note:** frontmatter-utils.ts lines 301-303 remain uncovered (Buffer.from fallback for environments without atob). This is defensive code unreachable in Jest/Node environments and is acceptable. - -### Overall Project Coverage - -- **Total Coverage:** 99.71% statements, 94.46% branches, 99% functions, 99.8% lines -- **Test Count:** 505 β†’ **512 tests** (+7 new tests) -- **All Tests:** βœ… 512 passing, 0 failing -- **Build Status:** βœ… Successful - -## Work Completed - -### Phase 1: Dead Code Removal (3 commits) - -**Commit 1:** `896dda0` - Remove dead code from error-messages.ts -- Deleted `permissionDenied()` method (12 lines) -- Deleted `formatError()` method (14 lines) -- Result: 82.6% β†’ 100% coverage - -**Commit 2:** `59812e5` - Remove unused createVersionedResponse() method -- Deleted `createVersionedResponse()` method (11 lines) -- Result: 88.88% β†’ 100% coverage - -**Commit 3:** `fb82642` - Remove createVersionedResponse() reference from CHANGELOG -- Cleaned up documentation for deleted method - -### Phase 2: Test Addition & Bug Fixes (3 commits) - -**Commit 4:** `b902ed4` - Achieve 100% coverage on path-utils.ts -- Fixed code ordering bug that made Windows drive validation unreachable -- Reordered validation checks in `isValidVaultPath()` -- Added 3 new tests for `pathExists()` method -- Updated 2 tests to use backslash format for Windows paths -- Result: 98.18% β†’ 100% coverage - -**Commit 5:** `e76f316` - Make Pattern 4 reachable in Excalidraw code fence parsing -- Fixed regex bug: Changed `[a-z-]*` to `[a-z-]+` in Pattern 3 -- Added test for code fence without language specifier -- Result: Made lines 253-255 reachable and covered - -**Commit 6:** `945d59b` - Add decompression failure handling and test coverage -- Added base64 validation before decompression -- Added error logging in catch block -- Added test for decompression failure handling -- Result: Covered lines 318-327 - -## Technical Details - -### Dead Code Identified - -1. **ErrorMessages.permissionDenied()** - Never called in codebase -2. **ErrorMessages.formatError()** - Never called in codebase -3. **VersionUtils.createVersionedResponse()** - Never called (only in docs) - -**Total Lines Removed:** 37 lines of dead code - -### Bugs Fixed - -1. **path-utils.ts**: Windows absolute path check was unreachable - - **Issue:** Invalid character check (including `:`) ran before Windows drive letter check - - **Fix:** Reordered validation logic to check absolute paths first - - **Impact:** No behavioral change, but correct code path now executes - -2. **frontmatter-utils.ts**: Pattern 4 was unreachable - - **Issue:** Pattern 3 regex `[a-z-]*` (zero or more) matched empty string, preventing Pattern 4 from executing - - **Fix:** Changed to `[a-z-]+` (one or more) to require language specifier - - **Impact:** Pattern 4 now properly handles code fences without language specifiers - -### Tests Added - -1. **path-utils.test.ts** (+3 tests) - - pathExists() - file exists - - pathExists() - folder exists - - pathExists() - path does not exist - -2. **frontmatter-utils.test.ts** (+2 tests) - - Parses Excalidraw with code fence lacking language specifier - - Handles decompression failure gracefully - -3. **Updated tests** (2) - - Windows absolute paths now use backslash format - -**Total:** +5 new tests, 2 updated tests - -## Commit History - -``` -b902ed4 test: achieve 100% coverage on path-utils.ts -e76f316 fix: Make Pattern 4 reachable in Excalidraw code fence parsing -945d59b test: add decompression failure handling and test coverage -fb82642 docs: remove createVersionedResponse() reference from CHANGELOG -59812e5 test: remove unused createVersionedResponse() method -896dda0 refactor: remove dead code from error-messages.ts -``` - -## Files Modified - -### Source Code -- `src/utils/error-messages.ts` (-28 lines) -- `src/utils/version-utils.ts` (-11 lines) -- `src/utils/path-utils.ts` (+6 lines reordering) -- `src/utils/frontmatter-utils.ts` (+11 lines validation) - -### Tests -- `tests/path-utils.test.ts` (+24 lines) -- `tests/frontmatter-utils.test.ts` (+56 lines) - -### Documentation -- `CHANGELOG.md` (-1 line) -- `docs/plans/2025-01-20-utils-coverage-completion.md` (created) - -## Verification - -βœ… All 512 tests passing -βœ… Build successful (`npm run build`) -βœ… Coverage improved across all target modules -βœ… No regressions introduced -βœ… Code quality maintained - -## Success Criteria Met - -- βœ… error-messages.ts at 100% line coverage -- βœ… version-utils.ts at 100% line coverage -- βœ… path-utils.ts at 100% line coverage -- βœ… frontmatter-utils.ts at 98.34% line coverage (100% reachable code) -- βœ… All tests passing (512 tests, +7 from baseline) -- βœ… Build succeeds -- βœ… Dead code removed cleanly (37 lines) -- βœ… 2 subtle bugs fixed -- βœ… Work documented - -## Key Insights - -1. **Dead Code Discovery:** Three utility methods existed that were never called - identifying and removing them improved coverage without adding tests - -2. **Unreachable Code Bugs:** Found two subtle bugs where validation logic was unreachable due to code ordering or regex patterns - these weren't functional bugs but prevented proper code coverage - -3. **Test-Driven Improvements:** Adding targeted tests not only improved coverage but revealed underlying code quality issues that needed fixing - -4. **Defensive Code:** Lines 301-303 in frontmatter-utils.ts represent legitimate defensive code for environments without `atob` - acceptable to leave uncovered in Jest environment - -## Next Steps - -This work completes the pre-release validation for utils modules. Combined with the previous tools coverage work, the codebase now has: -- **Tools:** 100% line coverage (note-tools.ts, vault-tools.ts) -- **Utils:** 100% line coverage (all reachable code in 7 modules) -- **Overall:** 99.8% line coverage - -Ready to merge to master. diff --git a/manifest.json b/manifest.json index dd7d977..3a76386 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "obsidian-mcp-server", "name": "MCP Server", - "version": "3.0.0", + "version": "1.0.0", "minAppVersion": "0.15.0", "description": "Exposes Obsidian vault operations via Model Context Protocol (MCP) over HTTP", "author": "Bill Ballou", diff --git a/package.json b/package.json index 12ef303..af6d03f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-mcp-server", - "version": "3.0.0", + "version": "1.0.0", "description": "MCP (Model Context Protocol) server plugin for Obsidian - exposes vault operations via HTTP", "main": "main.js", "scripts": { diff --git a/versions.json b/versions.json index d722c35..26382a1 100644 --- a/versions.json +++ b/versions.json @@ -1,8 +1,3 @@ { - "1.0.0": "0.15.0", - "1.1.0": "0.15.0", - "1.2.0": "0.15.0", - "2.0.0": "0.15.0", - "2.1.0": "0.15.0", - "3.0.0": "0.15.0" + "1.0.0": "0.15.0" }