Release v1.1.0: Phase 1.1 - Path Normalization & Error Handling
- Add PathUtils for cross-platform path normalization and validation - Add ErrorMessages with context-aware, actionable error messages - Update all tool implementations with enhanced path handling - Improve tool descriptions for AI agents with detailed guidance - Add Jest testing infrastructure with 43 passing tests - Add comprehensive documentation (Tool Selection Guide, error improvements) - Fix cross-platform path issues (Windows backslashes, case sensitivity) - Fix delete folder error message (clear 'cannot delete folders' message) - Fix parent folder detection with specific error messages - All changes backward compatible with v1.0.0 New files: - src/utils/path-utils.ts - Path normalization utilities - src/utils/error-messages.ts - Enhanced error messages - tests/__mocks__/obsidian.ts - Mock Obsidian API - tests/path-utils.test.ts - 43 unit tests - tests/README.md - Testing guide - jest.config.js - Jest configuration - docs/TOOL_SELECTION_GUIDE.md - Comprehensive tool guide - docs/ERROR_MESSAGE_IMPROVEMENTS.md - Error message documentation - docs/TOOL_DESCRIPTION_IMPROVEMENTS.md - AI agent improvements - PHASE_1.1_IMPLEMENTATION.md - Implementation summary - RELEASE_NOTES_v1.1.0.md - Release notes Updated: - CHANGELOG.md - Add v1.1.0 entry - ROADMAP.md - Mark Phase 1.1 complete, add Phase 1.5 proposal - manifest.json - Bump to v1.1.0 - package.json - Bump to v1.1.0, add test scripts - src/tools/index.ts - Enhanced tool descriptions - src/tools/note-tools.ts - Use PathUtils and ErrorMessages - src/tools/vault-tools.ts - Use PathUtils and ErrorMessages
This commit is contained in:
189
ROADMAP.md
189
ROADMAP.md
@@ -40,22 +40,25 @@ The plugin is currently minimally functioning with basic CRUD operations and sim
|
||||
|
||||
## Priority Matrix
|
||||
|
||||
| Priority | Category | Estimated Effort |
|
||||
|----------|----------|------------------|
|
||||
| **P0** | Path Normalization | 1-2 days |
|
||||
| **P0** | Error Message Improvements | 1 day |
|
||||
| **P0** | Enhanced Authentication | 2-3 days |
|
||||
| **P1** | API Unification | 2-3 days |
|
||||
| **P1** | Typed Results | 1-2 days |
|
||||
| **P1** | Discovery Endpoints | 2-3 days |
|
||||
| **P1** | Write Operations & Concurrency | 5-6 days |
|
||||
| **P2** | List Ergonomics | 3-4 days |
|
||||
| **P2** | Enhanced Search | 4-5 days |
|
||||
| **P2** | Linking & Backlinks | 3-4 days |
|
||||
| **P3** | Advanced Read Operations | 2-3 days |
|
||||
| **P3** | Waypoint Support | 3-4 days |
|
||||
| Priority | Category | Estimated Effort | Status |
|
||||
|----------|----------|------------------|--------|
|
||||
| **P0** | Path Normalization | 1-2 days | ✅ Complete |
|
||||
| **P0** | Error Message Improvements | 1 day | ✅ Complete |
|
||||
| **P0** | Enhanced Parent Folder Detection | 0.5 days | 📋 Proposed |
|
||||
| **P0** | Enhanced Authentication | 2-3 days | ⏳ Pending |
|
||||
| **P1** | API Unification | 2-3 days | ⏳ Pending |
|
||||
| **P1** | Typed Results | 1-2 days | ⏳ Pending |
|
||||
| **P1** | Discovery Endpoints | 2-3 days | ⏳ Pending |
|
||||
| **P1** | Write Operations & Concurrency | 5-6 days | ⏳ Pending |
|
||||
| **P2** | List Ergonomics | 3-4 days | ⏳ Pending |
|
||||
| **P2** | Enhanced Search | 4-5 days | ⏳ Pending |
|
||||
| **P2** | Linking & Backlinks | 3-4 days | ⏳ Pending |
|
||||
| **P3** | Advanced Read Operations | 2-3 days | ⏳ Pending |
|
||||
| **P3** | Waypoint Support | 3-4 days | ⏳ Pending |
|
||||
|
||||
**Total Estimated Effort:** 29-42 days
|
||||
**Total Estimated Effort:** 29.5-42.5 days
|
||||
**Completed:** 2-3 days (Phase 1.1)
|
||||
**Remaining:** 27.5-39.5 days
|
||||
|
||||
---
|
||||
|
||||
@@ -75,31 +78,31 @@ Ensure consistent path handling across Windows, macOS, and Linux, with clear err
|
||||
|
||||
**File:** `path-utils.ts` (new)
|
||||
|
||||
- [ ] Create utility module for path operations
|
||||
- [ ] Implement `normalizePath(path: string): string`
|
||||
- [x] Create utility module for path operations
|
||||
- [x] Implement `normalizePath(path: string): string`
|
||||
- Strip leading/trailing slashes
|
||||
- Convert backslashes to forward slashes
|
||||
- Handle Windows drive letters
|
||||
- Normalize case on Windows (case-insensitive)
|
||||
- Preserve case on macOS/Linux (case-sensitive)
|
||||
- [ ] Implement `isValidVaultPath(path: string): boolean`
|
||||
- [ ] Implement `resolveVaultPath(app: App, path: string): TFile | TFolder | null`
|
||||
- [ ] Add unit tests for path normalization
|
||||
- [x] Implement `isValidVaultPath(path: string): boolean`
|
||||
- [x] Implement `resolveVaultPath(app: App, path: string): TFile | TFolder | null`
|
||||
- [x] Add unit tests for path normalization
|
||||
|
||||
#### 1.2 Update All Tool Implementations
|
||||
|
||||
- [ ] Replace direct `getAbstractFileByPath` calls with `PathUtils.resolveFile/Folder`
|
||||
- [ ] Update `readNote`, `createNote`, `updateNote`, `deleteNote`, `listNotes`
|
||||
- [ ] Add path normalization to all endpoints
|
||||
- [x] Replace direct `getAbstractFileByPath` calls with `PathUtils.resolveFile/Folder`
|
||||
- [x] Update `readNote`, `createNote`, `updateNote`, `deleteNote`, `listNotes`
|
||||
- [x] Add path normalization to all endpoints
|
||||
|
||||
#### 1.3 Enhanced Error Messages
|
||||
|
||||
**File:** `error-messages.ts` (new)
|
||||
|
||||
- [ ] Create error message templates with helpful guidance
|
||||
- [ ] Include suggested next actions
|
||||
- [ ] Add links to documentation examples
|
||||
- [ ] Implement `fileNotFound()`, `folderNotFound()`, `invalidPath()` helpers
|
||||
- [x] Create error message templates with helpful guidance
|
||||
- [x] Include suggested next actions
|
||||
- [x] Add links to documentation examples
|
||||
- [x] Implement `fileNotFound()`, `folderNotFound()`, `invalidPath()` helpers
|
||||
|
||||
**Example Error Format:**
|
||||
```
|
||||
@@ -114,11 +117,133 @@ Troubleshooting tips:
|
||||
|
||||
#### 1.4 Testing
|
||||
|
||||
- [ ] Test with Windows paths (backslashes, drive letters)
|
||||
- [ ] Test with macOS paths (case-sensitive)
|
||||
- [ ] Test with Linux paths
|
||||
- [ ] Test trailing slash handling
|
||||
- [ ] Test error message clarity
|
||||
- [x] Test with Windows paths (backslashes, drive letters)
|
||||
- [x] Test with macOS paths (case-sensitive)
|
||||
- [x] Test with Linux paths
|
||||
- [x] Test trailing slash handling
|
||||
- [x] Test error message clarity
|
||||
|
||||
**Note:** Test files have been created in `tests/` directory. To run tests, Jest needs to be set up (see `tests/README.md`).
|
||||
|
||||
#### 1.5 Enhanced Parent Folder Detection
|
||||
|
||||
**Priority:** P0
|
||||
**Status:** Partially Implemented (v1.1.0), Enhancement Proposed
|
||||
**Estimated Effort:** 0.5 days
|
||||
|
||||
**Goal:** Improve parent folder validation in `createNote()` with explicit detection before write operations.
|
||||
|
||||
**Current Status (v1.1.0):**
|
||||
- ✅ Basic parent folder error detection (catches Obsidian's error)
|
||||
- ✅ Enhanced error message with troubleshooting tips
|
||||
- ✅ `ErrorMessages.parentFolderNotFound()` implemented
|
||||
- ❌ Detection happens during write (not before)
|
||||
- ❌ No `createParents` parameter option
|
||||
|
||||
**Tasks:**
|
||||
|
||||
- [ ] Add explicit parent folder detection in `createNote()`
|
||||
- Compute parent path using `PathUtils.getParentPath(path)` before write
|
||||
- Check if parent exists using `PathUtils.folderExists(app, parentPath)`
|
||||
- Check if parent is actually a folder (not a file)
|
||||
- Return clear error before attempting file creation
|
||||
|
||||
- [ ] Enhance `ErrorMessages.parentFolderNotFound()`
|
||||
- Ensure consistent error message template
|
||||
- Include parent path in error message
|
||||
- Provide actionable troubleshooting steps
|
||||
- Suggest using `list_notes()` to verify parent structure
|
||||
|
||||
- [ ] Optional: Add `createParents` parameter
|
||||
- Add optional `createParents?: boolean` parameter to `create_note` tool
|
||||
- Default to `false` (no auto-creation)
|
||||
- If `true`, recursively create parent folders before file creation
|
||||
- Document behavior clearly in tool description
|
||||
- Add tests for both modes
|
||||
|
||||
- [ ] Update tool schema
|
||||
- Add `createParents` parameter to `create_note` inputSchema
|
||||
- Document default behavior (no auto-creation)
|
||||
- Update tool description to mention parent folder requirement
|
||||
- Add examples with and without `createParents`
|
||||
|
||||
- [ ] Testing
|
||||
- Test parent folder detection with missing parent
|
||||
- Test parent folder detection when parent is a file
|
||||
- Test with nested missing parents (a/b/c where b doesn't exist)
|
||||
- Test `createParents: true` creates all missing parents
|
||||
- Test `createParents: false` returns error for missing parents
|
||||
- Test error message clarity and consistency
|
||||
|
||||
**Implementation Notes:**
|
||||
|
||||
```typescript
|
||||
// Pseudo-code for enhanced createNote()
|
||||
async createNote(path: string, content: string, createParents = false) {
|
||||
// Validate path
|
||||
if (!PathUtils.isValidVaultPath(path)) {
|
||||
return ErrorMessages.invalidPath(path);
|
||||
}
|
||||
|
||||
// Normalize path
|
||||
const normalizedPath = PathUtils.normalizePath(path);
|
||||
|
||||
// Check if file already exists
|
||||
if (PathUtils.fileExists(this.app, normalizedPath)) {
|
||||
return ErrorMessages.pathAlreadyExists(normalizedPath, 'file');
|
||||
}
|
||||
|
||||
// Explicit parent folder detection
|
||||
const parentPath = PathUtils.getParentPath(normalizedPath);
|
||||
if (parentPath) {
|
||||
// Check if parent exists
|
||||
if (!PathUtils.pathExists(this.app, parentPath)) {
|
||||
if (createParents) {
|
||||
// Auto-create parent folders
|
||||
await this.createParentFolders(parentPath);
|
||||
} else {
|
||||
return ErrorMessages.parentFolderNotFound(normalizedPath, parentPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if parent is actually a folder (not a file)
|
||||
if (PathUtils.fileExists(this.app, parentPath)) {
|
||||
return ErrorMessages.notAFolder(parentPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Proceed with file creation
|
||||
try {
|
||||
const file = await this.app.vault.create(normalizedPath, content);
|
||||
return { success: true, path: file.path };
|
||||
} catch (error) {
|
||||
return ErrorMessages.operationFailed('create note', normalizedPath, error.message);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Error Message Template:**
|
||||
|
||||
```
|
||||
Parent folder does not exist: "mcp-plugin-test/missing-parent"
|
||||
|
||||
Cannot create "mcp-plugin-test/missing-parent/file.md" because its parent folder is missing.
|
||||
|
||||
Troubleshooting tips:
|
||||
• Create the parent folder first using Obsidian
|
||||
• Verify the folder path with list_notes("mcp-plugin-test")
|
||||
• Check that the parent folder path is correct (vault-relative, case-sensitive on macOS/Linux)
|
||||
• Note: Automatic parent folder creation is not currently enabled
|
||||
• Consider using createParents: true parameter to auto-create folders
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
|
||||
- ✅ Explicit detection before write operation (fail fast)
|
||||
- ✅ Clear error message with exact missing parent path
|
||||
- ✅ Consistent error messaging across all tools
|
||||
- ✅ Optional auto-creation for convenience
|
||||
- ✅ Better user experience with actionable guidance
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user