feat: Phase 3 - Discovery Endpoints (stat and exists tools)

- Add stat tool for detailed file/folder metadata
- Add exists tool for fast path existence checking
- Add StatResult and ExistsResult type definitions
- Implement stat() and exists() methods in VaultTools
- Register both tools in ToolRegistry with complete schemas
- Update version to 2.1.0
- Update ROADMAP.md to mark Phase 3 complete
- Update CHANGELOG.md with Phase 3 release notes
- Add IMPLEMENTATION_NOTES_PHASE3.md documentation
- Clean up old phase documentation files
This commit is contained in:
2025-10-16 22:59:38 -04:00
parent 9d07ec64e2
commit 83ac6bedfa
12 changed files with 614 additions and 572 deletions

View File

@@ -1,5 +1,5 @@
import { App, TFile, TFolder } from 'obsidian';
import { CallToolResult, FileMetadata, DirectoryMetadata, VaultInfo, SearchResult, SearchMatch } from '../types/mcp-types';
import { CallToolResult, FileMetadata, DirectoryMetadata, VaultInfo, SearchResult, SearchMatch, StatResult, ExistsResult } from '../types/mcp-types';
import { PathUtils } from '../utils/path-utils';
import { ErrorMessages } from '../utils/error-messages';
@@ -239,4 +239,119 @@ export class VaultTools {
modified: modified
};
}
// Phase 3: Discovery Endpoints
async stat(path: string): Promise<CallToolResult> {
// Validate path
if (!PathUtils.isValidVaultPath(path)) {
return {
content: [{ type: "text", text: ErrorMessages.invalidPath(path) }],
isError: true
};
}
// Normalize the path
const normalizedPath = PathUtils.normalizePath(path);
// Check if it's a file
const file = PathUtils.resolveFile(this.app, normalizedPath);
if (file) {
const result: StatResult = {
path: normalizedPath,
exists: true,
kind: "file",
metadata: this.createFileMetadata(file)
};
return {
content: [{
type: "text",
text: JSON.stringify(result, null, 2)
}]
};
}
// Check if it's a folder
const folder = PathUtils.resolveFolder(this.app, normalizedPath);
if (folder) {
const result: StatResult = {
path: normalizedPath,
exists: true,
kind: "directory",
metadata: this.createDirectoryMetadata(folder)
};
return {
content: [{
type: "text",
text: JSON.stringify(result, null, 2)
}]
};
}
// Path doesn't exist
const result: StatResult = {
path: normalizedPath,
exists: false
};
return {
content: [{
type: "text",
text: JSON.stringify(result, null, 2)
}]
};
}
async exists(path: string): Promise<CallToolResult> {
// Validate path
if (!PathUtils.isValidVaultPath(path)) {
return {
content: [{ type: "text", text: ErrorMessages.invalidPath(path) }],
isError: true
};
}
// Normalize the path
const normalizedPath = PathUtils.normalizePath(path);
// Check if it's a file
if (PathUtils.fileExists(this.app, normalizedPath)) {
const result: ExistsResult = {
path: normalizedPath,
exists: true,
kind: "file"
};
return {
content: [{
type: "text",
text: JSON.stringify(result, null, 2)
}]
};
}
// Check if it's a folder
if (PathUtils.folderExists(this.app, normalizedPath)) {
const result: ExistsResult = {
path: normalizedPath,
exists: true,
kind: "directory"
};
return {
content: [{
type: "text",
text: JSON.stringify(result, null, 2)
}]
};
}
// Path doesn't exist
const result: ExistsResult = {
path: normalizedPath,
exists: false
};
return {
content: [{
type: "text",
text: JSON.stringify(result, null, 2)
}]
};
}
}