Advertisement

← vibesdk

src/routes/chat/utils/file-state-helpers.ts

3.9 KB Download file
import type { PhaseTimelineItem } from '../hooks/use-chat';
import type { FileType } from '@/api-types';
import { getFileType } from '@/utils/string';

/**
 * Update a specific file in the files array
 */
export function updateFileInArray(
    files: FileType[],
    filePath: string,
    updates: Partial<FileType>
): FileType[] {
    const existingFileIndex = files.findIndex(f => f.filePath === filePath);
    
    if (existingFileIndex >= 0) {
        return files.map((file, index) => 
            index === existingFileIndex 
                ? { ...file, ...updates }
                : file
        );
    }
    
    // Add new file if it doesn't exist
    return [...files, {
        filePath,
        fileContents: '',
        isGenerating: false,
        needsFixing: false,
        hasErrors: false,
        language: getFileType(filePath),
        ...updates
    }];
}

/**
 * Remove a file from the files array (e.g. when the agent deletes it)
 */
export function removeFileFromArray(
    files: FileType[],
    filePath: string
): FileType[] {
    return files.filter(f => f.filePath !== filePath);
}

/**
 * Update file status in phase timeline
 */
export function updatePhaseFileStatus(
    phaseTimeline: PhaseTimelineItem[],
    filePath: string,
    status: 'generating' | 'completed' | 'error' | 'validating',
    fileContents?: string
): PhaseTimelineItem[] {
    const updatedTimeline = [...phaseTimeline];
    
    // Find the most recent phase containing this file (iterate backwards)
    for (let i = updatedTimeline.length - 1; i >= 0; i--) {
        const phase = updatedTimeline[i];
        if (phase.status === 'completed' && status !== 'completed') {
            continue; // Skip completed phases unless we're marking as completed
        }
        
        const fileInPhase = phase.files.find(f => f.path === filePath);
        if (fileInPhase) {
            fileInPhase.status = status;
            if (fileContents !== undefined) {
                fileInPhase.contents = fileContents;
            }
            console.log(`File ${status} in phase ${phase.name}: ${filePath}`);
            break;
        }
    }
    
    return updatedTimeline;
}

/**
 * Add or update a file with generating state
 */
export function setFileGenerating(
    files: FileType[],
    filePath: string,
    explanation?: string
): FileType[] {
    return updateFileInArray(files, filePath, {
        filePath,
        fileContents: '',
        explanation: explanation || '',
        isGenerating: true,
        needsFixing: false,
        hasErrors: false,
        language: getFileType(filePath),
    });
}

/**
 * Update file content chunk
 */
export function appendFileChunk(
    files: FileType[],
    filePath: string,
    chunk: string
): FileType[] {
    const existingFile = files.find(f => f.filePath === filePath);
    
    if (existingFile) {
        return files.map(file => 
            file.filePath === filePath
                ? { ...file, fileContents: file.fileContents + chunk }
                : file
        );
    }
    
    // Create new file with chunk
    return [...files, {
        filePath,
        fileContents: chunk,
        explanation: '',
        isGenerating: true,
        needsFixing: false,
        hasErrors: false,
        language: getFileType(filePath),
    }];
}

/**
 * Mark file as completed
 */
export function setFileCompleted(
    files: FileType[],
    filePath: string,
    fileContents: string
): FileType[] {
    return updateFileInArray(files, filePath, {
        fileContents,
        isGenerating: false,
        needsFixing: false,
        hasErrors: false,
    });
}

/**
 * Mark all files as completed
 */
export function setAllFilesCompleted(files: FileType[]): FileType[] {
    return files.map(file => ({
        ...file,
        isGenerating: false,
        needsFixing: false,
        hasErrors: false,
    }));
}