1. Source editor blank: Added ensureEditor() method with try-catch that
lazily creates the CodeMirror editor when setEditorContent is called
if the initial DOMContentLoaded creation failed or was skipped.
Replaced inline createEditor calls in createTabElements and
DOMContentLoaded with ensureEditor().
2. Export via pandoc failing: runPandocCmd parsed the full path
/bin/linux/pandoc as the command, then prepended it to args because
parsed.command !== 'pandoc'. This caused pandoc to receive its own
binary path as the first input file. Fix: use path.basename() to
check if the command ends with 'pandoc' (or 'pandoc.exe').
Amit Haridas
The main window uses nodeIntegration without preload, so window.electronAPI
was undefined. This caused the DOMContentLoaded handler to crash at:
await window.electronAPI.getAppVersion()
which prevented the CodeMirror editor from being created (blank source
window) and stopped renderer-ready from being sent (broken menu/options).
Fixes:
1. Add window.electronAPI shim at top of renderer.js wrapping ipcRenderer.
2. Update CSP meta tag to allow KaTeX CDN (style-src, script-src, font-src).
Amit Haridas
ModalManager.js is loaded via <script> tag in index.html, which
declares class ModalManager in the global script scope. renderer.js
was then doing 'let ModalManager;' which caused:
SyntaxError: Identifier 'ModalManager' has already been declared
This prevented renderer.js from executing at all, breaking tabs,
editor, file open, and preview rendering.
Fix: conditionally require ModalManager only if undefined, without
re-declaring. In sloppy mode this safely assigns to the existing global.
Amit Haridas
The welcome tab setup awaited getAppVersion() inside DOMContentLoaded.
While yielding, the renderer-ready timeout fired, file-opened was processed,
and openFile rendered the markdown. When the welcome setup resumed, it
overwrote tab.content and preview.innerHTML with the welcome screen,
leaving the preview blank.
Fix: only show the welcome screen if the tab is still empty (no filePath
and no content) when the async setup resumes.
Amit Haridas
This will help identify whether the issue is:
1. marked.parse returning a Promise instead of string
2. DOMPurify.sanitize failing
3. The preview element not existing
4. Libraries not being loaded
Amit Haridas
- Add missing updateUI() call at end of openFile() to set .active class
on tab content. Without this, the CSS rule .tab-content:not(.active)
{ display: none } kept newly opened files invisible.
- Add diagnostic logging to file-opened IPC handler and openFile()
to trace future file loading issues.
- Add diagnostic logging to openFileFromPath() in main process.
Amit Haridas
window.ModalManager was set unconditionally, causing "Identifier
'ModalManager' has already been declared" when script tag in HTML
also loaded ModalManager before renderer.js required it.
Now checks !window.ModalManager before setting.
Amit Haridas
require('dompurify') returns a factory function, not a sanitizer
instance. Calling .sanitize() on the factory threw a TypeError,
which was caught by the preview renderer's try-catch and displayed
a generic "Error rendering preview" message. Fix by invoking the
factory with the renderer's window object.
Amit Haridas
Restrict Electron permission requests to only clipboard operations.
Deny: camera, microphone, geolocation, notifications, and all other
permissions by default.
Implements setPermissionRequestHandler on web-contents-created event
to enforce security policy early in the app lifecycle.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add get-app-version IPC handler in main.js (returns app.getVersion())
- Expose electronAPI.getAppVersion() in preload.js
- index.html: replace hardcoded v4.2.0 span with dynamic population
from getAppVersion() in DOMContentLoaded
- welcome.js: accept appVersion param instead of hardcoded 4.1.0
- renderer.js: pass live version to createWelcomeContent()
- main.js about screen: use app.getVersion() instead of hardcoded 4.1.0
- Update stale @version 4.1.0 JSDoc comments to 4.3.0
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
electron-builder detects git tags in CI and tries to auto-publish to
GitHub, failing with 'GH_TOKEN not set'. We handle the release
separately via softprops/action-gh-release, so suppress auto-publish.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add build:linux-ci script (deb + AppImage, no snap — snapcraft not
available on ubuntu-latest runners without extra setup)
- Switch release.yml linux build to npm run build:linux-ci
- release job: if: always() so Windows artifacts still get released
even if linux build fails
- Download artifact steps: continue-on-error so missing platform
doesn't block GitHub Release creation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove rpm from linux build targets (rpmbuild not available locally)
CI can add it back with apt-get if needed, but pandoc/ffmpeg are now
bundled so the rpm depends were incorrect anyway
- Remove rpmbuild apt install step from release.yml (not needed)
- Remove pandoc/ffmpeg from deb depends — they are now bundled binaries
- Keep imagemagick and libreoffice-common in deb depends (not bundled)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove package-lock.json from .gitignore so npm ci works in CI
- Refactor main.js: delegate PDF ops to src/main/PDFOperations.js,
git ops to src/main/GitOperations.js
- getPandocPath(): use bundled binary from resources/bin/ when packaged,
fall back to dev bin/ or system pandoc in development
- getFFmpegPath(): use ffmpeg-static (asarUnpack) when packaged
- Install ffmpeg-static (v5.3.0, bundled 76MB binary)
- Add scripts/download-tools.js to fetch pandoc binary at build time
(idempotent, runs on CI before electron-builder)
- electron-builder: add asarUnpack for ffmpeg-static, extraFiles for
pandoc binary per platform (linux + win32)
- release.yml: switch build-windows to windows-latest runner with native
NSIS support; add cert decode step; add download-tools step for both
linux and windows jobs
- Fix lint error: hoist outlinePanelContainer to module scope so
TabManager methods can reference it without no-undef errors
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add plugin system bootstrap in renderer.js after sidebar/commands init
- Wire status bar DOM insertion, editor API, and IPC adapters
- Add plugin-settings:get/set IPC channels to preload allowlist
- Add IPC handlers in main process using existing settings store
- Fix eqeqeq warning in EventBus.hasHandler
Amit Haridas
- PluginContext: scoped API with crash-safe command wrappers
- PluginRegistry: lifecycle management with graceful init failure
- SettingsStore: plugin-scoped key/value via IPC backend
- Export hooks: pre/post hooks on registry for cross-plugin integration
Amit Haridas
9 tasks across 8 chunks, strict TDD:
- EventBus with crash-safe handlers
- PluginAPI base class
- PluginLoader with manifest validation
- PluginContext with scoped API
- PluginRegistry with lifecycle management
- SettingsStore for plugin-scoped settings
- Export hooks integration
- Sample plugin + renderer wiring
Amit Haridas
- GGUF GPU: child process isolation with crash detection/restart
- Event bus: versioned payload schemas for all events
- Plugin sandbox: 5s handler timeout, IPC delegation for heavy ops
- AI streaming: full lifecycle with requestId, cancel, heartbeat, orphan cleanup
- Comment anchors: context-based positioning (not byte offsets) with re-anchor on file change
- Cross-plugin: capability discovery, 30s timeout, graceful degradation
- Bundle size: GPU variants as lazy downloads, not bundled by default
- Command uniqueness: registry rejects duplicates at load time
Amit Haridas
- Remove signAndEditExecutable:false so code signing works properly
- Add legalTrademarks and copyright metadata to build config
- Add publisherName via build.copyright (embedded in PE resources)
- Create scripts/create-selfsigned-cert.ps1 for local dev signing
- Update release.yml: build on windows-latest runner (not Wine),
auto-sign when CSC_LINK_BASE64/CSC_KEY_PASSWORD secrets present,
fall back to unsigned otherwise
- Add lint step to ci.yml (Phase 4.3 plan gap)
- Add .vscode/launch.json debug configs (Phase 4.3 plan gap)
- Fix .gitignore: exclude *.pfx/*.p12 cert files, track launch.json,
fix concatenated agents.md/coverage/ lines
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Zen mode hides all chrome and centers the editor with typewriter
scrolling, line dimming, and a floating word count HUD.
Toggle with F11, exit with Escape.
Amit Haridas
- Bump version to 4.1.0 in package.json and index.html
- Add build:local script for combined Linux + Windows local builds
- Add CI workflow: runs tests on push/PR to master
- Add Release workflow: tag-triggered (v*), parallel Linux + Windows
builds, publishes all packages to GitHub Releases
Amit Haridas
- Set backdrop z-index:0 and content z-index:1 to fix backdrop covering
modal content within the stacking context
- Force reflow between removing hidden and adding open class so CSS
opacity transition fires correctly
- Add transitionend listener + setTimeout fallback to restore hidden
class after close animation completes
- Override flex:1 on modal footer buttons to prevent full-width stretch
- Add min-width to modal size variants for consistent sizing
- Add 23 tests covering open/close lifecycle, keyboard, and destroy
Amit Haridas
Convert 10 dialogs from old classes (.export-dialog, .batch-dialog, .find-dialog)
to the new unified .modal structure with proper accessibility attributes.
Changes:
- find-dialog: small modal with find/replace controls
- export-dialog: large modal with export options
- print-preview-overlay: full-size modal for print preview
- table-generator-dialog: default modal for table creation
- ascii-art-dialog: large modal for ASCII art generation
- universal-converter-dialog: large modal for file conversion
- batch-dialog: large modal for batch processing
- pdf-editor-dialog: full-size modal for PDF editing
- header-footer-dialog: default modal for header/footer config
- field-picker-dialog: small modal for field selection
All dialogs now include:
- role="dialog" and aria-modal="true" for accessibility
- aria-labelledby pointing to title element
- .modal-backdrop with data-close attribute
- .modal-content with appropriate size class
- .modal-header with title and close button
- .modal-body for content
- .modal-footer with action buttons
Amit Haridas
- Create adapters/types.js with comprehensive type definitions
- Create adapters/electron/fs.js for file system operations
- Prepare structure for future migration to Tauri/Flutter
This abstraction layer makes future platform migration easier
and enables better testing with mock adapters.
Amit Haridas
- Add previewDebounceTimers map to track debounce timers per tab
- Add updatePreview(tabId, immediate) with optional immediate flag
- Debounce preview updates during typing (300ms delay)
- Use immediate=true for tab switches and file loads
- Refactor _renderPreview as internal method
This significantly improves editor responsiveness when typing
in large markdown files.
Amit Haridas
- Add tab type system ('markdown' and 'pdf')
- Create PDF tabs with their own state (page, zoom, rotation)
- Update closeTab to properly clean up PDF resources
- Update updateUI to handle PDF tabs (hide toolbar, etc.)
- Add visual indicators for PDF tabs in tab bar
- Add CSS styles for PDF tab containers
Fixes: PDF and markdown multitab function not working
Amit Haridas
- Add custom EditorView.theme for CodeMirror 6 with JetBrains Mono
- Update .editor-textarea and #editor font-family to prioritize JetBrains Mono
- Update preview code blocks (#preview code, .preview-content code) to use JetBrains Mono
- Ensures consistent monospace font across editor source and markdown rendering
Amit Haridas
CSS improvements:
- Standardize dark theme selectors to body[class*="dark"] pattern
- This ensures all dark themes (theme-dark, theme-dracula, etc.)
receive consistent styling
- Add semantic color variables (--text-primary, --bg-primary, etc.)
- Replace hardcoded colors with CSS variables in:
- Tab bar component
- Toolbar separator
- Pane resizer
- Status bar
- Add fallback values for backward compatibility
This improves maintainability and makes theming more consistent.
Amit Haridas