Skip to content

Fix/system hardening - #124

Merged
mind-murtaza merged 38 commits into
devfrom
fix/system-hardening
Jun 24, 2026
Merged

mind-murtaza merged 38 commits into
devfrom
fix/system-hardening

Conversation

@Ashminita28

@Ashminita28 Ashminita28 commented Jun 23, 2026 •

Copy link
Copy Markdown
Collaborator

Description

This PR solves several architectural abstraction leaks, performance bugs, and dead-code paths that need fixing.

Type of Change

  • Bug fix
  • New feature
  • Refactor (no functional change)
  • Documentation update
  • Style / UI change
  • Build / CI change

Related Issue

Closes #118, #119, #120, #121, #122, #123

Changes Made

  • memoized document statistics in ReaderStats:- 6ad4383
  • removed optional chainig on required platformadaptors methods in useFile:- 8f53a91
  • marked desktop only methods as optional in platform adapter interface:- 90a1c38
  • corrected zip filename and clarify storage caching behavior:- 3af57ed
  • handle QuotaExceededError in BrowserLocalStorageAdapter:- f4f01d9
  • fixed invalid ARIA nesting and add explicit button types in welcome component:- a61a9d7
  • handled file picker cancel event to prevent hanging promises:- 6674b0a
  • prevented listeners leaks in onFileChanged and onOpenFilePath:-0ad0af2
  • guarded sendMessage against undefined runtime response:- 8c8083c

Checklist

  • My code follows the project's coding guidelines
  • I have tested my changes locally
  • I have used conventional commit messages
  • I have updated documentation if needed
  • My changes do not introduce new warnings or errors

Electron main/preload

  • packages/platform-adapters/src/adapters/electron-adapter.ts: Hardened BrowserLocalStorageAdapter.setItem to catch QuotaExceededError, warn instead of crashing, and rethrow other failures.
  • packages/platform-adapters/tests/electron-adapter.test.ts: Added coverage ensuring Electron preload adapter methods forward/rethrow IPC errors without swallowing.

Renderer UI

  • apps/renderer/src/components/ReaderStats.tsx: Memoized wordCount, lineCount, and byteSize with useMemo keyed by the markdown prop to prevent per-render recomputation.
  • apps/renderer/src/components/Welcome.tsx: Fixed invalid interactive nesting and strengthened semantics/accessibility:
    • Ensured “Open File” uses a real button with type="button".
    • Restructured the desktop browse/drop target to avoid nested interactive elements.
    • Added/updated extension-only “Recent” list (up to 5 items) with onOpenRecent actions and formatted metadata/badges.
  • apps/renderer/src/components/ReaderToolbar.tsx: Render controls based on callback presence (not isExtension gating), improved export dropdown ARIA wiring, and log export failures instead of silently swallowing.
  • apps/renderer/src/hooks/useFile.ts: Removed optional chaining for required platform adapter methods (api.readFile, api.openFileDialog).
  • apps/renderer/src/hooks/useFileActions.ts: Added explicit error handling for folder/file dialogs and loadFileInTab failures.
  • apps/renderer/src/hooks/useWatcher.ts: Changed watcher setup/teardown promise rejections from silent ignore to console warnings.
  • apps/renderer/src/hooks/useExport.ts: Removed Chrome-extension-specific export flows; now gates exports strictly by platform API capabilities (and showSaveDialog where required).
  • apps/renderer/src/hooks/useMenuEvents.ts: Registers export menu handlers only when corresponding callbacks exist.
  • apps/renderer/src/types/component-types.ts / apps/renderer/src/types/hook-types.ts: Tightened export-related prop types to allow undefined where appropriate.

Markdown rendering

  • apps/renderer/src/utils/constants/style-constants.ts: Updated callout emoji mappings (NOTE/IMPORTANT) and added INFO.
  • apps/renderer/tests/renderer/callout.test.ts: Strengthened callout parsing assertions, including [!INFO], [!IMPORTANT], and [!CAUTION] emoji/class conversions.

Shared packages (platform adapters / extension plumbing)

  • packages/platform-adapters/src/types/platform-type.ts: Marked desktop-only adapter methods as optional in PlatformAdapter (showSaveDialog, exportHTML, exportPDF, exportDOCX, onUpdateAvailable, downloadUpdate), keeping getPathForFile required.
  • packages/platform-adapters/src/adapters/chrome-adapter.ts:
    • Updated menu listener lifecycle to support multiple listeners per event with correct per-listener disposal.
    • Handled browser file picker cancellation by removing the input and resolving null.
    • Corrected file content caching key usage and improved storage-caching behavior with quota/limit awareness (transient caching when persistence fails).
    • Prevented listener leaks by defensively removing prior chromeApi.runtime.onMessage handlers before re-registering for onFileChanged / onOpenFilePath.
    • Hardened sendMessage to throw when runtime.sendMessage(...) returns a falsy/undefined response.
    • Adjusted export/download behavior: exportHTML/exportPDF now follow safer assembly/print semantics; downloadUpdate is unsupported; removed showSaveDialog and exportDOCX from the adapter implementation.
  • apps/extension/src/utils/helpers/message-handler.ts: Reduced false “desktop-only” blocking by removing multiple CHROME_MESSAGE_TYPES entries from the unsupported set.
  • docs/docs/product/browser-extension.md and docs/versioned_docs/version-1.0.0/product/browser-extension.md: Clarified that opened local Markdown content is kept only in a temporary in-session runtime cache, while only recent metadata/settings persist to Chrome storage (and updated the referenced bundle artifact name to extension-release.zip).

Tests

  • apps/renderer/tests/components/Welcome.test.tsx: Migrated interactions from fireEvent to @testing-library/user-event, updated click flow assertions to be async, and consolidated extension-mode expectations.
  • apps/renderer/tests/components/Sidebar.test.tsx: Migrated TOC click to userEvent.
  • apps/renderer/tests/components/TabBar.test.tsx: Migrated tab switching/closing to userEvent.
  • apps/main-processor/tests/recent.test.ts: Expanded recent-item enrichment coverage by testing stat success vs ENOENT failure.
  • packages/platform-adapters/tests/chrome-adapter.test.ts:
    • Updated file picker expectations (timestamp-prefixed path) and assertions.
    • Added multi-menu-listener cleanup test to ensure no listener leaks.
    • Added sendMessage-undefined rejection test.
    • Updated downloadUpdate test to expect the “not supported” error.

Tooling/CI

  • .github/workflows/release.yml: Disabled GitHub Actions credential persistence for key jobs and tightened artifact download/publishing to target specific Electron and Chrome artifacts.

Docs

  • Updated multiple doc/README sections to improve guidance on IPC/API routing, fenced code block language tags, and installation/release instructions (including the extension-release.zip artifact naming and clarified local-file caching behavior).

Packaging

  • apps/extension/popup.html and apps/extension/viewer.html: Updated favicon links to use the PNG asset (icons/icon-32x32px.png) instead of the prior SVG reference.

Breaking changes: None

@coderabbitai

coderabbitai Bot commented Jun 23, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This 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.

Changes

Platform adapter and renderer export flow

Layer / File(s) Summary
Adapter contracts and storage quota
packages/platform-adapters/src/types/platform-type.ts, packages/platform-adapters/src/adapters/electron-adapter.ts, packages/platform-adapters/__tests__/electron-adapter.test.ts
PlatformAdapter marks export/update methods optional, BrowserLocalStorageAdapter catches quota failures, and adapter error propagation is tested.
ChromeAdapter file and runtime lifecycle
packages/platform-adapters/src/adapters/chrome-adapter.ts, packages/platform-adapters/__tests__/chrome-adapter.test.ts, apps/extension/src/utils/helpers/message-handler.ts
Chrome file opening, listener management, exports, unsupported-update handling, and falsy message responses change together, with matching adapter tests and narrower extension-side message blocking.
Renderer export and platform hooks
apps/renderer/src/hooks/useFile.ts, apps/renderer/src/hooks/useExport.ts, apps/renderer/src/hooks/useMenuEvents.ts, apps/renderer/src/components/ReaderToolbar.tsx, apps/renderer/src/hooks/useFileActions.ts, apps/renderer/src/hooks/useWatcher.ts, apps/renderer/src/types/component-types.ts, apps/renderer/src/types/hook-types.ts
Renderer file loading, export gating, menu registration, toolbar controls, and dialog/watcher error handling are updated for the new platform API shape.

UI, tests, docs, and packaging

Layer / File(s) Summary
Welcome, stats, and recent files
apps/renderer/src/components/Welcome.tsx, apps/renderer/src/components/ReaderStats.tsx, apps/main-processor/__tests__/recent.test.ts, apps/renderer/__tests__/components/Welcome.test.tsx
Welcome rendering, recent-file display, stats memoization, recent-file size enrichment, and the related interaction tests are updated together.
Component interaction and callout coverage
apps/renderer/src/utils/constants/style-constants.ts, apps/renderer/__tests__/renderer/callout.test.ts, apps/renderer/__tests__/components/Sidebar.test.tsx, apps/renderer/__tests__/components/TabBar.test.tsx
Callout mappings and parser tests change together with Sidebar and TabBar interaction tests moving to userEvent.
Extension assets, docs, CSP, and release packaging
apps/extension/popup.html, apps/extension/viewer.html, apps/renderer/index.html, docs/docs/product/browser-extension.md, docs/versioned_docs/version-1.0.0/product/browser-extension.md, docs/docs/installation.mdx, docs/versioned_docs/version-1.0.0/installation.mdx, README.md, apps/extension/README.md, apps/main-processor/README.md, apps/preload/README.md, apps/renderer/README.md, .github/workflows/release.yml
Extension favicons, browser-extension and installation docs, README structure notes, renderer CSP image sources, and release artifact download steps are revised together.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • mind-murtaza
🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is too vague and doesn't describe the actual change set. Use a specific title like “Memoize ReaderStats document statistics”.},{
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/system-hardening

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Expand tests for new Recent behavior in Welcome.

The suite does not validate the newly introduced recent-item interactions/constraints (e.g., invoking onOpenRecent and 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

📥 Commits

Reviewing files that changed from the base of the PR and between 64b40a1 and 8c8083c.

📒 Files selected for processing (12)
  • apps/extension/popup.html
  • apps/extension/viewer.html
  • apps/renderer/__tests__/components/Welcome.test.tsx
  • apps/renderer/src/components/ReaderStats.tsx
  • apps/renderer/src/components/Welcome.tsx
  • apps/renderer/src/hooks/useFile.ts
  • apps/renderer/src/utils/constants/style-constants.ts
  • docs/docs/product/browser-extension.md
  • docs/versioned_docs/version-1.0.0/product/browser-extension.md
  • packages/platform-adapters/src/adapters/chrome-adapter.ts
  • packages/platform-adapters/src/adapters/electron-adapter.ts
  • packages/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 Reader

A 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.html
  • apps/extension/viewer.html
  • apps/renderer/__tests__/components/Welcome.test.tsx
  • docs/versioned_docs/version-1.0.0/product/browser-extension.md
  • apps/renderer/src/components/ReaderStats.tsx
  • apps/renderer/src/hooks/useFile.ts
  • packages/platform-adapters/src/adapters/electron-adapter.ts
  • docs/docs/product/browser-extension.md
  • packages/platform-adapters/src/types/platform-type.ts
  • packages/platform-adapters/src/adapters/chrome-adapter.ts
  • apps/renderer/src/utils/constants/style-constants.ts
  • apps/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.tsx
  • apps/renderer/src/components/ReaderStats.tsx
  • apps/renderer/src/hooks/useFile.ts
  • packages/platform-adapters/src/adapters/electron-adapter.ts
  • packages/platform-adapters/src/types/platform-type.ts
  • packages/platform-adapters/src/adapters/chrome-adapter.ts
  • apps/renderer/src/utils/constants/style-constants.ts
  • apps/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.tsx
  • apps/renderer/src/components/ReaderStats.tsx
  • apps/renderer/src/hooks/useFile.ts
  • apps/renderer/src/utils/constants/style-constants.ts
  • apps/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.tsx
  • apps/renderer/src/components/ReaderStats.tsx
  • apps/renderer/src/hooks/useFile.ts
  • apps/renderer/src/utils/constants/style-constants.ts
  • apps/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 Docs

Docusaurus documentation and marketing site for Markdown Reader.

Run locally

pnpm install
pnpm start

Build

pnpm build

Files:

  • docs/versioned_docs/version-1.0.0/product/browser-extension.md
  • docs/docs/product/browser-extension.md
docs/versioned_docs/version-1.0.0/**

⚙️ CodeRabbit configuration file

docs/versioned_docs/version-1.0.0/**: ---
title: Architecture

Architecture 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.api object.
  • 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:

  1. Renderer initiates the request by invoking the readFile(path) function on the bridge API.
  2. Preload Bridge translates this function call into a secure background communication token named IPC READ_FILE and forwards it to the main environment.
  3. Main Process intercepts the token and instantly runs security checks to validate both the message sender and the requested filesystem path safety.
  4. Main Process queries the Filesystem to read the specific markdown file text on the disk.
  5. Filesystem reads the hard drive storage and returns the raw file content bytes back up to the Main Process.
  6. 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 Extension

Browser 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 .md or .markdown file 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:

  1. Download the extension bundle file (markdown-reader-extension.zip) from the latest repository releases section.
  2. Unzip or extract the folder to a safe location on your computer (e.g., your Documents folder).
  3. 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.md
  • docs/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.tsx
  • apps/renderer/src/hooks/useFile.ts
  • apps/renderer/src/utils/constants/style-constants.ts
  • 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/ReaderStats.tsx
  • apps/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: Architecture

Architecture 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.api object.
  • 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:

  1. Renderer initiates the request by invoking the readFile(path) function on the bridge API.
  2. Preload Bridge translates this function call into a secure background communication token named IPC READ_FILE and forwards it to the main environment.
  3. Main Process intercepts the token and instantly runs security checks to validate both the message sender and the requested filesystem path safety.
  4. Main Process queries the Filesystem to read the specific markdown file text on the disk.
  5. Filesystem reads the hard drive storage and returns the raw file content bytes back up to the Main Process.
  6. 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 Extension

Browser 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 .md or .markdown file 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:

  1. Download the extension bundle file (markdown-reader-extension.zip) from the latest repository releases section.
  2. Unzip or extract the folder to a safe location on your computer (e.g., your Documents folder).
  3. 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

Comment thread apps/extension/popup.html
Comment thread apps/renderer/src/components/ReaderStats.tsx Outdated
Comment thread apps/renderer/src/components/Welcome.tsx
Comment thread apps/renderer/src/utils/constants/style-constants.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Clear stale transientFiles entries 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 from transientFiles when setItem() 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

📥 Commits

Reviewing files that changed from the base of the PR and between 8c8083c and c90baff.

📒 Files selected for processing (13)
  • README.md
  • apps/extension/README.md
  • apps/extension/src/utils/helpers/message-handler.ts
  • apps/main-processor/README.md
  • apps/preload/README.md
  • apps/renderer/README.md
  • apps/renderer/__tests__/renderer/callout.test.ts
  • apps/renderer/src/components/ReaderStats.tsx
  • apps/renderer/src/components/Welcome.tsx
  • apps/renderer/src/hooks/useFileActions.ts
  • apps/renderer/src/hooks/useWatcher.ts
  • packages/platform-adapters/__tests__/chrome-adapter.test.ts
  • packages/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 Reader

A 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.ts
  • apps/renderer/src/hooks/useFileActions.ts
  • apps/main-processor/README.md
  • packages/platform-adapters/__tests__/chrome-adapter.test.ts
  • apps/renderer/README.md
  • apps/preload/README.md
  • README.md
  • apps/renderer/__tests__/renderer/callout.test.ts
  • apps/extension/README.md
  • apps/renderer/src/components/ReaderStats.tsx
  • apps/renderer/src/components/Welcome.tsx
  • packages/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.ts
  • apps/renderer/src/hooks/useFileActions.ts
  • apps/renderer/src/components/ReaderStats.tsx
  • 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:

  • packages/platform-adapters/__tests__/chrome-adapter.test.ts
  • apps/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.ts
  • apps/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.tsx
  • apps/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!

Comment thread apps/renderer/README.md
Comment thread packages/platform-adapters/__tests__/chrome-adapter.test.ts
Comment thread packages/platform-adapters/src/adapters/chrome-adapter.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Keep the recent-file identity stable across edits.

Line 125 now bakes size and lastModified into the persisted path, but addRecentFile() deduplicates recents by exact path. 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

📥 Commits

Reviewing files that changed from the base of the PR and between c90baff and 14c5bca.

📒 Files selected for processing (15)
  • .github/workflows/release.yml
  • apps/main-processor/__tests__/recent.test.ts
  • apps/renderer/__tests__/components/Sidebar.test.tsx
  • apps/renderer/__tests__/components/TabBar.test.tsx
  • apps/renderer/__tests__/components/Welcome.test.tsx
  • apps/renderer/src/components/ReaderToolbar.tsx
  • apps/renderer/src/components/Welcome.tsx
  • apps/renderer/src/hooks/useExport.ts
  • apps/renderer/src/hooks/useMenuEvents.ts
  • apps/renderer/src/types/component-types.ts
  • apps/renderer/src/types/hook-types.ts
  • docs/docs/installation.mdx
  • docs/versioned_docs/version-1.0.0/installation.mdx
  • packages/platform-adapters/__tests__/electron-adapter.test.ts
  • packages/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.tsx
  • packages/platform-adapters/__tests__/electron-adapter.test.ts
  • apps/renderer/__tests__/components/Welcome.test.tsx
  • apps/renderer/__tests__/components/TabBar.test.tsx
  • apps/main-processor/__tests__/recent.test.ts
**

⚙️ CodeRabbit configuration file

**: # Markdown Reader

A 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.tsx
  • packages/platform-adapters/__tests__/electron-adapter.test.ts
  • apps/renderer/src/types/component-types.ts
  • apps/renderer/src/hooks/useMenuEvents.ts
  • apps/renderer/src/types/hook-types.ts
  • apps/renderer/__tests__/components/Welcome.test.tsx
  • apps/renderer/__tests__/components/TabBar.test.tsx
  • apps/renderer/src/hooks/useExport.ts
  • docs/versioned_docs/version-1.0.0/installation.mdx
  • apps/main-processor/__tests__/recent.test.ts
  • apps/renderer/src/components/ReaderToolbar.tsx
  • docs/docs/installation.mdx
  • packages/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.tsx
  • packages/platform-adapters/__tests__/electron-adapter.test.ts
  • apps/renderer/__tests__/components/Welcome.test.tsx
  • apps/renderer/__tests__/components/TabBar.test.tsx
  • apps/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.ts
  • apps/renderer/src/hooks/useMenuEvents.ts
  • apps/renderer/src/types/hook-types.ts
  • apps/renderer/src/hooks/useExport.ts
  • apps/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 Docs

Docusaurus documentation and marketing site for Markdown Reader.

Run locally

pnpm install
pnpm start

Build

pnpm build

Files:

  • docs/versioned_docs/version-1.0.0/installation.mdx
  • docs/docs/installation.mdx
docs/versioned_docs/version-1.0.0/**

⚙️ CodeRabbit configuration file

docs/versioned_docs/version-1.0.0/**: ---
title: Architecture

Architecture 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.api object.
  • 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:

  1. Renderer initiates the request by invoking the readFile(path) function on the bridge API.
  2. Preload Bridge translates this function call into a secure background communication token named IPC READ_FILE and forwards it to the main environment.
  3. Main Process intercepts the token and instantly runs security checks to validate both the message sender and the requested filesystem path safety.
  4. Main Process queries the Filesystem to read the specific markdown file text on the disk.
  5. Filesystem reads the hard drive storage and returns the raw file content bytes back up to the Main Process.
  6. 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.mdx
  • docs/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: Architecture

Architecture 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.api object.
  • 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:

  1. Renderer initiates the request by invoking the readFile(path) function on the bridge API.
  2. Preload Bridge translates this function call into a secure background communication token named IPC READ_FILE and forwards it to the main environment.
  3. Main Process intercepts the token and instantly runs security checks to validate both the message sender and the requested filesystem path safety.
  4. Main Process queries the Filesystem to read the specific markdown file text on the disk.
  5. Filesystem reads the hard drive storage and returns the raw file content bytes back up to the Main Process.
  6. 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 & Privacy

No 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.

Comment thread apps/renderer/__tests__/components/Sidebar.test.tsx
Comment thread apps/renderer/__tests__/components/TabBar.test.tsx
Comment thread apps/renderer/src/components/ReaderToolbar.tsx
Comment thread apps/renderer/src/hooks/useMenuEvents.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Add 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

📥 Commits

Reviewing files that changed from the base of the PR and between 14c5bca and 18f6f02.

⛔ Files ignored due to path filters (1)
  • docs/static/video/windows-install.mp4 is excluded by !**/*.mp4, !**/*.{png,jpg,jpeg,gif,webp,ico,icns,mp4,zip}
📒 Files selected for processing (2)
  • apps/renderer/__tests__/components/Welcome.test.tsx
  • 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 (5)
**

⚙️ CodeRabbit configuration file

**: # Markdown Reader

A 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.tsx
  • apps/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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 18f6f02 and 0d1974d.

📒 Files selected for processing (4)
  • .github/workflows/release.yml
  • apps/extension/popup.html
  • apps/extension/viewer.html
  • apps/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 Reader

A 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.html
  • apps/renderer/index.html
  • apps/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.html
  • apps/extension/popup.html
🔇 Additional comments (1)
.github/workflows/release.yml (1)

195-217: LGTM!

Comment thread apps/renderer/index.html Outdated
@mind-murtaza
mind-murtaza merged commit 4d8c69a into dev Jun 24, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants