feat: Add Diff View and File History Tracking

- Implemented a new Diff view in the Workbench to track file changes
- Added file history tracking with version control and change tracking
- Created a FileModifiedDropdown to browse and manage modified files
- Enhanced ActionRunner to support file history persistence
- Updated Workbench and BaseChat components to support new diff view functionality
- Added support for inline and side-by-side diff view modes
This commit is contained in:
Toddyclipsgg
2025-02-16 23:10:15 -03:00
parent 744b6c2433
commit 382bf2c9a3
14 changed files with 1356 additions and 375 deletions

View File

@@ -1,7 +1,7 @@
import type { WebContainer } from '@webcontainer/api';
import { path } from '~/utils/path';
import { path as nodePath } from '~/utils/path';
import { atom, map, type MapStore } from 'nanostores';
import type { ActionAlert, BoltAction } from '~/types/actions';
import type { ActionAlert, BoltAction, FileHistory } from '~/types/actions';
import { createScopedLogger } from '~/utils/logger';
import { unreachable } from '~/utils/unreachable';
import type { ActionCallbackData } from './message-parser';
@@ -276,9 +276,9 @@ export class ActionRunner {
}
const webcontainer = await this.#webcontainer;
const relativePath = path.relative(webcontainer.workdir, action.filePath);
const relativePath = nodePath.relative(webcontainer.workdir, action.filePath);
let folder = path.dirname(relativePath);
let folder = nodePath.dirname(relativePath);
// remove trailing slashes
folder = folder.replace(/\/+$/g, '');
@@ -304,4 +304,31 @@ export class ActionRunner {
this.actions.setKey(id, { ...actions[id], ...newState });
}
async getFileHistory(filePath: string): Promise<FileHistory | null> {
try {
const webcontainer = await this.#webcontainer;
const historyPath = this.#getHistoryPath(filePath);
const content = await webcontainer.fs.readFile(historyPath, 'utf-8');
return JSON.parse(content);
} catch (error) {
return null;
}
}
async saveFileHistory(filePath: string, history: FileHistory) {
const webcontainer = await this.#webcontainer;
const historyPath = this.#getHistoryPath(filePath);
await this.#runFileAction({
type: 'file',
filePath: historyPath,
content: JSON.stringify(history),
changeSource: 'auto-save'
} as any);
}
#getHistoryPath(filePath: string) {
return nodePath.join('.history', filePath);
}
}