### Install and Run Development Server Source: https://github.com/xiaochong/markbun/blob/main/README.md Commands to install dependencies and start the development environment with or without Hot Module Replacement. ```bash # Install dependencies bun install # Development without HMR (uses bundled assets) bun run dev # Development with HMR (recommended) bun run dev:hmr ``` -------------------------------- ### Simplified Test Imports Source: https://github.com/xiaochong/markbun/blob/main/README.md Example of using the setup file to simplify import paths in test files. ```typescript // Import from setup.ts instead of long relative paths import { isTableCell, toggleBold } from '../setup'; ``` -------------------------------- ### Clone and setup repository Source: https://github.com/xiaochong/markbun/blob/main/CONTRIBUTING.md Commands to clone the repository and navigate into the project directory. ```bash git clone https://github.com/yourusername/markbun.git cd markbun ``` -------------------------------- ### Install dependencies Source: https://github.com/xiaochong/markbun/blob/main/CONTRIBUTING.md Command to install project dependencies using Bun. ```bash bun install ``` -------------------------------- ### Run Development Server Source: https://github.com/xiaochong/markbun/blob/main/AGENTS.md Start the development environment; logs will appear in the terminal. ```bash # Logs appear in terminal where you run `bun dev` bun dev ``` -------------------------------- ### Basic JavaScript Example Source: https://github.com/xiaochong/markbun/blob/main/website/index.html A simple demonstration of logging a string to the console. ```javascript const hello = "MarkBun World"; console.log(hello); ``` -------------------------------- ### Clone and Build MarkBun Source: https://github.com/xiaochong/markbun/blob/main/website/download.html Commands to clone the repository, install dependencies, and build the project for production. ```bash git clone https://github.com/xiaochong/markbun cd markbun # Install dependencies bun install # Build for production bun run build ``` -------------------------------- ### Install Turndown dependencies Source: https://github.com/xiaochong/markbun/blob/main/docs/plans/2026-04-04-003-feat-clipboard-operations-plan.md Command to add the Turndown library and its TypeScript definitions to the project. ```bash bun add turndown @types/turndown ``` -------------------------------- ### Commit message example Source: https://github.com/xiaochong/markbun/blob/main/CONTRIBUTING.md Example of a properly formatted conventional commit message. ```text feat: Add file explorer sidebar component - Implement folder tree navigation - Add file open/save handlers - Style with Tailwind CSS ``` -------------------------------- ### Add Milkdown Plugins Source: https://github.com/xiaochong/markbun/blob/main/README.md Install additional Milkdown plugins using the Bun package manager. ```bash bun add @milkdown/plugin-math ``` -------------------------------- ### Run development mode Source: https://github.com/xiaochong/markbun/blob/main/CONTRIBUTING.md Commands to start the development server with or without Hot Module Replacement (HMR). ```bash # With HMR (recommended for UI development) bun run dev:hmr # Without HMR bun run dev ``` -------------------------------- ### Update setupMenu in src/bun/menu.ts Source: https://github.com/xiaochong/markbun/blob/main/docs/windows-menu.md Modify the menu setup function to remove the Windows-specific platform check and enable native menus for all platforms. ```typescript // Current code (using frontend menu) export function setupMenu(state: ViewMenuState, tFn: (key: string) => string): void { const menu: ApplicationMenuItemConfig[] = [...]; currentMenuConfig = menu; // Windows uses frontend menu, skip native menu setup if (!isWindows) { ApplicationMenu.setApplicationMenu(menu); } } // Change to (using native menu) export function setupMenu(state: ViewMenuState, tFn: (key: string) => string): void { const menu: ApplicationMenuItemConfig[] = [...]; currentMenuConfig = menu; // All platforms use native menu ApplicationMenu.setApplicationMenu(menu); } ``` -------------------------------- ### Git Commit Message Examples Source: https://github.com/xiaochong/markbun/blob/main/AGENTS.md Standardized commit message prefixes for tracking project changes. ```text feat: Add file explorer sidebar fix: Fix auto-save not triggering on window blur docs: Update README with build instructions style: Fix toolbar button alignment refactor: Extract file operations to separate module test: Add tests for file saving ``` -------------------------------- ### Display Blob URL in Markdown Source: https://github.com/xiaochong/markbun/blob/main/AGENTS.md Example of the markdown format used within the editor to reference a Blob URL. ```typescript // Editor markdown uses blob URL const markdown = `![alt](blob:https://...)${"`"}; ``` -------------------------------- ### Detect fenced code block ranges Source: https://github.com/xiaochong/markbun/blob/main/docs/solutions/logic-errors/milkdown-html-block-code-fence-misidentification-and-chunk-splitting-2026-04-09.md Utility function to identify the start and end line indices of all fenced code blocks within a document. ```typescript function getFenceRanges(lines: string[]): Array<[number, number]> { const ranges: Array<[number, number]> = []; let inFence = false; let fenceChar = ''; let fenceLen = 0; let start = -1; for (let i = 0; i < lines.length; i++) { const line = lines[i]; if (!inFence) { const m = line.match(/^(\`{3,}|~{3,})/); if (m) { inFence = true; fenceChar = m[1][0]; fenceLen = m[1].length; start = i; } } else { const m = line.match(/^(\`+|~+)\s*$/); if (m && m[1][0] === fenceChar && m[1].length >= fenceLen) { ranges.push([start, i]); inFence = false; } } } return ranges; } ``` -------------------------------- ### Configure Electrobun Main Process Source: https://github.com/xiaochong/markbun/blob/main/AGENTS.md Sets up the native window and application menu for the desktop environment. ```typescript import { BrowserWindow, ApplicationMenu } from "electrobun/bun"; // Create window const win = new BrowserWindow({ title: "MarkBun", url: "views://main-ui/index.html", width: 1200, height: 800, }); // Set up menus ApplicationMenu.setApplicationMenu([ { label: "File", submenu: [ { label: "New", action: "file-new" }, { label: "Open", action: "file-open" }, { label: "Save", action: "file-save" }, ], }, ]); ``` -------------------------------- ### Build Project for Release Source: https://github.com/xiaochong/markbun/blob/main/README.md Commands to build the application for either canary or stable release channels. ```bash # Build for canary release bun run build:canary # Build for stable release bun run build:stable ``` -------------------------------- ### Run Development Scripts Source: https://github.com/xiaochong/markbun/blob/main/README.md Use these Bun commands to manage the development lifecycle, including building, testing, and linting. ```bash bun run dev # Start development with file watch bun run dev:hmr # Start development with HMR (recommended) bun run build:canary # Build canary release bun run build:stable # Build stable release bun run test # Run tests once bun run test:watch # Run tests in watch mode bun run test:coverage # Run tests with coverage bun run lint # Run typecheck and tests ``` -------------------------------- ### Configure MarkBun Settings Source: https://github.com/xiaochong/markbun/blob/main/README.md Settings are defined in the ~/.config/markbun/settings.json file to control general, editor, appearance, and backup behaviors. ```json { "__version": 1, "general": { "autoSave": true, "autoSaveInterval": 2000, "language": "en" }, "editor": { "fontSize": 15, "lineHeight": 1.65 }, "appearance": { "theme": "system", "sidebarWidth": 280 }, "backup": { "enabled": true, "maxVersions": 20, "retentionDays": 30, "recoveryInterval": 30000 } } ``` -------------------------------- ### Initialize Milkdown Editor Source: https://github.com/xiaochong/markbun/blob/main/AGENTS.md Configures the editor instance with commonmark, GFM, and history plugins. ```typescript import { Editor } from "@milkdown/kit/core"; import { commonmark } from "@milkdown/kit/preset/commonmark"; import { gfm } from "@milkdown/kit/preset/gfm"; import { history } from "@milkdown/kit/plugin/history"; Editor.make() .use(commonmark) .use(gfm) .use(history) .create(); ``` -------------------------------- ### Implement Electrobun Renderer Process Source: https://github.com/xiaochong/markbun/blob/main/AGENTS.md Handles menu actions and communicates with the main process via RPC. ```typescript import { Electroview } from "electrobun/view"; const electrobun = new Electroview({ rpc: null }); // Listen for menu actions electrobun.on("menu-action", (action) => { if (action === "file-save") { saveDocument(); } }); // Call main process electrobun.rpc("saveFile", { content: "..." }); ``` -------------------------------- ### Build and verify changes Source: https://github.com/xiaochong/markbun/blob/main/CONTRIBUTING.md Commands to build the project and check for TypeScript errors before submission. ```bash bun run build:canary ``` ```bash bun run tsc --noEmit ``` -------------------------------- ### Run Pre-commit Checks Source: https://github.com/xiaochong/markbun/blob/main/AGENTS.md Execute these commands before committing to ensure code quality and type safety. ```bash # Quick syntax and type check bun run typecheck # Full check (types + tests) bun run lint ``` -------------------------------- ### Configure MarkBun UI State Source: https://github.com/xiaochong/markbun/blob/main/README.md UI state preferences such as window dimensions and visibility toggles are stored in ~/.config/markbun/ui-state.json. ```json { "showTitleBar": false, "showToolBar": false, "showStatusBar": false, "showSidebar": false, "sidebarWidth": 280, "sidebarActiveTab": "files", "windowX": 200, "windowY": 200, "windowWidth": 1200, "windowHeight": 800 } ``` -------------------------------- ### Main App File Processing Logic Source: https://github.com/xiaochong/markbun/blob/main/docs/file-association.md Logic for consuming the pending file path during startup, runtime, and via RPC. ```typescript const filePath = await consumePendingFile(); if (filePath) pendingOpenFilePath = filePath; ``` ```typescript watch('/tmp/markbun', (eventType, filename) => { if (filename !== 'pending.txt') return; const filePath = await consumePendingFile(); if (filePath) openFileInFocusedWindow(filePath); }); ``` ```typescript // RPC: getPendingFile getPendingFile: async () => { if (!pendingOpenFilePath) return null; const filePath = pendingOpenFilePath; pendingOpenFilePath = null; return { path: filePath, content: ... }; } ``` -------------------------------- ### Enable Renderer DevTools Source: https://github.com/xiaochong/markbun/blob/main/AGENTS.md Configure BrowserWindow options to enable developer tools in the renderer process. ```javascript const win = new BrowserWindow({ // ... webPreferences: { devTools: true, }, }); ``` -------------------------------- ### Clipboard Implementation Sequence Source: https://github.com/xiaochong/markbun/blob/main/docs/plans/2026-04-04-003-feat-clipboard-operations-plan.md Visual representation of the dependency chain and verification points for clipboard feature development. ```text Unit 1 (frontmatter extract + clipboardBlobConverter) ↓ Unit 2 (App.tsx: menu action + keyboard handler) ← VERIFICATION GATE HERE ↓ confirm execCommand works Unit 3 (backend: readFromClipboard extension) ← can start parallel with Unit 2 ↓ Unit 4 (insertMarkdown + turndown + smart paste) ← depends on Unit 2 + Unit 3 ↓ Unit 5 (image paste) ← depends on Unit 4 paste framework ``` -------------------------------- ### Run Bun Test Commands Source: https://github.com/xiaochong/markbun/blob/main/README.md Standard commands for executing tests, watching for changes, and generating coverage reports. ```bash # Run all tests bun test # Run tests in watch mode (during development) bun run test:watch # Run tests with coverage report bun run test:coverage ``` -------------------------------- ### Initialize Dark Mode Source: https://github.com/xiaochong/markbun/blob/main/website/about.html Checks local storage for the theme preference and applies the dark class to the document element. ```javascript if(localStorage.getItem("mb-theme")==="dark")document.documentElement.classList.add("dark"); ``` -------------------------------- ### Implement recommended commands fallback Source: https://github.com/xiaochong/markbun/blob/main/docs/solutions/ui-bugs/command-palette-history-and-discovery-2026-04-01.md Provides a default list of commands to display when the user's command history is empty. ```typescript // src/mainview/hooks/useQuickOpen.ts if (commandHistory.length > 0) { // Show by recency order from history recentCommands = commandHistory .map(action => allCommandItems.find(c => c.type === 'command' && c.action === action)) .filter(...) .slice(0, MAX_PER_GROUP); } else { // No history yet: show recommended (most useful) commands const recommended = [ 'view-quick-open', 'edit-find', 'file-save', 'format-strong', 'format-emphasis', 'view-toggle-sidebar', 'view-toggle-theme', ]; recentCommands = recommended .map(action => allCommandItems.find(c => c.type === 'command' && c.action === action)) .filter(...) .slice(0, MAX_PER_GROUP); } ``` -------------------------------- ### Visualize Edit Mode Flow with Mermaid Source: https://github.com/xiaochong/markbun/blob/main/website/index.html A flowchart demonstrating the decision process between WYSIWYG and Source editing modes. ```mermaid graph TD A[Open File] --> B{Edit Mode?} B -->|WYSIWYG| C[Milkdown] B -->|Source| D[CodeMirror] ``` -------------------------------- ### Project structure overview Source: https://github.com/xiaochong/markbun/blob/main/CONTRIBUTING.md Visual representation of the project directory layout. ```text markbun/ ├── src/ │ ├── bun/ # Main process (Bun/Electrobun) │ │ └── index.ts # Entry point │ └── mainview/ # Renderer process (React) │ ├── App.tsx # Main component │ ├── main.tsx # React entry │ └── index.css # Styles ├── doc/ # Documentation ├── electrobun.config.ts # Electrobun configuration └── package.json ``` -------------------------------- ### Main Process Electrobun Imports Source: https://github.com/xiaochong/markbun/blob/main/docs/architecture.md Essential imports for accessing system-level APIs and window management in the main process. ```typescript import Electrobun, { BrowserWindow, BrowserView, Updater, Utils, ApplicationMenu, ContextMenu, Screen } from "electrobun/bun"; ``` -------------------------------- ### Generate Coverage Report Source: https://github.com/xiaochong/markbun/blob/main/README.md Command to execute tests and output a coverage report. ```bash bun test --coverage ``` -------------------------------- ### Perform Manual Verification Source: https://github.com/xiaochong/markbun/blob/main/AGENTS.md Use these commands to verify specific parts of the codebase or run tests in isolation. ```bash # Only check our code, ignore node_modules bun run typecheck 2>&1 | grep "src/" || echo "✓ No errors in src" # Just run tests bun test ``` -------------------------------- ### Git Workflow for Contributing Source: https://github.com/xiaochong/markbun/blob/main/README.md Standard sequence of commands for submitting a feature contribution to the repository. ```bash git checkout -b feature/amazing-feature ``` ```bash git commit -m 'Add amazing feature' ``` ```bash git push origin feature/amazing-feature ``` -------------------------------- ### Configure Electrobun build settings Source: https://github.com/xiaochong/markbun/blob/main/docs/architecture.md Defines the application metadata and platform-specific build configurations for the Electrobun framework. ```typescript // electrobun.config.ts import type { ElectrobunConfig } from "electrobun"; // CEF is only needed in dev mode for debugging const isBuild = process.argv.some(arg => arg === "build"); export default { app: { name: "MarkBun", identifier: "dev.markbun.app", version: "0.1.0", urlSchemes: ["markbun"], }, build: { copy: { "dist/index.html": "views/mainview/index.html", "dist/assets": "views/mainview/assets", "src/mainview/images": "views/mainview/images", }, watchIgnore: ["dist/**"], mac: { bundleCEF: !isBuild, }, linux: { bundleCEF: true, icon: "icon.iconset/icon_256x256.png", }, win: { bundleCEF: false, icon: "icon.iconset/icon_256x256.png", }, }, } satisfies ElectrobunConfig; ``` -------------------------------- ### Importing Electrobun Modules Source: https://github.com/xiaochong/markbun/blob/main/llms.txt Use these import patterns to access Electrobun functionality in main and browser contexts. ```typescript import { BrowserWindow } from "electrobun/bun" ``` ```typescript import { Electroview } from "electrobun/view" ``` -------------------------------- ### Pre-commit Verification Commands Source: https://github.com/xiaochong/markbun/blob/main/README.md Commands to run before committing code to ensure type safety and test passing. ```bash # Before committing bunx tsc --noEmit # Type check bun test # Run all tests ``` -------------------------------- ### Integrate Conversion into Milkdown Editor Source: https://github.com/xiaochong/markbun/blob/main/docs/solutions/best-practices/milkdown-frontmatter-display-workaround-2026-04-04.md Apply conversion logic at initialization, parsing, retrieval, and change notification points to maintain data integrity. ```typescript // useCrepeEditor.ts // 1. Initial display conversion const initialValueRef = useRef(convertFrontmatterToCodeBlock(defaultValue)); // 2. setMarkdown - convert before parsing const setMarkdown = useCallback((markdown: string, options?) => { const convertedMarkdown = convertFrontmatterToCodeBlock(markdown); // ... parse convertedMarkdown }, []); // 3. getMarkdown - convert before returning const getMarkdown = useCallback(() => { const content = crepeRef.current?.getMarkdown() ?? ''; return convertCodeBlockToFrontmatter(content); }, []); // 4. onChange - convert before notifying const changeListenerPlugin = $prose((ctx) => { return new Plugin({ view: () => ({ update: (view, prevState) => { if (!view.state.doc.eq(prevState.doc)) { const serializer = ctx.get(serializerCtx); const markdown = serializer(view.state.doc); // Convert before notifying parent onChangeRef.current?.(convertCodeBlockToFrontmatter(markdown)); } }, }), }); }); ``` -------------------------------- ### Define MarkBun technical stack configuration Source: https://github.com/xiaochong/markbun/blob/main/website/about.html Represents the core runtime, UI framework, and security configuration used in the MarkBun architecture. ```json { "core": { "runtime": "Bun (1.16.0+)", "language": "TypeScript", "shell": "Electrobun" }, "ui": { "framework": "React 18", "styling": "Tailwind CSS", "editor": "Milkdown" }, "security": { "isolation": true, "ipc_bridge": "Secure Context", "telemetry": null } } ``` -------------------------------- ### Agent-Browser Automation Commands Source: https://github.com/xiaochong/markbun/blob/main/AGENTS.md Use agent-browser for automation tasks. Always include the --cdp 9222 flag to connect to the remote debugging port. ```shell # Connect to the running Chrome with remote debugging on port 9222 agent-browser --cdp 9222 open http://localhost:5173 agent-browser --cdp 9222 snapshot ``` ```bash agent-browser --cdp 9222 snapshot -i # Get interactive elements snapshot agent-browser --cdp 9222 click @e1 # Click element agent-browser --cdp 9222 screenshot # Take screenshot ``` -------------------------------- ### Define UI State Interface Source: https://github.com/xiaochong/markbun/blob/main/docs/architecture.md Stores ephemeral window and layout configuration separate from persistent settings. ```typescript interface UIState { showTitleBar: boolean; showToolBar: boolean; showStatusBar: boolean; showSidebar: boolean; sourceMode: boolean; sidebarWidth: number; sidebarActiveTab: 'files' | 'outline' | 'search'; windowX: number; windowY: number; windowWidth: number; windowHeight: number; displayId?: number; } ``` -------------------------------- ### Run i18n validation and linting Source: https://github.com/xiaochong/markbun/blob/main/docs/plans/2026-04-06-002-refactor-consolidated-i18n-plan.md Commands used to verify the integrity of translation files and overall project health. ```bash bun run lint ``` ```bash bun run scripts/validate-i18n.ts ``` -------------------------------- ### Synchronous HTML preview rendering Source: https://github.com/xiaochong/markbun/blob/main/docs/solutions/integration-issues/milkdown-html-block-rendering-with-dompurify-2026-04-07.md Parses HTML content and mirrors 'src' attributes to 'data-src' to prevent DOMPurify from stripping them. Must return synchronously to prevent Milkdown from displaying a loading placeholder. ```typescript if (lang === 'html' && content.trim()) { const parser = new DOMParser(); const doc = parser.parseFromString(content.trim(), 'text/html'); // Preserve width/height against Milkdown CSS resets doc.querySelectorAll('img').forEach((img) => { const widthAttr = img.getAttribute('width'); const heightAttr = img.getAttribute('height'); if (widthAttr && !img.style.width) { img.style.width = /\D/.test(widthAttr) ? widthAttr : `${widthAttr}px`; } if (heightAttr && !img.style.height) { img.style.height = /\D/.test(heightAttr) ? heightAttr : `${heightAttr}px`; } }); // Mirror src to data-src so Milkdown's internal DOMPurify can't strip it permanently doc.querySelectorAll('img').forEach((img) => { const src = img.getAttribute('src'); if (src) { img.setAttribute('data-src', src); } }); // MUST return synchronously to avoid Milkdown's "Loading..." placeholder return doc.body.innerHTML; } ``` -------------------------------- ### Restore HTML preview images via MutationObserver Source: https://github.com/xiaochong/markbun/blob/main/docs/solutions/integration-issues/milkdown-html-block-rendering-with-dompurify-2026-04-07.md Uses a MutationObserver to detect HTML blocks and restore 'src' attributes from 'data-src', while resolving local file paths to blob URLs. ```typescript const restoreHtmlPreviewImages = () => { const htmlBlocks = container.querySelectorAll('.milkdown-code-block[data-lang="html"]'); htmlBlocks.forEach((block) => { const imgs = block.querySelectorAll('.preview img[data-src]'); imgs.forEach((img) => { if (img.hasAttribute('data-resolved')) return; const dataSrc = img.getAttribute('data-src'); if (!dataSrc) return; // Recover src if DOMPurify stripped it if (!img.getAttribute('src')) { img.setAttribute('src', dataSrc); } // Resolve local file paths to blob URLs (WebView cannot access file://) if (!/^(https?:|data:|blob:)/i.test(dataSrc)) { const resolvedPath = workspaceManager.resolvePath(dataSrc); loadLocalImage(resolvedPath, dataSrc) .then((blobUrl) => { if (blobUrl) { img.setAttribute('src', blobUrl); img.setAttribute('data-src', blobUrl); } }) .catch((e) => { console.error('[HTML Preview] Failed to load local image:', dataSrc, e); }); } img.setAttribute('data-resolved', 'true'); }); }); }; const observer = new MutationObserver(() => { updateLatexCodeBlocks(); restoreHtmlPreviewImages(); }); observer.observe(container, { childList: true, subtree: true, characterData: true, }); ``` -------------------------------- ### Apply Tailwind Styling Source: https://github.com/xiaochong/markbun/blob/main/AGENTS.md Use semantic tokens and the cn() utility instead of raw colors or manual ternaries. ```tsx // ❌ Don't: Raw colors, manual ternaries
// ✅ Do: Semantic tokens, cn() utility import { cn } from "@/lib/utils";
``` -------------------------------- ### Standalone Viewer Mermaid Configuration Source: https://github.com/xiaochong/markbun/blob/main/docs/solutions/ui-bugs/mermaid-flowchart-blank-nodes-and-svg-collapse-webkit-2026-04-08.md Uses default Mermaid settings for standalone viewers to ensure maximum compatibility. ```typescript mermaid.initialize({ startOnLoad: false, theme: isDark ? 'dark' : 'default', suppressErrorRendering: true, // Use Mermaid defaults (htmlLabels: true) for maximum compatibility }); const { svg } = await mermaid.render(id, mermaidSource); ``` -------------------------------- ### Style Frontmatter Code Blocks with CSS Source: https://github.com/xiaochong/markbun/blob/main/docs/solutions/best-practices/milkdown-frontmatter-display-workaround-2026-04-04.md Apply Typora-like styling to the first YAML code block to visually distinguish frontmatter from document content. ```css /* Typora-like gray background for frontmatter */ .milkdown-crepe-container .ProseMirror pre[data-language="yaml"]:first-child { background: #f5f5f5 !important; border-radius: 4px; padding: 12px 16px; margin: 0 0 16px 0; font-family: 'SF Mono', SFMono-Regular, ui-monospace, Menlo, Monaco, 'Courier New', monospace !important; font-size: 0.85em; line-height: 1.5; color: #666; border: none; } .dark .milkdown-crepe-container .ProseMirror pre[data-language="yaml"]:first-child { background: #2d2d2d !important; color: #999; } ``` -------------------------------- ### AppleScript Droplet for File Association Source: https://github.com/xiaochong/markbun/blob/main/docs/file-association.md This script acts as the handler for file-open events, writing the target file path to a temporary file and launching the main application. ```applescript on open theFiles set filePath to POSIX path of (item 1 of theFiles) do shell script "echo " & quoted form of filePath & " > /tmp/markbun/pending.txt" set appPath to POSIX path of (path to me) & "Contents/MacOS/MarkBun-canary.app" do shell script "open " & quoted form of appPath end open ``` -------------------------------- ### URL Scheme Listener Source: https://github.com/xiaochong/markbun/blob/main/docs/file-association.md Handles file opening requests via URL scheme when the application is already running. ```typescript Electrobun.events.on('open-url', (event) => { const url = new URL(event.data.url); if (url.hostname === 'open') { const filePath = decodeURIComponent(url.searchParams.get('path') ?? ''); if (filePath) openFileInFocusedWindow(filePath); } }); ``` -------------------------------- ### Implement Frontmatter Conversion Functions Source: https://github.com/xiaochong/markbun/blob/main/docs/solutions/best-practices/milkdown-frontmatter-display-workaround-2026-04-04.md Use these functions to transform YAML frontmatter into code blocks for the editor and back to frontmatter for file persistence. ```typescript // Display: convert --- to ```yaml function convertFrontmatterToCodeBlock(markdown: string): string { const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*(?:\n|$)/; const match = markdown.match(frontmatterRegex); if (match) { const frontmatter = match[1]; const content = markdown.slice(match[0].length); return "```yaml\n" + frontmatter + "\n```\n" + content; } return markdown; } // Save: convert ```yaml back to --- function convertCodeBlockToFrontmatter(markdown: string): string { const codeBlockRegex = /^```yaml\s*\n([\s\S]*?)\n```\s*(?:\n|$)/; const match = markdown.match(codeBlockRegex); if (match) { const frontmatter = match[1]; const content = markdown.slice(match[0].length); const normalizedFrontmatter = frontmatter.endsWith('\n') ? frontmatter : frontmatter + '\n'; return "---\n" + normalizedFrontmatter + "---\n\n" + content; } return markdown; } ``` -------------------------------- ### Implement AI Chat Panel Width Clamping Source: https://github.com/xiaochong/markbun/blob/main/docs/solutions/ui-bugs/ai-chat-panel-flex-shrink-layout-fix-2026-04-04.md Adds a NaN guard for width calculations and applies min-w-0 to the panel container. ```tsx const safeWidth = Number.isFinite(width) ? width : MIN_WIDTH; const clampedWidth = Math.max(MIN_WIDTH, Math.min(MAX_WIDTH, safeWidth));
``` -------------------------------- ### Update Main Editor Container Layout Source: https://github.com/xiaochong/markbun/blob/main/docs/solutions/ui-bugs/ai-chat-panel-flex-shrink-layout-fix-2026-04-04.md Replaces conditional minWidth with min-w-0 to allow the main editor container to shrink. ```tsx // Before
// After
``` -------------------------------- ### Conventional commit types Source: https://github.com/xiaochong/markbun/blob/main/CONTRIBUTING.md List of standard commit message prefixes used in the project. ```text feat: Add new feature fix: Fix a bug docs: Update documentation style: Code style changes refactor: Code refactoring test: Add or update tests chore: Build process or auxiliary tool changes ``` -------------------------------- ### Switch from atomicWrite to plain writeFile Source: https://github.com/xiaochong/markbun/blob/main/docs/solutions/logic-errors/session-persistence-race-condition-react-effect-2026-04-02.md Replaces atomic write operations with standard file writing to avoid ENOENT errors, as session state is considered disposable. ```typescript // Before: atomicWrite (.tmp + rename) — caused ENOENT // After: plain writeFile — session state is disposable, doesn't need crash safety export async function saveSessionState(state: SessionState) { await ensureConfigDir(); await writeFile(SESSION_STATE_PATH, JSON.stringify(state, null, 2), 'utf-8'); return { success: true }; } ``` -------------------------------- ### Extend readFromClipboard type definitions Source: https://github.com/xiaochong/markbun/blob/main/docs/plans/2026-04-04-003-feat-clipboard-operations-plan.md Update the RPC interface to include optional parameters for HTML and image data, and expand the response object to include these fields. ```typescript readFromClipboard: { params: { html?: boolean; image?: boolean }; response: { success: boolean; text?: string; html?: string; imageData?: string; // base64 encoded imageFormat?: string; // 'png' | 'tiff' error?: string; } }; ``` -------------------------------- ### Register RPC Tool Handler Source: https://github.com/xiaochong/markbun/blob/main/docs/solutions/integration-issues/ai-tool-call-cascading-failures-rpc-stream-lifecycle-2026-04-04.md Implement the handler in the webview to execute tools registered on the global AI object. ```typescript requests: { executeAITool: ({ tool, args }) => { const aiTools = (window as any).__markbunAI; if (!aiTools?.[tool]) return { success: false, error: `Tool not found: ${tool}` }; const result = aiTools[tool](args ? JSON.parse(args) : undefined); return { success: true, result: typeof result === 'string' ? result : JSON.stringify(result) }; }, }, ``` -------------------------------- ### Define CommandEntry Interface Source: https://github.com/xiaochong/markbun/blob/main/docs/plans/2026-04-06-001-refactor-unified-command-manifest-plan.md Schema extension for command entries including menu path, execution context, and platform-specific overrides. ```typescript // Directional sketch — field names approximate interface CommandEntry { action: string; // existing i18nKey: string; // existing accelerator?: string; // existing category: CommandCategory;// existing // New fields: menuPath?: string[]; // e.g., ['Format', 'Strong'] for menu tree placement executionContext: 'main' | 'renderer' | 'cross-process'; when?: (ctx: CommandContext) => boolean; toggled?: string; // context key name for checked state platformOverrides?: { macOS?: Partial>; windows?: Partial>; }; } ``` -------------------------------- ### Integrate Frontmatter Conversion in Clipboard Converter Source: https://github.com/xiaochong/markbun/blob/main/docs/plans/2026-04-04-003-feat-clipboard-operations-plan.md Apply frontmatter conversion to the serialized markdown before returning it for clipboard operations. ```typescript let markdown = serializer(doc); markdown = prepareForClipboard(markdown); markdown = convertCodeBlockToFrontmatter(markdown); return markdown; ``` -------------------------------- ### Source Editor Architecture Source: https://github.com/xiaochong/markbun/blob/main/docs/architecture.md Component structure for the CodeMirror 6 source editor implementation. ```text SourceEditor (React Component) ├── EditorView + EditorState ├── @codemirror/lang-markdown ├── @codemirror/theme-one-dark (dark mode) ├── Extensions: lineNumbers, history, search, bracketMatching └── Custom syntax highlighting for light/dark themes ``` -------------------------------- ### Inline Preview Mermaid Configuration Source: https://github.com/xiaochong/markbun/blob/main/docs/solutions/ui-bugs/mermaid-flowchart-blank-nodes-and-svg-collapse-webkit-2026-04-08.md Configures Mermaid for inline previews by setting htmlLabels to false to avoid WebKit-specific rendering issues. ```typescript mermaid.initialize({ startOnLoad: false, theme: darkModeRef.current ? 'dark' : 'default', suppressErrorRendering: true, htmlLabels: false, }); mermaid.render(id, code) // pass original code, no
replacement ``` -------------------------------- ### Renderer Process Electrobun Imports Source: https://github.com/xiaochong/markbun/blob/main/docs/architecture.md Required import for the renderer process to interface with the Electrobun view layer. ```typescript import { Electroview } from "electrobun/view"; ``` -------------------------------- ### TypeScript Import Ordering Source: https://github.com/xiaochong/markbun/blob/main/AGENTS.md Follow this order for imports: external dependencies, internal absolute imports using the @/ alias, and relative imports. ```typescript // 1. External dependencies import React from "react"; import { Editor } from "@milkdown/kit/core"; // 2. Internal absolute imports (@/ alias) import { Button } from "@/components/ui/button"; import { useFiles } from "@/hooks/useFiles"; // 3. Relative imports import { MilkdownEditor } from "./MilkdownEditor"; ``` -------------------------------- ### Register Command Handlers Source: https://github.com/xiaochong/markbun/blob/main/docs/plans/2026-04-06-001-refactor-unified-command-manifest-plan.md Pattern for registering command handlers at the module or component level, supporting both simple callbacks and complex multi-process handlers with conditional execution. ```typescript // Directional sketch — registration at module top level or App.tsx top level registerHandler('format-strong', (ctx) => { editorRef.current?.toggleBold(); }); registerHandler('file-save', { mainHandler: (fw) => { fw.state.filePath = ... }, rendererAction: (ctx) => { handleSave() }, }, { when: (ctx) => ctx.get('hasOpenFile') }); ``` -------------------------------- ### Implement Cmd+X (Cut) for Input Fields Source: https://github.com/xiaochong/markbun/blob/main/docs/solutions/ui-bugs/webview-clipboard-shortcuts-input-fields-2026-04-01.md Intercepts cut commands to remove selected text and write it to the clipboard via the Electrobun IPC API. ```typescript case 'x': { const xTarget = e.target as HTMLElement; if (xTarget.tagName === 'INPUT' || xTarget.tagName === 'TEXTAREA') { e.preventDefault(); const el = xTarget as HTMLInputElement | HTMLTextAreaElement; const start = el.selectionStart ?? 0; const end = el.selectionEnd ?? start; if (start === end) break; const selectedText = el.value.substring(start, end); el.setRangeText(''); // Remove selection synchronously void electrobun.writeToClipboard(selectedText); } else { e.preventDefault(); void clipboard.cut(); } break; } ``` -------------------------------- ### CSS Styles for UI Components Source: https://github.com/xiaochong/markbun/blob/main/website/download.html Custom styles for Material Symbols, gradients, and active navigation links. ```css .material-symbols-outlined { font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24; } .btn-gradient { background: linear-gradient(135deg, rgb(var(--c-primary-dim)) 0%, rgb(var(--c-secondary-dim)) 100%); } .nav-link-active { color: rgb(var(--c-on-surface)); font-weight: 600; border-bottom: 2px solid rgb(var(--c-primary)); padding-bottom: 0.25rem; } ``` -------------------------------- ### Milkdown Integration Architecture Source: https://github.com/xiaochong/markbun/blob/main/docs/architecture.md Structure of the MilkdownEditor component, including custom hooks, Crepe configuration, and plugin dependencies. ```text MilkdownEditor (React Component, forwardRef + memo) ├── useCrepeEditor (custom hook) │ ├── Crepe (from @milkdown/crepe) │ │ ├── Feature config: │ │ │ ├── BlockEdit: disabled │ │ │ ├── LinkTooltip: enabled │ │ │ ├── Toolbar: disabled (custom Toolbar used) │ │ │ ├── ImageBlock: enabled (with custom onUpload, proxyDomURL) │ │ │ └── CodeMirror: enabled (with Mermaid diagram rendering) │ │ │ │ │ └── Plugins: │ │ ├── clipboard (@milkdown/plugin-clipboard) │ │ ├── history (@milkdown/plugin-history) │ │ ├── gfm (@milkdown/preset-gfm) │ │ ├── clipboardBlobConverter (custom — blob URL handling) │ │ ├── inlineMarksPlugin (custom — highlight, superscript, subscript) │ │ ├── breaksPlugin (custom — soft line breaks) │ │ └── inlineMarksParsersPlugin (custom — remarkHighlight, remarkSuperSub) │ │ │ └── Content loading: │ ├── Direct parse (< 500 lines) │ └── Chunked loading (>= 500 lines, code-block-aware splitting) │ ├── useThemeLoader (custom hook) │ ├── @milkdown/crepe/theme/frame.css (light mode) │ └── @milkdown/crepe/theme/frame-dark.css (dark mode) │ ├── useContextMenu (custom hook) │ └── Style imports: ├── @milkdown/crepe/theme/common/style.css └── @milkdown/crepe/theme/common/link-tooltip.css ``` -------------------------------- ### Drag-Drop Image Insertion Flow Source: https://github.com/xiaochong/markbun/blob/main/AGENTS.md Correct implementation flow for handling dropped images, including duplicate detection and conversion to Blob URLs. ```typescript // Correct flow const dataUrl = await readFileAsDataURL(file); const base64 = extractBase64FromDataUrl(dataUrl); const saveResult = await electrobun.saveDroppedImage(fileName, base64, workspaceRoot); // Bun process will: // - Search recursively (max 3 levels) for existing file // - Compare: name + size + head(10bytes) + tail(10bytes) // - Return existing path if found, or save to assets/ const blobUrl = await loadLocalImage(saveResult.absolutePath); // ✅ Use blob URL editor.insertImage(blobUrl, alt); // ✅ Not base64! ``` -------------------------------- ### Configure ToolCallCard Shrink Behavior Source: https://github.com/xiaochong/markbun/blob/main/docs/solutions/ui-bugs/ai-chat-panel-flex-shrink-layout-fix-2026-04-04.md Ensures card elements and truncating spans can shrink without breaking layout bounds. ```tsx // Root card fills wrapper width
// Header button clips overflow