Fix/system hardening - #124
Conversation
…ethods in useFile
… adapter interface
… in welcome component
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThis PR updates adapter contracts and Chrome runtime behavior, refactors renderer export and welcome flows, expands tests, and revises extension docs, assets, CSP, and release packaging. ChangesPlatform adapter and renderer export flow
UI, tests, docs, and packaging
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/renderer/__tests__/components/Welcome.test.tsx (1)
32-40: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winExpand tests for new Recent behavior in Welcome.
The suite does not validate the newly introduced recent-item interactions/constraints (e.g., invoking
onOpenRecentand rendering cap of 5 items), especially in extension mode. That leaves the new feature path under-tested.As per coding guidelines, "Write unit tests for all new features to maintain code quality"; and as per path instructions, tests should "cover success and failure paths."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/renderer/__tests__/components/Welcome.test.tsx` around lines 32 - 40, Expand the test case 'shows a list of recent files when provided' to validate the newly introduced recent-item interactions and constraints. Add test coverage for: invoking the onOpenRecent callback when a recent file item is clicked (verify the callback receives the correct file path), verifying that only a maximum of 5 items are rendered when more recent files are provided, and testing the behavior in extension mode. Additionally, add separate test cases to cover edge cases such as empty recent files list and handling of missing or invalid file data to ensure both success and failure paths are tested as per the coding guidelines.Sources: Coding guidelines, Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/extension/popup.html`:
- Line 6: The popup.html file references icon assets in the icons/ directory
(icon-32x32px.png and other sizes: 16, 48, 128) that do not exist, which will
cause manifest validation failures and missing toolbar icons. Create the icons/
directory in apps/extension/ with the required PNG assets at sizes 16×16, 32×32,
48×48, and 128×128 pixels, or alternatively remove all icon references from
popup.html, viewer.html, and manifest.json if icons are intentionally omitted.
In `@apps/renderer/src/components/ReaderStats.tsx`:
- Around line 7-14: The useMemo hook in the ReaderStats component is being
called conditionally after an early return statement, which violates React's
rules of hooks that require hooks to execute unconditionally on every render.
Move the early return check that validates the markdown parameter to after the
useMemo call, ensuring that the useMemo hook executes before any conditional
logic that would prevent it from running on subsequent renders.
In `@apps/renderer/src/components/Welcome.tsx`:
- Around line 48-50: The button elements in the Welcome component that call
onOpenRecent and another button at line 111 are missing explicit type
attributes, causing them to default to type="submit" in form contexts and
potentially trigger accidental form submissions. Add type="button" attribute to
both button elements to ensure they function as regular buttons rather than form
submit buttons.
In `@apps/renderer/src/utils/constants/style-constants.ts`:
- Around line 4-10: The CALLOUT_MAP constant now supports six callout types
(NOTE, WARNING, TIP, IMPORTANT, CAUTION, INFO) but test coverage is incomplete
and documentation is outdated. In callout.test.ts, add test cases for the
missing callout types (IMPORTANT, CAUTION, INFO) and ensure each test verifies
that both the icon and label properties from the CALLOUT_MAP are actually
rendered in the HTML output, not just the class name. Additionally, update
docs/docs/product/markdown-support.md to include documentation examples for all
six callout types instead of just NOTE and WARNING, showing the proper markdown
syntax for each type.
---
Outside diff comments:
In `@apps/renderer/__tests__/components/Welcome.test.tsx`:
- Around line 32-40: Expand the test case 'shows a list of recent files when
provided' to validate the newly introduced recent-item interactions and
constraints. Add test coverage for: invoking the onOpenRecent callback when a
recent file item is clicked (verify the callback receives the correct file
path), verifying that only a maximum of 5 items are rendered when more recent
files are provided, and testing the behavior in extension mode. Additionally,
add separate test cases to cover edge cases such as empty recent files list and
handling of missing or invalid file data to ensure both success and failure
paths are tested as per the coding guidelines.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 039a5824-41a0-4e74-a2ac-1a6f8bd96fef
📒 Files selected for processing (12)
apps/extension/popup.htmlapps/extension/viewer.htmlapps/renderer/__tests__/components/Welcome.test.tsxapps/renderer/src/components/ReaderStats.tsxapps/renderer/src/components/Welcome.tsxapps/renderer/src/hooks/useFile.tsapps/renderer/src/utils/constants/style-constants.tsdocs/docs/product/browser-extension.mddocs/versioned_docs/version-1.0.0/product/browser-extension.mdpackages/platform-adapters/src/adapters/chrome-adapter.tspackages/platform-adapters/src/adapters/electron-adapter.tspackages/platform-adapters/src/types/platform-type.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: build
🧰 Additional context used
📓 Path-based instructions (17)
**
⚙️ CodeRabbit configuration file
**: # Markdown ReaderA native desktop applicaion for reading Markdown files, built entirely on the JavaScript/TypeScript ecosystem using Electron as the desktop runtime.
markdown-reader is to Markdown what Adobe Acrobat Reader is to PDF:
a dedicated, native, first-class desktop viewer for .md files.Table of Contents
Why Markdown Reader ?
The Problem
Markdown is the most widely used plain-text writing format in the world.
Developers, writers, and teams produce millions of .md files daily.
Yet there is no dedicated desktop reader for Markdown that:
Missing Capability Current Workaround Pain Level Opens .md files natively on double-click No default handler — opens as raw text High Renders beautifully like a document VS Code preview pane feels like a dev tool Medium Has a sidebar TOC like a PDF reader Manual heading scanning Medium Supports all Markdown features GitHub renders some, browsers render none High Works fully offline Must open a browser manually High Feels like a reader, not an editor Every tool adds edit affordances Medium VS Code is an editor. GitHub is a web interface. Obsidian is a note-taking vault.
None of them are just a reader — a clean, dedicated app for opening and
reading Markdown files.The Solution
markdown-reader is a dedicated native desktop Markdown reader:
- Double-click any .md file and it opens in markdown-reader
- Registered as the system default application for .md files on install
- Beautiful readable typography — not a developer tool aesthetic
- Full M...
Files:
apps/extension/popup.htmlapps/extension/viewer.htmlapps/renderer/__tests__/components/Welcome.test.tsxdocs/versioned_docs/version-1.0.0/product/browser-extension.mdapps/renderer/src/components/ReaderStats.tsxapps/renderer/src/hooks/useFile.tspackages/platform-adapters/src/adapters/electron-adapter.tsdocs/docs/product/browser-extension.mdpackages/platform-adapters/src/types/platform-type.tspackages/platform-adapters/src/adapters/chrome-adapter.tsapps/renderer/src/utils/constants/style-constants.tsapps/renderer/src/components/Welcome.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use TypeScript as the primary language for the application
Files:
apps/renderer/__tests__/components/Welcome.test.tsxapps/renderer/src/components/ReaderStats.tsxapps/renderer/src/hooks/useFile.tspackages/platform-adapters/src/adapters/electron-adapter.tspackages/platform-adapters/src/types/platform-type.tspackages/platform-adapters/src/adapters/chrome-adapter.tsapps/renderer/src/utils/constants/style-constants.tsapps/renderer/src/components/Welcome.tsx
apps/renderer/**/*.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
apps/renderer/**/*.{ts,tsx}: Use React for frontend UI components
Use Shiki for syntax highlighting in code blocks
Use KaTeX for mathematical equation rendering
Use Mermaid for diagram rendering
Files:
apps/renderer/__tests__/components/Welcome.test.tsxapps/renderer/src/components/ReaderStats.tsxapps/renderer/src/hooks/useFile.tsapps/renderer/src/utils/constants/style-constants.tsapps/renderer/src/components/Welcome.tsx
apps/renderer/**/*.{ts,tsx,css}
📄 CodeRabbit inference engine (README.md)
Use Tailwind CSS for styling
Files:
apps/renderer/__tests__/components/Welcome.test.tsxapps/renderer/src/components/ReaderStats.tsxapps/renderer/src/hooks/useFile.tsapps/renderer/src/utils/constants/style-constants.tsapps/renderer/src/components/Welcome.tsx
**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use Vitest for testing
Files:
apps/renderer/__tests__/components/Welcome.test.tsx
⚙️ CodeRabbit configuration file
**/*.{test,spec}.{ts,tsx}: Review tests.
- Cover success and failure paths, especially IPC, filesystem, markdown rendering, search, settings, tabs, and exports.
- Use isolated temp directories for disk tests and clean them up.
- Mock Electron/preload APIs explicitly.
- Prefer Testing Library user-event and getByRole for UI tests.
Files:
apps/renderer/__tests__/components/Welcome.test.tsx
**/*.{test,spec}.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Write unit tests for all new features to maintain code quality, adding test cases alongside component source code and ensuring all tests pass via
pnpm vitest
Files:
apps/renderer/__tests__/components/Welcome.test.tsx
docs/versioned_docs/version-1.0.0/product/**/*.md
📄 CodeRabbit inference engine (docs/versioned_docs/version-1.0.0/product/markdown-support.md)
docs/versioned_docs/version-1.0.0/product/**/*.md: Support GitHub Flavored Markdown (GFM) features including headings (H1-H6), bold, italic, strikethrough, ordered and unordered lists, nested lists, task lists, inline code, fenced code blocks, blockquotes, tables with alignment, horizontal rules, and autolinks
Use Shiki for code block syntax highlighting with language-aware highlighting for 100+ languages, controlled by the active app theme
Implement expected code block reader features: language label, copy button, optional line numbers, and safe horizontal scrolling or wrapping
Support Mermaid fenced code blocks for common diagram types: flowcharts, sequence diagrams, ER diagrams, Gantt charts, class diagrams, state diagrams, pie charts, and git graphs
Support inline math using single dollar signs ($) and block math using double dollar signs ($ $) for mathematical expressions
Support documentation-style callouts using the syntax> [!NOTE]and> [!WARNING]for different message types
Files:
docs/versioned_docs/version-1.0.0/product/browser-extension.md
docs/**
⚙️ CodeRabbit configuration file
docs/**: # Markdown Reader DocsDocusaurus documentation and marketing site for Markdown Reader.
Run locally
pnpm install pnpm startBuild
pnpm build
Files:
docs/versioned_docs/version-1.0.0/product/browser-extension.mddocs/docs/product/browser-extension.md
docs/versioned_docs/version-1.0.0/**
⚙️ CodeRabbit configuration file
docs/versioned_docs/version-1.0.0/**: ---
title: ArchitectureArchitecture Overview
1. System Communication Flow
The application processes data across four distinct layers, moving sequentially from the user interface down to the computer operating system:
- Renderer (React): The frontend user interface. It owns the UI state and triggers operations by calling a global
window.apiobject.- Preload Bridge: The secure intermediary layer. It exposes a strictly typed, context-isolated API to the renderer and passes messages back and forth across the process boundary.
- Main Process IPC: The core background application. It validates all incoming requests, checks message senders, verifies system paths, and coordinates backend actions.
- Subsystems: The individual specialized modules managed directly by the Main Process. These include:
- Local Filesystem: Handles raw reading and writing of document files.
- Export Modules: Converts and packages documents for output.
- File Watcher: Monitors project directories for automated file changes and sends real-time update notifications back through the Main Process to the Renderer.
2. Step-by-Step File Open Flow
When a user opens a file, the application executes a sequential 7-step process across its operational layers:
- Renderer initiates the request by invoking the
readFile(path)function on the bridge API.- Preload Bridge translates this function call into a secure background communication token named
IPC READ_FILEand forwards it to the main environment.- Main Process intercepts the token and instantly runs security checks to validate both the message sender and the requested filesystem path safety.
- Main Process queries the Filesystem to read the specific markdown file text on the disk.
- Filesystem reads the hard drive storage and returns the raw file content bytes back up to the Main Process.
- Main Process forwards that...
Files:
docs/versioned_docs/version-1.0.0/product/browser-extension.md
docs/versioned_docs/version-1.0.0/product/**
⚙️ CodeRabbit configuration file
docs/versioned_docs/version-1.0.0/product/**: ---
title: Browser ExtensionBrowser Extension
The Markdown Reader browser extension lets you open and read Markdown files in Chrome with the same reader-first experience as the desktop app. It is useful when you want a lightweight reader tab inside the browser, without opening a separate desktop window.
What it does
The extension opens a full-page Markdown Reader tab from the Chrome toolbar. From that tab, you can choose a local
.mdor.markdownfile and read it with the shared Markdown Reader interface:
- Rendered GitHub Flavored Markdown
- Table of contents and reader layout
- Themes, zoom, and reading controls
- Recent file tracking through Chrome storage
- Local-first reading with no account or cloud upload
Because browsers protect local files more strictly than desktop apps, the extension asks you to choose a file through the browser file picker. After you choose it, the extension caches the opened content in Chrome storage so it can keep the recent-file experience usable inside Chrome.
Why it matters
The extension gives Markdown Reader a second shell:
- Use the desktop app when you want native file associations, folder browsing, export, and operating-system integration
- Use the Chrome extension when you want a fast browser tab for reading Markdown without leaving Chrome
Both experiences share the same product code where possible, so the reading behavior stays consistent instead of becoming two separate apps.
Enable it in Chrome
Until the extension is officially published through the Chrome Web Store, you can manually load the pre-compiled extension package directly into Google Chrome using these steps:
- Download the extension bundle file (
markdown-reader-extension.zip) from the latest repository releases section.- Unzip or extract the folder to a safe location on your computer (e.g., your Documents folder).
- Open your Google Chrome browser and navigate to `chrome://extens...
Files:
docs/versioned_docs/version-1.0.0/product/browser-extension.md
docs/**/*.{md,mdx,ts,tsx}
⚙️ CodeRabbit configuration file
docs/**/*.{md,mdx,ts,tsx}: Review docs.
- Docs must match current shortcuts, markdown support, export behaviour, install steps, and privacy/offline claims.
- Code blocks need language tags.
- Links and images should resolve.
- Docusaurus components must guard browser-only APIs during static build.
Files:
docs/versioned_docs/version-1.0.0/product/browser-extension.mddocs/docs/product/browser-extension.md
apps/renderer/src/**/*.{ts,tsx}
⚙️ CodeRabbit configuration file
apps/renderer/src/**/*.{ts,tsx}: Review as React renderer code.
- Keep components typed, accessible, keyboard-friendly, and resilient to missing preload APIs.
- Effects must have correct dependencies and cleanup.
- Handle loading, empty, error, stale-response, and rejected-promise states.
- Do not import Node-only modules into renderer code.
- Avoid unnecessary derived state, unsafe globals, and broad any types.
Files:
apps/renderer/src/components/ReaderStats.tsxapps/renderer/src/hooks/useFile.tsapps/renderer/src/utils/constants/style-constants.tsapps/renderer/src/components/Welcome.tsx
apps/renderer/src/**/*.{css,tsx}
⚙️ CodeRabbit configuration file
apps/renderer/src/**/*.{css,tsx}: Review UI, theme, and accessibility.
- Interactive controls need semantic elements, visible focus, and keyboard access.
- Theme changes must preserve readable contrast in light and dark modes.
- Markdown prose must remain readable for tables, code, blockquotes, links, lists, and images.
- Prefer existing tokens/classes over ad hoc inline styling.
Files:
apps/renderer/src/components/ReaderStats.tsxapps/renderer/src/components/Welcome.tsx
docs/docs/product/**/*.{md,markdown}
📄 CodeRabbit inference engine (docs/docs/product/markdown-support.md)
Support GitHub Flavored Markdown (GFM) features including headings (H1-H6), bold, italic, strikethrough, ordered and unordered lists, nested lists, task lists, inline code, fenced code blocks, blockquotes, tables with alignment, horizontal rules, and autolinks
Files:
docs/docs/product/browser-extension.md
docs/docs/**
⚙️ CodeRabbit configuration file
docs/docs/**: ---
title: ArchitectureArchitecture Overview
1. System Communication Flow
The application processes data across four distinct layers, moving sequentially from the user interface down to the computer operating system:
- Renderer (React): The frontend user interface. It owns the UI state and triggers operations by calling a global
window.apiobject.- Preload Bridge: The secure intermediary layer. It exposes a strictly typed, context-isolated API to the renderer and passes messages back and forth across the process boundary.
- Main Process IPC: The core background application. It validates all incoming requests, checks message senders, verifies system paths, and coordinates backend actions.
- Subsystems: The individual specialized modules managed directly by the Main Process. These include:
- Local Filesystem: Handles raw reading and writing of document files.
- Export Modules: Converts and packages documents for output.
- File Watcher: Monitors project directories for automated file changes and sends real-time update notifications back through the Main Process to the Renderer.
2. Step-by-Step File Open Flow
When a user opens a file, the application executes a sequential 7-step process across its operational layers:
- Renderer initiates the request by invoking the
readFile(path)function on the bridge API.- Preload Bridge translates this function call into a secure background communication token named
IPC READ_FILEand forwards it to the main environment.- Main Process intercepts the token and instantly runs security checks to validate both the message sender and the requested filesystem path safety.
- Main Process queries the Filesystem to read the specific markdown file text on the disk.
- Filesystem reads the hard drive storage and returns the raw file content bytes back up to the Main Process.
- Main Process forwards that document content back a...
Files:
docs/docs/product/browser-extension.md
docs/docs/product/**
⚙️ CodeRabbit configuration file
docs/docs/product/**: ---
title: Browser ExtensionBrowser Extension
The Markdown Reader browser extension lets you open and read Markdown files in Chrome with the same reader-first experience as the desktop app. It is useful when you want a lightweight reader tab inside the browser, without opening a separate desktop window.
What it does
The extension opens a full-page Markdown Reader tab from the Chrome toolbar. From that tab, you can choose a local
.mdor.markdownfile and read it with the shared Markdown Reader interface:
- Rendered GitHub Flavored Markdown
- Table of contents and reader layout
- Themes, zoom, and reading controls
- Recent file tracking through Chrome storage
- Local-first reading with no account or cloud upload
Because browsers protect local files more strictly than desktop apps, the extension asks you to choose a file through the browser file picker. After you choose it, the extension caches the opened content in Chrome storage so it can keep the recent-file experience usable inside Chrome.
Why it matters
The extension gives Markdown Reader a second shell:
- Use the desktop app when you want native file associations, folder browsing, export, and operating-system integration
- Use the Chrome extension when you want a fast browser tab for reading Markdown without leaving Chrome
Both experiences share the same product code where possible, so the reading behavior stays consistent instead of becoming two separate apps.
Enable it in Chrome
Until the extension is officially published through the Chrome Web Store, you can manually load the pre-compiled extension package directly into Google Chrome using these steps:
- Download the extension bundle file (
markdown-reader-extension.zip) from the latest repository releases section.- Unzip or extract the folder to a safe location on your computer (e.g., your Documents folder).
- Open your Google Chrome browser and navigate to
chrome://extensions/by typing it into...
Files:
docs/docs/product/browser-extension.md
apps/renderer/src/**/{renderer,markdown,utils}/**/*.{ts,tsx}
⚙️ CodeRabbit configuration file
apps/renderer/src/**/{renderer,markdown,utils}/**/*.{ts,tsx}: Review markdown rendering carefully.
- Sanitize raw HTML, links, images, Mermaid, KaTeX, anchors, and exported content.
- Block script execution, javascript: URLs, unsafe inline handlers, and unsafe local file references.
- Heading IDs and TOC entries must be stable and collision-safe.
- Mermaid/KaTeX/code highlighting failures should not break the whole document.
- Add tests for unsafe HTML, malformed markdown, links, images, code blocks, Mermaid, and KaTeX when changed.
Files:
apps/renderer/src/utils/constants/style-constants.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-23T09:23:17.388Z
Learning: Share product code between the desktop app and Chrome extension to keep reading behavior consistent and avoid maintaining two separate apps
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-23T09:23:17.388Z
Learning: Store only recent-file metadata and settings in Chrome storage; keep opened content in temporary runtime cache for the current session and do not persist content to Chrome storage
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-23T09:23:17.388Z
Learning: Use the browser file picker interface for users to choose local Markdown files instead of direct file system access
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-23T09:23:17.388Z
Learning: Support GitHub Flavored Markdown rendering in the extension with the same reader interface as the desktop app
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-23T09:23:40.569Z
Learning: Share Markdown Reader product code between the desktop app and Chrome extension to keep reading behavior consistent
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-23T09:23:40.569Z
Learning: Chrome extension should use the browser file picker for safe local file access instead of direct filesystem operations
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-23T09:23:40.569Z
Learning: Extension should persist only recent-file metadata and settings in Chrome storage, not full file content
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-23T09:23:40.569Z
Learning: Live reload functionality should be designated as desktop-only, not implemented in the Chrome extension
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-23T09:23:40.569Z
Learning: Native folder browsing functionality should be restricted to the desktop app only, not the Chrome extension
🪛 React Doctor (0.5.8)
apps/renderer/__tests__/components/Welcome.test.tsx
[warning] 27-27: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
apps/renderer/src/components/Welcome.tsx
[warning] 13-13: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 14-14: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 15-15: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 16-16: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 22-22: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 25-25: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 30-30: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 35-35: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 41-41: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 42-42: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 45-45: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 47-47: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 48-48: Your users can submit the form by accident because a <button> with no type defaults to submit.
Set an explicit button type so plain buttons do not submit forms by accident: type="button", "submit", or "reset".
(button-has-type)
[warning] 48-48: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 52-52: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 53-53: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 56-56: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 63-63: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 64-64: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 66-66: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 85-85: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 90-90: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 91-91: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 93-93: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 94-94: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
[warning] 95-95: This JSX crashes because React isn't in scope.
If you're on React 17+ with the new JSX transform, disable this rule. Otherwise import React at the top of the file.
(react-in-jsx-scope)
🔇 Additional comments (6)
packages/platform-adapters/src/types/platform-type.ts (1)
34-40: LGTM!packages/platform-adapters/src/adapters/chrome-adapter.ts (1)
154-161: LGTM!Also applies to: 233-235, 274-276, 344-349
packages/platform-adapters/src/adapters/electron-adapter.ts (1)
25-39: LGTM!apps/renderer/src/hooks/useFile.ts (1)
32-32: LGTM!Also applies to: 57-57
docs/docs/product/browser-extension.md (1)
19-19: LGTM!Documentation accurately reflects the actual implementation:
- Line 19 correctly clarifies that opened content lives in a temporary runtime cache (not persisted), while only metadata and settings persist to Chrome storage.
- Line 34 correctly references the release-built artifact name
extension-release.zip(confirmed by release.yml).Also applies to: 34-34
docs/versioned_docs/version-1.0.0/product/browser-extension.md (1)
19-19: LGTM!Also applies to: 34-34
…r, handle unsupport ops locally
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/platform-adapters/src/adapters/chrome-adapter.ts (1)
127-137: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winClear stale
transientFilesentries on a later successful cache write.Once a path is added here, reopening the same file after storage becomes available again still leaves
addRecentFile()returning early for the rest of the session. Remove the path fromtransientFileswhensetItem()succeeds so recovered files can reappear in recents.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/platform-adapters/src/adapters/chrome-adapter.ts` around lines 127 - 137, The `ChromeAdapter` cache write path leaves stale entries in `transientFiles` after a quota failure, so `addRecentFile()` keeps skipping recovered files. Update the `setItem()` flow in `ChromeAdapter` so that on a later successful write the current `path` is removed from `transientFiles`, and keep the existing quota-error handling in the `catch` block unchanged. This should be done in the same area as the `storage.setItem(...)` try/catch and the `transientFiles` set logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/renderer/README.md`:
- Around line 81-83: Update the earlier renderer overview in the README so it no
longer says file operations always go through the preload/main-process IPC path;
instead, describe cross-platform feature access through usePlatformAPI, which
routes ElectronAdapter and ChromeAdapter behavior appropriately. Keep the
existing markdown renderer context, but make sure the guidance around
window.markdownReaderAPI and usePlatformAPI clearly distinguishes the underlying
Electron bridge from the UI-facing abstraction.
In `@packages/platform-adapters/__tests__/chrome-adapter.test.ts`:
- Around line 117-119: The current Chrome adapter tests cover the picker success
path, but the new picker logic in the adapter also has a cancel branch and
quota-based transient-file suppression that need regression coverage. Add unit
tests around the picker flow in the Chrome adapter test suite to verify the
cancel event path is handled correctly and that transient-file/session-only
entries are suppressed when quota behavior is triggered, using the existing
adapter picker and file cache/recent-files behavior as the target points.
In `@packages/platform-adapters/src/adapters/chrome-adapter.ts`:
- Around line 312-320: The exportHTML method in chrome-adapter.ts is hardcoding
the download filename instead of using the caller-provided outputPath, so the
exported HTML name is lost. Update exportHTML to derive the a.download value
from outputPath while keeping the existing Blob/URL download flow in
chrome-adapter.ts, ensuring the exported file preserves the requested name.
---
Outside diff comments:
In `@packages/platform-adapters/src/adapters/chrome-adapter.ts`:
- Around line 127-137: The `ChromeAdapter` cache write path leaves stale entries
in `transientFiles` after a quota failure, so `addRecentFile()` keeps skipping
recovered files. Update the `setItem()` flow in `ChromeAdapter` so that on a
later successful write the current `path` is removed from `transientFiles`, and
keep the existing quota-error handling in the `catch` block unchanged. This
should be done in the same area as the `storage.setItem(...)` try/catch and the
`transientFiles` set logic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 843dced7-fbe3-4ac5-bc30-f2b9ff3f35a7
📒 Files selected for processing (13)
README.mdapps/extension/README.mdapps/extension/src/utils/helpers/message-handler.tsapps/main-processor/README.mdapps/preload/README.mdapps/renderer/README.mdapps/renderer/__tests__/renderer/callout.test.tsapps/renderer/src/components/ReaderStats.tsxapps/renderer/src/components/Welcome.tsxapps/renderer/src/hooks/useFileActions.tsapps/renderer/src/hooks/useWatcher.tspackages/platform-adapters/__tests__/chrome-adapter.test.tspackages/platform-adapters/src/adapters/chrome-adapter.ts
💤 Files with no reviewable changes (1)
- apps/extension/src/utils/helpers/message-handler.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: build
🧰 Additional context used
📓 Path-based instructions (5)
**
⚙️ CodeRabbit configuration file
**: # Markdown ReaderA native desktop applicaion for reading Markdown files, built entirely on the JavaScript/TypeScript ecosystem using Electron as the desktop runtime.
markdown-reader is to Markdown what Adobe Acrobat Reader is to PDF:
a dedicated, native, first-class desktop viewer for .md files.Table of Contents
Why Markdown Reader ?
The Problem
Markdown is the most widely used plain-text writing format in the world.
Developers, writers, and teams produce millions of .md files daily.
Yet there is no dedicated desktop reader for Markdown that:
Missing Capability Current Workaround Pain Level Opens .md files natively on double-click No default handler — opens as raw text High Renders beautifully like a document VS Code preview pane feels like a dev tool Medium Has a sidebar TOC like a PDF reader Manual heading scanning Medium Supports all Markdown features GitHub renders some, browsers render none High Works fully offline Must open a browser manually High Feels like a reader, not an editor Every tool adds edit affordances Medium VS Code is an editor. GitHub is a web interface. Obsidian is a note-taking vault.
None of them are just a reader — a clean, dedicated app for opening and
reading Markdown files.The Solution
markdown-reader is a dedicated native desktop Markdown reader:
- Double-click any .md file and it opens in markdown-reader
- Registered as the system default application for .md files on install
- Beautiful readable typography — not a developer tool aesthetic
- Full M...
Files:
apps/renderer/src/hooks/useWatcher.tsapps/renderer/src/hooks/useFileActions.tsapps/main-processor/README.mdpackages/platform-adapters/__tests__/chrome-adapter.test.tsapps/renderer/README.mdapps/preload/README.mdREADME.mdapps/renderer/__tests__/renderer/callout.test.tsapps/extension/README.mdapps/renderer/src/components/ReaderStats.tsxapps/renderer/src/components/Welcome.tsxpackages/platform-adapters/src/adapters/chrome-adapter.ts
apps/renderer/src/**/*.{ts,tsx}
⚙️ CodeRabbit configuration file
apps/renderer/src/**/*.{ts,tsx}: Review as React renderer code.
- Keep components typed, accessible, keyboard-friendly, and resilient to missing preload APIs.
- Effects must have correct dependencies and cleanup.
- Handle loading, empty, error, stale-response, and rejected-promise states.
- Do not import Node-only modules into renderer code.
- Avoid unnecessary derived state, unsafe globals, and broad any types.
Files:
apps/renderer/src/hooks/useWatcher.tsapps/renderer/src/hooks/useFileActions.tsapps/renderer/src/components/ReaderStats.tsxapps/renderer/src/components/Welcome.tsx
**/*.{test,spec}.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Write unit tests for all new features to maintain code quality, adding test cases alongside component source code and ensuring all tests pass via
pnpm vitest
Files:
packages/platform-adapters/__tests__/chrome-adapter.test.tsapps/renderer/__tests__/renderer/callout.test.ts
**/*.{test,spec}.{ts,tsx}
⚙️ CodeRabbit configuration file
**/*.{test,spec}.{ts,tsx}: Review tests.
- Cover success and failure paths, especially IPC, filesystem, markdown rendering, search, settings, tabs, and exports.
- Use isolated temp directories for disk tests and clean them up.
- Mock Electron/preload APIs explicitly.
- Prefer Testing Library user-event and getByRole for UI tests.
Files:
packages/platform-adapters/__tests__/chrome-adapter.test.tsapps/renderer/__tests__/renderer/callout.test.ts
apps/renderer/src/**/*.{css,tsx}
⚙️ CodeRabbit configuration file
apps/renderer/src/**/*.{css,tsx}: Review UI, theme, and accessibility.
- Interactive controls need semantic elements, visible focus, and keyboard access.
- Theme changes must preserve readable contrast in light and dark modes.
- Markdown prose must remain readable for tables, code, blockquotes, links, lists, and images.
- Prefer existing tokens/classes over ad hoc inline styling.
Files:
apps/renderer/src/components/ReaderStats.tsxapps/renderer/src/components/Welcome.tsx
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:23.876Z
Learning: Build markdown-reader as a native desktop application for reading Markdown files using the JavaScript/TypeScript ecosystem, with Electron as the desktop runtime.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:23.876Z
Learning: Make the app a dedicated, first-class desktop viewer for `.md` files rather than a general editor.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:23.876Z
Learning: Open `.md` files on double-click and register the app as the system default handler for Markdown files on install.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:23.876Z
Learning: Provide readable, document-like typography instead of a developer-tool aesthetic.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:23.876Z
Learning: Support full Markdown rendering, including code, diagrams, math, tables, task lists, and callouts.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:23.876Z
Learning: Generate a table-of-contents sidebar automatically, similar to a PDF reader.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:23.876Z
Learning: Watch files and live-reload the view when Markdown files are edited externally.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:23.876Z
Learning: Support multiple built-in themes.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:23.876Z
Learning: Keep the app fully offline with zero cloud usage, telemetry, or accounts.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:23.876Z
Learning: Use only the JavaScript/TypeScript ecosystem; avoid Rust, Go, and C++ in the implementation.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:23.876Z
Learning: Use GitHub Actions for CI/CD.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:23.876Z
Learning: Support the documented release formats for Windows (`.exe`), Linux (`.AppImage`, `.deb`), and macOS (`.dmg`).
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:23.876Z
Learning: Use the documented keyboard shortcuts for core app actions such as opening files, search, zoom, theme switching, tab navigation, and toggling panels.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:30.641Z
Learning: The Chrome extension should open a full-page Markdown Reader tab from the browser toolbar and let the user choose a local `.md` or `.markdown` file through the browser file picker.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:30.641Z
Learning: After a file is chosen, the extension should keep the opened content only in a temporary runtime cache for the current session.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:30.641Z
Learning: The extension should persist only recent-file metadata and settings in Chrome storage.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:30.641Z
Learning: The browser extension should share the same Markdown Reader interface and reading behavior with the desktop app where possible.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:30.641Z
Learning: Live reload after opening a local file is a desktop-only feature; the Chrome extension should not attempt to support arbitrary local file watching.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:30.641Z
Learning: The extension should not rely on native folder browsing or native save/export flows that depend on desktop or platform-specific file-system access.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:36.337Z
Learning: The Chrome extension must let users open and read local `.md` and `.markdown` files in a full-page Markdown Reader tab from the browser toolbar.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:36.337Z
Learning: Because browsers restrict local file access, the extension must require users to select files through the browser file picker instead of directly watching arbitrary local files.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:36.337Z
Learning: After a file is opened, the extension should keep the file content only in a temporary runtime cache for the current session.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:36.337Z
Learning: The extension should persist only recent-file metadata and settings in Chrome storage, not the opened file contents.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:36.337Z
Learning: Live reload and other arbitrary local-file watching behavior should remain a desktop-only feature, since Chrome cannot watch chosen local files like the desktop app can.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T07:22:36.337Z
Learning: Native save dialogs and some export flows may depend on platform support and can be more complete in the desktop app than in the browser extension.
🔇 Additional comments (7)
README.md (1)
239-239: LGTM!apps/extension/README.md (1)
23-29: LGTM!apps/main-processor/README.md (1)
22-22: LGTM!apps/preload/README.md (1)
19-19: LGTM!Also applies to: 32-32
apps/renderer/src/components/Welcome.tsx (1)
30-37: LGTM!Also applies to: 39-77, 86-101
apps/renderer/src/components/ReaderStats.tsx (1)
7-14: LGTM!apps/renderer/__tests__/renderer/callout.test.ts (1)
8-42: LGTM!
…explicitly getting thrown
…download fallback
…ace silent catch blocks
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/platform-adapters/src/adapters/chrome-adapter.ts (1)
123-137: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winKeep the recent-file identity stable across edits.
Line 125 now bakes
sizeandlastModifiedinto the persisted path, butaddRecentFile()deduplicates recents by exactpath. Reopening the same Markdown file after any edit will create a second recent entry instead of updating the existing one. Use the composite value only as an internal cache key, and keep the recent-file path/identity stable.Suggested direction
- const path = `[${file.size}:${file.lastModified}]/${file.name}`; - this.openedFiles.set(path, content); + const path = file.name; + const cacheKey = `[${file.size}:${file.lastModified}]/${file.name}`; + this.openedFiles.set(path, content); try { - await this.storage.setItem(`${STORAGE_KEYS.FILE_CONTENT_PREFIX}${path}`, content); + await this.storage.setItem(`${STORAGE_KEYS.FILE_CONTENT_PREFIX}${cacheKey}`, content);Based on learnings, recent-file metadata should remain separate from temporary file-content cache keys.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/platform-adapters/src/adapters/chrome-adapter.ts` around lines 123 - 137, The recent-file identity is being tied to the cache key in chrome-adapter’s file open flow, which causes duplicate entries after edits. Update the reader.onload logic in chrome-adapter.ts so the composite value using file.size and file.lastModified is used only for the temporary file-content storage key, while the stable recent-file path passed to addRecentFile remains based on the original file identity. Keep the cache key and recent-file metadata separate so reopening the same file updates the existing recent entry instead of creating a new one.Source: Learnings
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/renderer/__tests__/components/Sidebar.test.tsx`:
- Line 34: The Sidebar test is using a text-only selector for the TOC item,
which is less robust than a role-based query. Update the click in
Sidebar.test.tsx to target the interactive TOC element by its accessible role
and name instead of getByText, following the Testing Library pattern used in
this suite and keeping the user.click interaction on the same Sidebar component
behavior.
In `@apps/renderer/__tests__/components/TabBar.test.tsx`:
- Line 55: The TabBar test is using index-based selection for the close button,
which makes it dependent on render order. Update the assertion in
TabBar.test.tsx to target the specific tab’s close button by its accessible name
instead of using getAllByRole(...)[0], so the test remains stable if the button
order changes.
In `@apps/renderer/src/components/ReaderToolbar.tsx`:
- Around line 111-121: The export popup in ReaderToolbar is announced as a menu
by the trigger, but the rendered popup is only a group, so the semantics and
keyboard expectations do not match. Update the ReaderToolbar export control to
use a disclosure pattern instead of menu semantics, or fully implement a real
menu pattern with matching role, item roles, and focus handling; in either case,
align the button and popup markup in ReaderToolbar so assistive tech and
keyboard users get consistent behavior.
In `@apps/renderer/src/hooks/useMenuEvents.ts`:
- Around line 45-53: The cleanup in useMenuEvents is still using global adapter
teardown instead of the per-listener disposers returned by api.onMenuEvent(),
which can remove other consumers’ callbacks. Update the effect in useMenuEvents
to store each unsubscribe from onExportHtml, onExportPdf, and onExportDocx
registrations and invoke those targeted disposers on unmount, and remove the
fallback call to removeMenuListeners().
---
Outside diff comments:
In `@packages/platform-adapters/src/adapters/chrome-adapter.ts`:
- Around line 123-137: The recent-file identity is being tied to the cache key
in chrome-adapter’s file open flow, which causes duplicate entries after edits.
Update the reader.onload logic in chrome-adapter.ts so the composite value using
file.size and file.lastModified is used only for the temporary file-content
storage key, while the stable recent-file path passed to addRecentFile remains
based on the original file identity. Keep the cache key and recent-file metadata
separate so reopening the same file updates the existing recent entry instead of
creating a new one.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 2873e663-354b-4328-b353-e161c0202c81
📒 Files selected for processing (15)
.github/workflows/release.ymlapps/main-processor/__tests__/recent.test.tsapps/renderer/__tests__/components/Sidebar.test.tsxapps/renderer/__tests__/components/TabBar.test.tsxapps/renderer/__tests__/components/Welcome.test.tsxapps/renderer/src/components/ReaderToolbar.tsxapps/renderer/src/components/Welcome.tsxapps/renderer/src/hooks/useExport.tsapps/renderer/src/hooks/useMenuEvents.tsapps/renderer/src/types/component-types.tsapps/renderer/src/types/hook-types.tsdocs/docs/installation.mdxdocs/versioned_docs/version-1.0.0/installation.mdxpackages/platform-adapters/__tests__/electron-adapter.test.tspackages/platform-adapters/src/adapters/chrome-adapter.ts
💤 Files with no reviewable changes (1)
- apps/renderer/src/components/Welcome.tsx
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: build
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{test,spec}.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Write unit tests for all new features to maintain code quality, adding test cases alongside component source code and ensuring all tests pass via
pnpm vitest
Files:
apps/renderer/__tests__/components/Sidebar.test.tsxpackages/platform-adapters/__tests__/electron-adapter.test.tsapps/renderer/__tests__/components/Welcome.test.tsxapps/renderer/__tests__/components/TabBar.test.tsxapps/main-processor/__tests__/recent.test.ts
**
⚙️ CodeRabbit configuration file
**: # Markdown ReaderA native desktop applicaion for reading Markdown files, built entirely on the JavaScript/TypeScript ecosystem using Electron as the desktop runtime.
markdown-reader is to Markdown what Adobe Acrobat Reader is to PDF:
a dedicated, native, first-class desktop viewer for .md files.Table of Contents
Why Markdown Reader ?
The Problem
Markdown is the most widely used plain-text writing format in the world.
Developers, writers, and teams produce millions of .md files daily.
Yet there is no dedicated desktop reader for Markdown that:
Missing Capability Current Workaround Pain Level Opens .md files natively on double-click No default handler — opens as raw text High Renders beautifully like a document VS Code preview pane feels like a dev tool Medium Has a sidebar TOC like a PDF reader Manual heading scanning Medium Supports all Markdown features GitHub renders some, browsers render none High Works fully offline Must open a browser manually High Feels like a reader, not an editor Every tool adds edit affordances Medium VS Code is an editor. GitHub is a web interface. Obsidian is a note-taking vault.
None of them are just a reader — a clean, dedicated app for opening and
reading Markdown files.The Solution
markdown-reader is a dedicated native desktop Markdown reader:
- Double-click any .md file and it opens in markdown-reader
- Registered as the system default application for .md files on install
- Beautiful readable typography — not a developer tool aesthetic
- Full M...
Files:
apps/renderer/__tests__/components/Sidebar.test.tsxpackages/platform-adapters/__tests__/electron-adapter.test.tsapps/renderer/src/types/component-types.tsapps/renderer/src/hooks/useMenuEvents.tsapps/renderer/src/types/hook-types.tsapps/renderer/__tests__/components/Welcome.test.tsxapps/renderer/__tests__/components/TabBar.test.tsxapps/renderer/src/hooks/useExport.tsdocs/versioned_docs/version-1.0.0/installation.mdxapps/main-processor/__tests__/recent.test.tsapps/renderer/src/components/ReaderToolbar.tsxdocs/docs/installation.mdxpackages/platform-adapters/src/adapters/chrome-adapter.ts
**/*.{test,spec}.{ts,tsx}
⚙️ CodeRabbit configuration file
**/*.{test,spec}.{ts,tsx}: Review tests.
- Cover success and failure paths, especially IPC, filesystem, markdown rendering, search, settings, tabs, and exports.
- Use isolated temp directories for disk tests and clean them up.
- Mock Electron/preload APIs explicitly.
- Prefer Testing Library user-event and getByRole for UI tests.
Files:
apps/renderer/__tests__/components/Sidebar.test.tsxpackages/platform-adapters/__tests__/electron-adapter.test.tsapps/renderer/__tests__/components/Welcome.test.tsxapps/renderer/__tests__/components/TabBar.test.tsxapps/main-processor/__tests__/recent.test.ts
apps/renderer/src/**/*.{ts,tsx}
⚙️ CodeRabbit configuration file
apps/renderer/src/**/*.{ts,tsx}: Review as React renderer code.
- Keep components typed, accessible, keyboard-friendly, and resilient to missing preload APIs.
- Effects must have correct dependencies and cleanup.
- Handle loading, empty, error, stale-response, and rejected-promise states.
- Do not import Node-only modules into renderer code.
- Avoid unnecessary derived state, unsafe globals, and broad any types.
Files:
apps/renderer/src/types/component-types.tsapps/renderer/src/hooks/useMenuEvents.tsapps/renderer/src/types/hook-types.tsapps/renderer/src/hooks/useExport.tsapps/renderer/src/components/ReaderToolbar.tsx
.github/workflows/**/*.yml
⚙️ CodeRabbit configuration file
.github/workflows/**/*.yml: Review CI/CD.
- Actions should use version tags, not
@main.- Secrets must use ${{ secrets.* }} and never be hardcoded.
- CI should install with pinned pnpm, then run lint, typecheck, tests, build, and package checks.
- Security scans should fail for high/critical findings unless justified.
Files:
.github/workflows/release.yml
docs/**
⚙️ CodeRabbit configuration file
docs/**: # Markdown Reader DocsDocusaurus documentation and marketing site for Markdown Reader.
Run locally
pnpm install pnpm startBuild
pnpm build
Files:
docs/versioned_docs/version-1.0.0/installation.mdxdocs/docs/installation.mdx
docs/versioned_docs/version-1.0.0/**
⚙️ CodeRabbit configuration file
docs/versioned_docs/version-1.0.0/**: ---
title: ArchitectureArchitecture Overview
1. System Communication Flow
The application processes data across four distinct layers, moving sequentially from the user interface down to the computer operating system:
- Renderer (React): The frontend user interface. It owns the UI state and triggers operations by calling a global
window.apiobject.- Preload Bridge: The secure intermediary layer. It exposes a strictly typed, context-isolated API to the renderer and passes messages back and forth across the process boundary.
- Main Process IPC: The core background application. It validates all incoming requests, checks message senders, verifies system paths, and coordinates backend actions.
- Subsystems: The individual specialized modules managed directly by the Main Process. These include:
- Local Filesystem: Handles raw reading and writing of document files.
- Export Modules: Converts and packages documents for output.
- File Watcher: Monitors project directories for automated file changes and sends real-time update notifications back through the Main Process to the Renderer.
2. Step-by-Step File Open Flow
When a user opens a file, the application executes a sequential 7-step process across its operational layers:
- Renderer initiates the request by invoking the
readFile(path)function on the bridge API.- Preload Bridge translates this function call into a secure background communication token named
IPC READ_FILEand forwards it to the main environment.- Main Process intercepts the token and instantly runs security checks to validate both the message sender and the requested filesystem path safety.
- Main Process queries the Filesystem to read the specific markdown file text on the disk.
- Filesystem reads the hard drive storage and returns the raw file content bytes back up to the Main Process.
- Main Process forwards that...
Files:
docs/versioned_docs/version-1.0.0/installation.mdx
docs/**/*.{md,mdx,ts,tsx}
⚙️ CodeRabbit configuration file
docs/**/*.{md,mdx,ts,tsx}: Review docs.
- Docs must match current shortcuts, markdown support, export behaviour, install steps, and privacy/offline claims.
- Code blocks need language tags.
- Links and images should resolve.
- Docusaurus components must guard browser-only APIs during static build.
Files:
docs/versioned_docs/version-1.0.0/installation.mdxdocs/docs/installation.mdx
apps/renderer/src/**/*.{css,tsx}
⚙️ CodeRabbit configuration file
apps/renderer/src/**/*.{css,tsx}: Review UI, theme, and accessibility.
- Interactive controls need semantic elements, visible focus, and keyboard access.
- Theme changes must preserve readable contrast in light and dark modes.
- Markdown prose must remain readable for tables, code, blockquotes, links, lists, and images.
- Prefer existing tokens/classes over ad hoc inline styling.
Files:
apps/renderer/src/components/ReaderToolbar.tsx
docs/docs/**
⚙️ CodeRabbit configuration file
docs/docs/**: ---
title: ArchitectureArchitecture Overview
1. System Communication Flow
The application processes data across four distinct layers, moving sequentially from the user interface down to the computer operating system:
- Renderer (React): The frontend user interface. It owns the UI state and triggers operations by calling a global
window.apiobject.- Preload Bridge: The secure intermediary layer. It exposes a strictly typed, context-isolated API to the renderer and passes messages back and forth across the process boundary.
- Main Process IPC: The core background application. It validates all incoming requests, checks message senders, verifies system paths, and coordinates backend actions.
- Subsystems: The individual specialized modules managed directly by the Main Process. These include:
- Local Filesystem: Handles raw reading and writing of document files.
- Export Modules: Converts and packages documents for output.
- File Watcher: Monitors project directories for automated file changes and sends real-time update notifications back through the Main Process to the Renderer.
2. Step-by-Step File Open Flow
When a user opens a file, the application executes a sequential 7-step process across its operational layers:
- Renderer initiates the request by invoking the
readFile(path)function on the bridge API.- Preload Bridge translates this function call into a secure background communication token named
IPC READ_FILEand forwards it to the main environment.- Main Process intercepts the token and instantly runs security checks to validate both the message sender and the requested filesystem path safety.
- Main Process queries the Filesystem to read the specific markdown file text on the disk.
- Filesystem reads the hard drive storage and returns the raw file content bytes back up to the Main Process.
- Main Process forwards that document content back a...
Files:
docs/docs/installation.mdx
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T10:28:11.461Z
Learning: Build the app entirely on the JavaScript/TypeScript ecosystem, using Electron as the desktop runtime.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T10:28:11.461Z
Learning: Use TypeScript for the codebase.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T10:28:11.461Z
Learning: Use GitHub Actions for CI/CD, with checks for build, lint, typecheck, and tests on pull requests and pushes to main and dev.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T10:28:11.461Z
Learning: Create production releases from Git tags, which should build installers, create a GitHub Release, and upload release artifacts.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T10:28:11.461Z
Learning: Build the Chrome extension with the dedicated extension build command.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T10:28:11.461Z
Learning: The application should be fully offline and avoid cloud, telemetry, and accounts.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T10:28:24.065Z
Learning: The browser extension and desktop app should share product code where possible so that reading behavior stays consistent instead of becoming two separate apps.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T10:28:29.368Z
Learning: The Chrome extension should open Markdown files in a full-page reader tab from the browser toolbar, using the shared Markdown Reader interface for reading behavior.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T10:28:29.368Z
Learning: When a user selects a local `.md` or `.markdown` file in the extension, the opened content should be stored only in a temporary runtime cache for the current session, while persisting only recent-file metadata and settings in Chrome storage.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T10:28:29.368Z
Learning: Because browser security limits direct local-file access, the extension should use the browser file picker for choosing files instead of relying on direct filesystem watching or folder access.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T10:28:29.368Z
Learning: The browser extension should preserve the same Markdown rendering behavior as the desktop app wherever possible, so the two experiences do not diverge into separate product implementations.
🪛 zizmor (1.26.1)
.github/workflows/release.yml
[error] 196-196: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 203-203: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🔇 Additional comments (6)
apps/main-processor/__tests__/recent.test.ts (1)
1-10: LGTM!Also applies to: 51-61
apps/renderer/__tests__/components/Welcome.test.tsx (1)
2-3: LGTM!Also applies to: 10-21, 24-27, 29-35
docs/docs/installation.mdx (1)
14-27: LGTM!Also applies to: 79-79, 92-92
docs/versioned_docs/version-1.0.0/installation.mdx (1)
14-27: LGTM!Also applies to: 79-79, 92-92
.github/workflows/release.yml (2)
28-28: LGTM!Also applies to: 101-101, 151-151
195-206: 🔒 Security & PrivacyNo change needed for
actions/download-artifact
These steps are already version-pinned, and this repo’s workflow policy uses release tags rather than immutable SHAs.> Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/renderer/__tests__/components/Welcome.test.tsx (1)
10-35: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winAdd tests for recent-item interaction and top-5 truncation.
This file now validates open-button flows, but it still misses assertions for the new recent-doc behavior: clicking a recent item should call
onOpenRecent(path), and only 5 items should render when more are provided.Suggested test additions
+ it('calls onOpenRecent with the selected path', async () => { + const handleOpenRecent = vi.fn(); + const user = userEvent.setup(); + const recent = [ + { path: '/docs/README.md', name: 'README.md', openedAt: Date.now() }, + ]; + render( + <Welcome onOpen={() => {}} recentFiles={recent} onOpenRecent={handleOpenRecent} />, + { wrapper }, + ); + + await user.click(screen.getByRole('button', { name: /README\.md/i })); + expect(handleOpenRecent).toHaveBeenCalledWith('/docs/README.md'); + }); + + it('renders only the 5 most recent items', () => { + const now = Date.now(); + const recent = Array.from({ length: 7 }, (_, i) => ({ + path: `/docs/file-${i + 1}.md`, + name: `file-${i + 1}.md`, + openedAt: now - i * 1000, + })); + render(<Welcome onOpen={() => {}} recentFiles={recent} />, { wrapper }); + + expect(screen.getByText('file-5.md')).toBeInTheDocument(); + expect(screen.queryByText('file-6.md')).not.toBeInTheDocument(); + expect(screen.queryByText('file-7.md')).not.toBeInTheDocument(); + });As per coding guidelines, “Write unit tests for all new features,” and as per path instructions for
**/*.{test,spec}.{ts,tsx}, “Cover success and failure paths.”🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/renderer/__tests__/components/Welcome.test.tsx` around lines 10 - 35, The Welcome tests cover open-button behavior but do not verify the new recent-doc interactions. Add assertions in Welcome.test.tsx for the Welcome component’s recent-item rendering so that clicking a recent item calls the onOpenRecent callback with the item path, and verify the recent list is truncated to 5 items when more than five are passed. Use the existing Welcome render setup and extend the current test cases around the Welcome component and recentFiles prop.Sources: Coding guidelines, Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@apps/renderer/__tests__/components/Welcome.test.tsx`:
- Around line 10-35: The Welcome tests cover open-button behavior but do not
verify the new recent-doc interactions. Add assertions in Welcome.test.tsx for
the Welcome component’s recent-item rendering so that clicking a recent item
calls the onOpenRecent callback with the item path, and verify the recent list
is truncated to 5 items when more than five are passed. Use the existing Welcome
render setup and extend the current test cases around the Welcome component and
recentFiles prop.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 31c5cf47-bffe-473d-9343-159117b32e09
⛔ Files ignored due to path filters (1)
docs/static/video/windows-install.mp4is excluded by!**/*.mp4,!**/*.{png,jpg,jpeg,gif,webp,ico,icns,mp4,zip}
📒 Files selected for processing (2)
apps/renderer/__tests__/components/Welcome.test.tsxapps/renderer/src/components/Welcome.tsx
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: build
🧰 Additional context used
📓 Path-based instructions (5)
**
⚙️ CodeRabbit configuration file
**: # Markdown ReaderA native desktop applicaion for reading Markdown files, built entirely on the JavaScript/TypeScript ecosystem using Electron as the desktop runtime.
markdown-reader is to Markdown what Adobe Acrobat Reader is to PDF:
a dedicated, native, first-class desktop viewer for .md files.Table of Contents
Why Markdown Reader ?
The Problem
Markdown is the most widely used plain-text writing format in the world.
Developers, writers, and teams produce millions of .md files daily.
Yet there is no dedicated desktop reader for Markdown that:
Missing Capability Current Workaround Pain Level Opens .md files natively on double-click No default handler — opens as raw text High Renders beautifully like a document VS Code preview pane feels like a dev tool Medium Has a sidebar TOC like a PDF reader Manual heading scanning Medium Supports all Markdown features GitHub renders some, browsers render none High Works fully offline Must open a browser manually High Feels like a reader, not an editor Every tool adds edit affordances Medium VS Code is an editor. GitHub is a web interface. Obsidian is a note-taking vault.
None of them are just a reader — a clean, dedicated app for opening and
reading Markdown files.The Solution
markdown-reader is a dedicated native desktop Markdown reader:
- Double-click any .md file and it opens in markdown-reader
- Registered as the system default application for .md files on install
- Beautiful readable typography — not a developer tool aesthetic
- Full M...
Files:
apps/renderer/src/components/Welcome.tsxapps/renderer/__tests__/components/Welcome.test.tsx
apps/renderer/src/**/*.{ts,tsx}
⚙️ CodeRabbit configuration file
apps/renderer/src/**/*.{ts,tsx}: Review as React renderer code.
- Keep components typed, accessible, keyboard-friendly, and resilient to missing preload APIs.
- Effects must have correct dependencies and cleanup.
- Handle loading, empty, error, stale-response, and rejected-promise states.
- Do not import Node-only modules into renderer code.
- Avoid unnecessary derived state, unsafe globals, and broad any types.
Files:
apps/renderer/src/components/Welcome.tsx
apps/renderer/src/**/*.{css,tsx}
⚙️ CodeRabbit configuration file
apps/renderer/src/**/*.{css,tsx}: Review UI, theme, and accessibility.
- Interactive controls need semantic elements, visible focus, and keyboard access.
- Theme changes must preserve readable contrast in light and dark modes.
- Markdown prose must remain readable for tables, code, blockquotes, links, lists, and images.
- Prefer existing tokens/classes over ad hoc inline styling.
Files:
apps/renderer/src/components/Welcome.tsx
**/*.{test,spec}.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Write unit tests for all new features to maintain code quality, adding test cases alongside component source code and ensuring all tests pass via
pnpm vitest
Files:
apps/renderer/__tests__/components/Welcome.test.tsx
**/*.{test,spec}.{ts,tsx}
⚙️ CodeRabbit configuration file
**/*.{test,spec}.{ts,tsx}: Review tests.
- Cover success and failure paths, especially IPC, filesystem, markdown rendering, search, settings, tabs, and exports.
- Use isolated temp directories for disk tests and clean them up.
- Mock Electron/preload APIs explicitly.
- Prefer Testing Library user-event and getByRole for UI tests.
Files:
apps/renderer/__tests__/components/Welcome.test.tsx
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T15:31:32.763Z
Learning: Implement the application entirely within the JavaScript/TypeScript ecosystem; do not introduce Rust, Go, or C++ components.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T15:31:32.763Z
Learning: Keep the app fully offline-first with zero cloud dependencies, zero telemetry, and zero accounts.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T15:31:32.763Z
Learning: Use GitHub Actions for CI/CD, including build, lint, typecheck, and test checks on pull requests and pushes to main and dev.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T15:31:32.763Z
Learning: Create production releases from Git tags and publish installers/release artifacts through the release pipeline.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T15:31:51.249Z
Learning: The Chrome extension should open the Markdown Reader as a full-page browser tab launched from the Chrome toolbar.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T15:31:51.249Z
Learning: The extension must let users choose local `.md` or `.markdown` files through the browser file picker instead of relying on direct local-file watching or desktop-style filesystem access.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T15:31:51.249Z
Learning: Keep the opened Markdown content only in a temporary runtime cache for the current session, and persist only recent-file metadata and settings in Chrome storage.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T15:31:51.249Z
Learning: Persist recent-file tracking in Chrome storage.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T15:31:51.249Z
Learning: Reuse shared Markdown Reader product code where possible so the browser extension and desktop app stay behaviorally consistent.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T15:31:51.249Z
Learning: Treat live reload, folder browsing, native save dialogs, and some export flows as desktop-only or browser-limited features in the Chrome extension.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T15:31:56.633Z
Learning: The Chrome extension should open a full-page Markdown Reader tab from the toolbar and use the shared Markdown Reader interface so the browser and desktop experiences stay consistent.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T15:31:56.633Z
Learning: The extension must let users choose local `.md` or `.markdown` files through the browser file picker, because browsers restrict direct local-file access.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T15:31:56.633Z
Learning: After a file is chosen, keep the opened content only in a temporary runtime cache for the current session.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T15:31:56.633Z
Learning: Persist only recent-file metadata and settings in Chrome storage; do not persist the full opened file content there.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T15:31:56.633Z
Learning: Use Chrome storage for recent-file tracking and settings, and keep the extension local-first with no account sign-in or cloud upload.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T15:31:56.633Z
Learning: Chrome-extension limitations are intentional: live reload, arbitrary local-file watching, native folder browsing, and some export/save flows are desktop-only or less complete in the browser.
🔇 Additional comments (1)
apps/renderer/src/components/Welcome.tsx (1)
49-50: LGTM!Also applies to: 84-151
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/renderer/index.html`:
- Line 12: Remove remote HTTPS image loading from the renderer CSP in the
index.html content security policy so the desktop app stays offline-first; keep
only local sources such as self, data:, and blob: in img-src, and move any
remote-image allowance behind an explicit opt-in mechanism outside the base
policy. Update the CSP entry in the renderer HTML accordingly, using the
existing content meta tag as the target for the change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: b008a207-9cbe-45f6-bde8-b23073170471
📒 Files selected for processing (4)
.github/workflows/release.ymlapps/extension/popup.htmlapps/extension/viewer.htmlapps/renderer/index.html
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
- GitHub Check: build
🧰 Additional context used
📓 Path-based instructions (2)
**
⚙️ CodeRabbit configuration file
**: # Markdown ReaderA native desktop applicaion for reading Markdown files, built entirely on the JavaScript/TypeScript ecosystem using Electron as the desktop runtime.
markdown-reader is to Markdown what Adobe Acrobat Reader is to PDF:
a dedicated, native, first-class desktop viewer for .md files.Table of Contents
Why Markdown Reader ?
The Problem
Markdown is the most widely used plain-text writing format in the world.
Developers, writers, and teams produce millions of .md files daily.
Yet there is no dedicated desktop reader for Markdown that:
Missing Capability Current Workaround Pain Level Opens .md files natively on double-click No default handler — opens as raw text High Renders beautifully like a document VS Code preview pane feels like a dev tool Medium Has a sidebar TOC like a PDF reader Manual heading scanning Medium Supports all Markdown features GitHub renders some, browsers render none High Works fully offline Must open a browser manually High Feels like a reader, not an editor Every tool adds edit affordances Medium VS Code is an editor. GitHub is a web interface. Obsidian is a note-taking vault.
None of them are just a reader — a clean, dedicated app for opening and
reading Markdown files.The Solution
markdown-reader is a dedicated native desktop Markdown reader:
- Double-click any .md file and it opens in markdown-reader
- Registered as the system default application for .md files on install
- Beautiful readable typography — not a developer tool aesthetic
- Full M...
Files:
apps/extension/viewer.htmlapps/renderer/index.htmlapps/extension/popup.html
.github/workflows/**/*.yml
⚙️ CodeRabbit configuration file
.github/workflows/**/*.yml: Review CI/CD.
- Actions should use version tags, not
@main.- Secrets must use ${{ secrets.* }} and never be hardcoded.
- CI should install with pinned pnpm, then run lint, typecheck, tests, build, and package checks.
- Security scans should fail for high/critical findings unless justified.
Files:
.github/workflows/release.yml
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T16:54:35.950Z
Learning: Implement markdown-reader entirely in the JavaScript/TypeScript ecosystem (Electron-based); do not introduce Rust, Go, or C++ components.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T16:54:49.912Z
Learning: The Chrome extension should open the Markdown Reader as a full-page browser tab from the Chrome toolbar.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T16:54:49.912Z
Learning: The extension should let users choose local `.md` or `.markdown` files through the browser file picker instead of trying to access arbitrary local files directly.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T16:54:49.912Z
Learning: After a file is opened, the extension should keep the content in temporary runtime cache for the current session and persist only recent-file metadata and settings in Chrome storage.
Learnt from: CR
Repo: mindfiredigital/markdown-reader
Timestamp: 2026-06-24T16:54:49.912Z
Learning: The browser extension should remain browser-safe and not rely on desktop-only capabilities such as live reload of arbitrary local files, native folder browsing, or platform-dependent save/export flows.
📚 Learning: 2026-06-23T09:45:44.974Z
Learnt from: Ashminita28
Repo: mindfiredigital/markdown-reader PR: 124
File: apps/extension/popup.html:6-6
Timestamp: 2026-06-23T09:45:44.974Z
Learning: In this repo, the Chrome extension (apps/extension/) does not keep icon PNGs in the source tree. Reviewers should assume icon files referenced from extension HTML (e.g., popup.html, viewer.html paths like icons/icon-32x32px.png) are provided at runtime by the build step that copies PNGs from apps/renderer/public/icons/ into the built extension bundle’s icons/ directory. Do not flag missing apps/extension/icons in the source tree; instead, verify that the build/copy step still runs and that any changes to icon paths keep them consistent with the copy destination.
Applied to files:
apps/extension/viewer.htmlapps/extension/popup.html
🔇 Additional comments (1)
.github/workflows/release.yml (1)
195-217: LGTM!
Description
This PR solves several architectural abstraction leaks, performance bugs, and dead-code paths that need fixing.
Type of Change
Related Issue
Closes #118, #119, #120, #121, #122, #123
Changes Made
Checklist
Electron main/preload
BrowserLocalStorageAdapter.setItemto catchQuotaExceededError, warn instead of crashing, and rethrow other failures.Renderer UI
wordCount,lineCount, andbyteSizewithuseMemokeyed by themarkdownprop to prevent per-render recomputation.buttonwithtype="button".onOpenRecentactions and formatted metadata/badges.isExtensiongating), improved export dropdown ARIA wiring, and log export failures instead of silently swallowing.api.readFile,api.openFileDialog).loadFileInTabfailures.showSaveDialogwhere required).undefinedwhere appropriate.Markdown rendering
[!INFO],[!IMPORTANT], and[!CAUTION]emoji/class conversions.Shared packages (platform adapters / extension plumbing)
PlatformAdapter(showSaveDialog,exportHTML,exportPDF,exportDOCX,onUpdateAvailable,downloadUpdate), keepinggetPathForFilerequired.null.chromeApi.runtime.onMessagehandlers before re-registering foronFileChanged/onOpenFilePath.sendMessageto throw whenruntime.sendMessage(...)returns a falsy/undefined response.exportHTML/exportPDFnow follow safer assembly/print semantics;downloadUpdateis unsupported; removedshowSaveDialogandexportDOCXfrom the adapter implementation.CHROME_MESSAGE_TYPESentries from the unsupported set.extension-release.zip).Tests
fireEventto@testing-library/user-event, updated click flow assertions to be async, and consolidated extension-mode expectations.userEvent.userEvent.statsuccess vsENOENTfailure.sendMessage-undefined rejection test.downloadUpdatetest to expect the “not supported” error.Tooling/CI
Docs
extension-release.zipartifact naming and clarified local-file caching behavior).Packaging
icons/icon-32x32px.png) instead of the prior SVG reference.Breaking changes: None