The filesInDraft structure is the heart of Holocron's real-time editing system. It maintains all file modifications in memory during an editing session, enabling instant preview updates without database writes.
Data Structure
FileUpdate Type
type FileUpdate = { githubPath: string // Full path to the file (e.g., "docs/getting-started.md") content: string | null // File content (null indicates deletion) addedLines?: number // Number of lines added (for tracking changes) deletedLines?: number // Number of lines removed (for tracking changes) }
filesInDraft Record
type FilesInDraft = Record<string, FileUpdate> // Example: { "docs/getting-started.md": { githubPath: "docs/getting-started.md", content: "# Getting Started\n\nWelcome to the docs...", addedLines: 5, deletedLines: 2 }, "docs/api.mdx": { githubPath: "docs/api.mdx", content: null, // File marked for deletion deletedLines: 150 } }
State Management
Website State (Main App)
Located in website/src/lib/state.tsx:
export type State = { currentSlug: string filesInDraft: Record<string, FileUpdate> lastPushedFiles: Record<string, FileUpdate> // Track what was last synced }
Docs State (Preview Site)
Located in docs-website/src/lib/docs-state.tsx:
export type DocsState = { filesInDraft: FilesInDraft deletedPages: Array<{ slug: string }> previewMode?: 'preview' | 'editor' // ... other fields }
File Operations
Creating/Updating Files
When a file is created or modified:
Content is stored with full text
Line count changes are calculated
addedLinesanddeletedLinestrack the diff
Deleting Files
When a file is deleted:
contentis set tonulldeletedLinescontains the original line countFile remains in
filesInDraftto track the deletion
Moving/Renaming Files
When a file is moved:
New path entry is created with content
Old path entry is marked as deleted (
content: null)Both operations are tracked in
filesInDraft
Data Flow
1. Tool Modifications
AI tools (like strReplaceEditor) modify filesInDraft:
// In edit-tool implementation filesInDraft[path] = { githubPath: path, content: newContent, addedLines: calculateAddedLines(oldContent, newContent), deletedLines: calculateDeletedLines(oldContent, newContent) }
2. FileSystemEmulator Access
FileSystemEmulator reads from filesInDraft first:
async read(path: string): Promise<string | null> { // Check draft first if (this.filesInDraft[path]) { return this.filesInDraft[path].content } // Fall back to database return this.getOriginalContent(path) }
3. Preview Updates
Docs website receives updates via postMessage:
// When editor changes in docs-website const message: IframeRpcMessage = { id: generateChatId(), state: { filesInDraft: { [githubPath]: updatedFile } } } window.parent.postMessage(message, '*')
Change Detection
Checking for Unpushed Changes
export function doFilesInDraftNeedPush( currentFilesInDraft: Record<string, FileUpdate>, lastPushedFiles: Record<string, FileUpdate> ) { return Object.keys(currentFilesInDraft).some(key => { const current = currentFilesInDraft[key] const initial = lastPushedFiles[key] const currentContent = (current?.content ?? '').trim() const initialContent = (initial?.content ?? '').trim() return currentContent !== initialContent }) }
Special Files Handling
Configuration Files
holocron.jsonc: Website configurationstyles.css: Custom CSS stylesmeta.json: Page metadata
These files are handled specially in filesInDraft:
Validated before storage
Parsed/serialized with proper formatting
May include comment preservation (for JSONC)
Memory Management
Limitations
All changes stay in memory until chat completes
Large files can consume significant memory
No incremental saves during long sessions
Optimizations
Line count tracking avoids full diff calculations
Null content for deletions saves memory
Batch updates reduce state changes
Persistence Strategy
When filesInDraft Persists
Chat Completion: Saved to database with chat
Manual Save: User triggers sync
GitHub Push: Converted to Git commits
When filesInDraft Clears
New Chat: Fresh session starts
Discard Changes: User cancels edits
Successful Push: After GitHub sync
Best Practices
Always Check Draft First: Tools should read from
filesInDraftbefore databaseTrack All Changes: Include line counts for better diff visualization
Validate Content: Check syntax before storing in draft
Batch Updates: Group related file changes to reduce renders
Clean Up Nulls: Remove deleted file entries after persistence