b7b3a185a0
Implement `ensureFolderExists` in `ToolExecutor` to create parent directories when creating, moving, or renaming notes. Update `ChatView` to properly persist agent mode and derive session titles from the first user message. Fix error handling in tool execution to return structured failures instead of null, and include failure details in follow-up messages.
138 lines
2.6 KiB
TypeScript
Executable File
138 lines
2.6 KiB
TypeScript
Executable File
// Enhanced Obsidian mock for testing
|
|
|
|
// Mock Vault
|
|
export class Vault {
|
|
getMarkdownFiles: () => any[];
|
|
read: (file: any) => Promise<string>;
|
|
create: (path: string, content: string) => Promise<any>;
|
|
createFolder: (path: string) => Promise<any>;
|
|
|
|
constructor() {
|
|
this.getMarkdownFiles = () => [];
|
|
this.read = async () => '';
|
|
this.create = async () => null;
|
|
this.createFolder = async () => null;
|
|
}
|
|
}
|
|
|
|
// Mock Workspace
|
|
export class Workspace {
|
|
getLeaf: () => any;
|
|
|
|
constructor() {
|
|
this.getLeaf = () => ({
|
|
setViewState: jest.fn(),
|
|
revealLeaf: jest.fn(),
|
|
});
|
|
}
|
|
}
|
|
|
|
// Mock App
|
|
export class App {
|
|
vault: Vault;
|
|
workspace: Workspace;
|
|
metadataCache: {
|
|
getFileCache: jest.Mock;
|
|
getFirstLinkpathDest: jest.Mock;
|
|
resolvedLinks: Record<string, Record<string, number>>;
|
|
};
|
|
|
|
constructor() {
|
|
this.vault = new Vault();
|
|
this.workspace = new Workspace();
|
|
this.metadataCache = {
|
|
getFileCache: jest.fn().mockReturnValue(null),
|
|
getFirstLinkpathDest: jest.fn().mockReturnValue(null),
|
|
resolvedLinks: {},
|
|
};
|
|
}
|
|
}
|
|
|
|
// Mock WorkspaceLeaf
|
|
export class WorkspaceLeaf {
|
|
app: App;
|
|
view: any;
|
|
setViewState: jest.Mock;
|
|
|
|
constructor() {
|
|
this.app = new App();
|
|
this.view = null;
|
|
this.setViewState = jest.fn();
|
|
}
|
|
}
|
|
|
|
// Mock ItemView - accepts a leaf and derives app from it
|
|
export class ItemView {
|
|
contentEl: HTMLElement;
|
|
app: App;
|
|
|
|
constructor(leaf?: WorkspaceLeaf) {
|
|
this.contentEl = document.createElement('div');
|
|
if (leaf && leaf.app) {
|
|
this.app = leaf.app;
|
|
} else {
|
|
this.app = new App();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Mock Notice - can be called with `new Notice(msg)` or as a function
|
|
export class Notice {
|
|
message: string;
|
|
|
|
constructor(message: string) {
|
|
this.message = message;
|
|
// Also record via jest for testing
|
|
(Notice as any).lastMessage = message;
|
|
}
|
|
}
|
|
(Notice as any).lastMessage = '';
|
|
|
|
// Mock Setting
|
|
export class Setting {
|
|
containerEl: HTMLElement;
|
|
|
|
constructor(containerEl: HTMLElement) {
|
|
this.containerEl = containerEl;
|
|
}
|
|
|
|
setName(_name: string): this {
|
|
return this;
|
|
}
|
|
|
|
setDesc(_desc: string): this {
|
|
return this;
|
|
}
|
|
|
|
addText(_callback: (text: any) => void): this {
|
|
return this;
|
|
}
|
|
}
|
|
|
|
// TFile type
|
|
export interface TFile {
|
|
basename: string;
|
|
path: string;
|
|
}
|
|
|
|
export class TFolder {
|
|
path: string;
|
|
|
|
constructor(path: string = '') {
|
|
this.path = path;
|
|
}
|
|
}
|
|
|
|
// Plugin class (used by main.ts)
|
|
export class Plugin {
|
|
app: App;
|
|
|
|
constructor() {
|
|
this.app = new App();
|
|
}
|
|
|
|
addRibbonIcon(_icon: string, _title: string, _callback: () => void): HTMLElement {
|
|
return document.createElement('div');
|
|
}
|
|
}
|