Feature/folder search#88
Conversation
…dden for production
|
Warning Review limit reached
More reviews will be available in 31 minutes and 34 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (4)
✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/renderer/src/hooks/useShortcuts.ts (1)
28-38:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDuplicate
mod+shift+fcondition makes focus-mode shortcut unreachable.Line 34 reuses the exact same predicate as Line 28, so that branch never executes after the early
returnat Line 31. This silently breaksonToggleFocusMode()keyboard access. Use a distinct shortcut for one action (or remove the stale branch).Suggested fix
- if (mod && e.shiftKey && e.key.toLowerCase() === 'f') { - e.preventDefault(); - onToggleFocusMode(); - return; - } + if (mod && e.shiftKey && e.key.toLowerCase() === 'm') { + e.preventDefault(); + onToggleFocusMode(); + return; + }As per coding guidelines, "apps/renderer/src/**/*.{ts,tsx}: ... keyboard-friendly ...".
🤖 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/src/hooks/useShortcuts.ts` around lines 28 - 38, The duplicate keyboard predicate (mod && e.shiftKey && e.key.toLowerCase() === 'f') makes the onToggleFocusMode() branch unreachable; update the shortcut logic in useShortcuts.ts by either changing the second predicate to a distinct key combination (e.g., use a different key or remove the shift/mod as appropriate) or removing the stale branch so onOpenFolderSearch() and onToggleFocusMode() have unique conditions; update the checks referencing mod, e.shiftKey, e.key.toLowerCase(), and call sites onOpenFolderSearch and onToggleFocusMode accordingly so both shortcuts are reachable and non-conflicting.
🤖 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/main-processor/__tests__/folder-search.test.ts`:
- Around line 7-17: Replace the fixed DIR constant and setup/teardown in the
test to use a unique temporary directory per run: create the temp dir with
mkdtempSync(path.join(tmpdir(), 'md-search-test-')) inside the beforeAll
(instead of mkdirSync on DIR) and store it in the same variable used by the
test, write files into that directory using writeFileSync(join(tempDir, ...)),
and remove it in afterAll using rmSync(tempDir, { recursive: true, force: true
}); update references to DIR in the test to use the new tempDir variable
(adjusting the beforeAll/afterAll hooks accordingly).
- Around line 19-41: Add a failure-path test for searchFolder that simulates a
filesystem error: mock fs.promises.readdir (or fs.readdirSync) to throw an
ENOENT or EACCES error before calling searchFolder(DIR, 'anything') and assert
the function propagates the error (use await
expect(searchFolder(...)).rejects.toThrow()). Name the test clearly (e.g.,
"throws when directory is unreadable") and ensure you restore/unmock fs after
the test so other tests are unaffected; reference the searchFolder function and
the test file's existing describe block to place the new it() case.
In `@apps/main-processor/src/folder-search.ts`:
- Around line 19-20: The current await readFile(filePath, 'utf-8') in
folder-search.ts can throw and abort the whole search; wrap the file read and
subsequent content.split(...) in a try/catch around readFile (referencing
readFile, filePath, content, lines) and on recoverable FS errors (e.g., ENOENT,
EACCES, EPERM, EISDIR, EMFILE) log a warning with the filePath and error and
continue to the next file, only rethrow or fail for truly unexpected errors;
ensure you do not let a single-file read failure propagate and stop processing
the rest of the folder.
In `@apps/main-processor/src/ipc.ts`:
- Around line 179-180: The code currently auto-authorizes renderer-supplied
folder paths by resolving folderPath and unconditionally adding safeFolderPath
into allowedFolderRoots in the SEARCH_FOLDER handling; instead, change the
SEARCH_FOLDER flow (the handler using resolveDirectoryPath and
allowedFolderRoots) to NOT add safeFolderPath automatically—validate that the
resolved safeFolderPath is already present in allowedFolderRoots (i.e., was
added only via explicit folder-open flow) and reject the request if it is not;
return/emit an error response when the root is unauthorized and ensure only the
explicit folder-open code path is allowed to mutate allowedFolderRoots.
In `@apps/main-processor/src/utils/helper/folder-search-helper.ts`:
- Around line 14-26: The traversal currently fails if readdir or a recursive
collectMarkdownFiles call throws; wrap the await readdir(folderPath, ...) call
in a try/catch and likewise wrap the recursive call to
collectMarkdownFiles(fullPath, ...) so recoverable FS errors (ENOENT, EACCES,
EPERM) are caught and cause the function to skip that folder/entry and continue,
while re-throwing unknown errors; keep using MARKDOWN_FILE_PATTERN, MAX_RESULTS
and entry checks (isSymbolicLink/isDirectory) unchanged so behavior stays the
same except for skipping unreadable/missing/permission-denied paths.
In `@apps/renderer/src/App.tsx`:
- Around line 122-143: The folder SearchBar is being seeded with the document
search `query` instead of the folder-specific `folderQuery`, causing wrong input
and empty-state logic; update the JSX where `SearchBar` is rendered (inside the
`isFolderSearchOpen` block) to pass `query={folderQuery}` instead of
`query={query}` and keep `onQueryChange={searchFolder}` (which updates the
folder query) so the component uses the folder-specific state; ensure references
to `SearchBar`, `isFolderSearchOpen`, `searchFolder`, and `folderQuery` are
adjusted accordingly.
- Around line 134-140: The onOpenFolderResult handler currently calls
loadFileInTab(result.filePath).then(...) without handling rejections; update the
onOpenFolderResult implementation so that loadFileInTab is awaited or its
promise uses .catch/.finally: ensure closeFolderSearch() is always called (use
finally) and surface a user-facing error/feedback when loadFileInTab rejects
(e.g., via existing toast/error UI or set an error state) instead of leaving the
folder search open and producing an unhandled rejection; reference the
loadFileInTab, openSearch, setQuery, and closeFolderSearch symbols when making
the change.
In `@apps/renderer/src/components/SearchBar.tsx`:
- Around line 114-153: The folder-mode UI in SearchBar.tsx is using the generic
prop query (and seeding localQuery from it) but the parent provides a separate
folderQuery; update SearchBar to use the folder-specific prop when isFolderMode
is true: replace usages of query (and the localQuery initial value) with
folderQuery for the folder-mode branches that render the empty-state message and
prefilled input, ensuring folderResults, isSearchingFolder, hasFolder and the
onOpenFolderResult handler remain wired up to the same UI elements so behavior
stays consistent.
In `@apps/renderer/src/hooks/useFolderSearch.ts`:
- Around line 17-34: searchFolder should guard against missing bridge, catch IPC
rejections, and ignore out-of-order responses: first check window.api and return
early if missing; increment a local request token (useRef like currentRequestId)
at the start of searchFolder, capture it in the async call, and only call
setFolderResults or setIsSearchingFolder(false) if the captured token matches
the latest; wrap the await window.api.searchFolder(folderPath, query) in
try/catch to prevent unhandled rejections and setFolderResults([]) or leave
results unchanged on error, and ensure setIsSearchingFolder is cleared in a
finally block that also checks the token to avoid clearing state for newer
requests (references: searchFolder, window.api.searchFolder, setFolderResults,
setIsSearchingFolder, folderPath, folderQuery).
In `@apps/renderer/src/hooks/useMenuEvents.ts`:
- Around line 30-31: Replace the comma-operator expression that registers both
listeners with two separate statements: call
window.api.onMenuEvent(MENU_EVENTS.SEARCH_FOLDER, onSearchFolder) on its own
line and window.api.onMenuEvent(MENU_EVENTS.TOGGLE_TOC, onToggleToc) on the next
line so the registration of MENU_EVENTS.SEARCH_FOLDER/onSearchFolder and
MENU_EVENTS.TOGGLE_TOC/onToggleToc is explicit and not wrapped in a
parenthesized comma expression.
---
Outside diff comments:
In `@apps/renderer/src/hooks/useShortcuts.ts`:
- Around line 28-38: The duplicate keyboard predicate (mod && e.shiftKey &&
e.key.toLowerCase() === 'f') makes the onToggleFocusMode() branch unreachable;
update the shortcut logic in useShortcuts.ts by either changing the second
predicate to a distinct key combination (e.g., use a different key or remove the
shift/mod as appropriate) or removing the stale branch so onOpenFolderSearch()
and onToggleFocusMode() have unique conditions; update the checks referencing
mod, e.shiftKey, e.key.toLowerCase(), and call sites onOpenFolderSearch and
onToggleFocusMode accordingly so both shortcuts are reachable and
non-conflicting.
🪄 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: 98c93dde-6ca5-4d82-83c7-3a7f4a16e8e9
📒 Files selected for processing (41)
apps/main-processor/__tests__/cli.test.tsapps/main-processor/__tests__/docx.test.tsapps/main-processor/__tests__/export.test.tsapps/main-processor/__tests__/file.test.tsapps/main-processor/__tests__/folder-search.test.tsapps/main-processor/__tests__/ipc.test.tsapps/main-processor/__tests__/menu.test.tsapps/main-processor/__tests__/recent.test.tsapps/main-processor/src/folder-search.tsapps/main-processor/src/ipc.tsapps/main-processor/src/utils/constants/folder-constants.tsapps/main-processor/src/utils/helper/folder-search-helper.tsapps/preload/src/index.tsapps/renderer/__tests__/components/Sidebar.test.tsxapps/renderer/__tests__/components/StatusBar.test.tsxapps/renderer/__tests__/components/TabBar.test.tsxapps/renderer/__tests__/components/Welcome.test.tsxapps/renderer/__tests__/hooks/useCollapsibleToc.test.tsapps/renderer/__tests__/hooks/useSearch.test.tsapps/renderer/__tests__/hooks/useSettings.test.tsapps/renderer/__tests__/renderer/callout.test.tsapps/renderer/__tests__/renderer/drag-drop.test.tsapps/renderer/__tests__/renderer/katex.test.tsapps/renderer/__tests__/renderer/markdown.test.tsapps/renderer/__tests__/renderer/mermaid.test.tsapps/renderer/__tests__/renderer/sanitize.test.tsapps/renderer/__tests__/renderer/sikhi.test.tsapps/renderer/__tests__/renderer/toc.test.tsapps/renderer/__tests__/store/tabStore.test.tsapps/renderer/src/App.tsxapps/renderer/src/components/SearchBar.tsxapps/renderer/src/hooks/useFileActions.tsapps/renderer/src/hooks/useFolderSearch.tsapps/renderer/src/hooks/useMenuEvents.tsapps/renderer/src/hooks/useShortcuts.tsapps/renderer/src/types/component-types.tsapps/renderer/src/types/hook-types.tspackages/shared-constants/src/ipc-constants.tspackages/shared-types/src/index.tspackages/shared-types/src/markdown-type.tspackages/shared-types/src/search-type.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use TypeScript as the primary language for the application
Files:
packages/shared-constants/src/ipc-constants.tsapps/main-processor/__tests__/folder-search.test.tsapps/main-processor/src/utils/helper/folder-search-helper.tsapps/main-processor/src/utils/constants/folder-constants.tsapps/renderer/src/hooks/useFileActions.tsapps/renderer/src/hooks/useFolderSearch.tsapps/main-processor/src/folder-search.tsapps/main-processor/src/ipc.tspackages/shared-types/src/search-type.tsapps/renderer/src/types/hook-types.tspackages/shared-types/src/markdown-type.tspackages/shared-types/src/index.tsapps/renderer/src/types/component-types.tsapps/preload/src/index.tsapps/renderer/src/hooks/useMenuEvents.tsapps/renderer/src/components/SearchBar.tsxapps/renderer/src/App.tsxapps/renderer/src/hooks/useShortcuts.ts
apps/main-processor/**/*.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use Marked for parsing Markdown content
Files:
apps/main-processor/__tests__/folder-search.test.tsapps/main-processor/src/utils/helper/folder-search-helper.tsapps/main-processor/src/utils/constants/folder-constants.tsapps/main-processor/src/folder-search.tsapps/main-processor/src/ipc.ts
**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use Vitest for testing
Files:
apps/main-processor/__tests__/folder-search.test.ts
⚙️ 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/main-processor/__tests__/folder-search.test.ts
**/*.{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/main-processor/__tests__/folder-search.test.ts
apps/main-processor/src/**/*.ts
⚙️ CodeRabbit configuration file
apps/main-processor/src/**/*.ts: Review as Electron main-process code.
- IPC handlers must use shared constants and validate renderer input.
- File/folder access must guard path traversal, missing files, permissions, symlinks, and deleted watched files.
- Watchers, menus, dialogs, and IPC listeners must be cleaned up.
- Do not expose Node/Electron internals or unrestricted filesystem access.
- Export/update/download flows must sanitize content, close resources, and avoid executing embedded scripts.
Files:
apps/main-processor/src/utils/helper/folder-search-helper.tsapps/main-processor/src/utils/constants/folder-constants.tsapps/main-processor/src/folder-search.tsapps/main-processor/src/ipc.ts
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/src/hooks/useFileActions.tsapps/renderer/src/hooks/useFolderSearch.tsapps/renderer/src/types/hook-types.tsapps/renderer/src/types/component-types.tsapps/renderer/src/hooks/useMenuEvents.tsapps/renderer/src/components/SearchBar.tsxapps/renderer/src/App.tsxapps/renderer/src/hooks/useShortcuts.ts
apps/renderer/**/*.{ts,tsx,css}
📄 CodeRabbit inference engine (README.md)
Use Tailwind CSS for styling
Files:
apps/renderer/src/hooks/useFileActions.tsapps/renderer/src/hooks/useFolderSearch.tsapps/renderer/src/types/hook-types.tsapps/renderer/src/types/component-types.tsapps/renderer/src/hooks/useMenuEvents.tsapps/renderer/src/components/SearchBar.tsxapps/renderer/src/App.tsxapps/renderer/src/hooks/useShortcuts.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/useFileActions.tsapps/renderer/src/hooks/useFolderSearch.tsapps/renderer/src/types/hook-types.tsapps/renderer/src/types/component-types.tsapps/renderer/src/hooks/useMenuEvents.tsapps/renderer/src/components/SearchBar.tsxapps/renderer/src/App.tsxapps/renderer/src/hooks/useShortcuts.ts
apps/preload/src/**/*.ts
⚙️ CodeRabbit configuration file
apps/preload/src/**/*.ts: Review as a strict preload boundary.
- Expose only typed contextBridge APIs, never raw ipcRenderer.
- Use shared IPC constants and shared payload/result types.
- Listener methods must return unsubscribe functions.
- Reject broad channel names, arbitrary invoke/send wrappers, and any-typed payloads.
Files:
apps/preload/src/index.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/SearchBar.tsxapps/renderer/src/App.tsx
🔇 Additional comments (9)
packages/shared-types/src/search-type.ts (1)
1-7: LGTM!packages/shared-types/src/index.ts (1)
6-6: LGTM!packages/shared-types/src/markdown-type.ts (1)
4-4: LGTM!Also applies to: 20-20
packages/shared-constants/src/ipc-constants.ts (1)
12-12: LGTM!apps/renderer/src/types/component-types.ts (1)
4-4: LGTM!Also applies to: 67-73
apps/main-processor/src/utils/constants/folder-constants.ts (1)
1-2: LGTM!apps/preload/src/index.ts (1)
18-18: LGTM!apps/renderer/src/types/hook-types.ts (1)
31-31: LGTM!Also applies to: 53-53
apps/renderer/src/hooks/useFileActions.ts (1)
7-7: LGTM!Also applies to: 10-16, 41-41
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/main-processor/src/ipc.ts (1)
174-187:⚠️ Potential issue | 🟠 Major | ⚡ Quick winValidate the IPC payload before resolving paths.
validateSenderauthenticates the caller, but it does not guarantee thatfolderPathandqueryare usable strings. A malformed payload reachesresolveDirectoryPath/searchFolderand can fail on the main-process boundary.Suggested fix
ipcMain.handle(IPC_CONSTANTS.SEARCH_FOLDER, async (event, folderPath: string, query: string) => { if (!validateSender(event)) { throw new Error('Untrusted sender'); } + if (typeof folderPath !== 'string' || typeof query !== 'string') { + throw new Error('Invalid search payload'); + } const safeFolderPath = await resolveDirectoryPath(folderPath); allowedFolderRoots.add(safeFolderPath);As per coding guidelines, “IPC handlers must use shared constants and validate renderer input.”
🤖 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/main-processor/src/ipc.ts` around lines 174 - 187, The IPC handler for IPC_CONSTANTS.SEARCH_FOLDER currently trusts folderPath and query after validateSender; add explicit validation and sanitization of the incoming payload before calling resolveDirectoryPath or searchFolder: verify folderPath and query are strings, non-empty, within max length, and match allowed pattern(s) (use the shared renderer-to-main validation utilities/constants), reject or throw a clear error for invalid types/values, and only then call resolveDirectoryPath(safeFolderPath) and proceed to allowedFolderRoots and searchFolder; reference the handler, validateSender, resolveDirectoryPath, searchFolder, and allowedFolderRoots when making the changes.
🤖 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/main-processor/__tests__/folder-search.test.ts`:
- Around line 42-46: The test title says the call should reject but the body
asserts an empty array; update the test for consistency by changing the
assertion to expect rejection: call searchFolder(nonExistentDir, 'React') via
Jest's promise matchers (await expect(searchFolder(...)).rejects.toThrow() or a
more specific error matcher) so the test truly verifies failure, and keep the
test name (or if you prefer to keep the current assertion, rename the it(...)
text to reflect that it returns an empty array); reference the searchFolder call
and the test description to make the change.
In `@apps/renderer/src/App.tsx`:
- Around line 140-141: The catch for loadFileInTab currently calls
setShowToast(true) which reuses the same toast used for the "File updated"
success message; change this to a dedicated error toast state (for example add
setShowErrorToast / showErrorToast or convert showToast to a typed toast object
like setToast({type:'error', message: '...'}) ) and update the component's
rendering logic where message="File updated" is used so success and error toasts
are rendered separately; ensure the catch block sets the error state and
supplies a clear error message while leaving the success toast untouched.
In `@apps/renderer/src/hooks/useFolderSearch.ts`:
- Around line 21-25: In useFolderSearch, when bailing out for empty/invalid
input (the branch that checks !folderPath || !query.trim() ||
!window.api?.searchFolder), invalidate any pending in-flight request by
advancing requestId.current (e.g., ++requestId.current) and set
isSearchingFolder to false before calling setFolderResults([]) and returning;
this ensures an older response cannot win later and repopulate folderResults for
an empty search.
---
Outside diff comments:
In `@apps/main-processor/src/ipc.ts`:
- Around line 174-187: The IPC handler for IPC_CONSTANTS.SEARCH_FOLDER currently
trusts folderPath and query after validateSender; add explicit validation and
sanitization of the incoming payload before calling resolveDirectoryPath or
searchFolder: verify folderPath and query are strings, non-empty, within max
length, and match allowed pattern(s) (use the shared renderer-to-main validation
utilities/constants), reject or throw a clear error for invalid types/values,
and only then call resolveDirectoryPath(safeFolderPath) and proceed to
allowedFolderRoots and searchFolder; reference the handler, validateSender,
resolveDirectoryPath, searchFolder, and allowedFolderRoots when making the
changes.
🪄 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: 9aaddd77-14ed-433e-bb14-b4fbc64fd2d7
📒 Files selected for processing (9)
apps/main-processor/__tests__/folder-search.test.tsapps/main-processor/src/folder-search.tsapps/main-processor/src/ipc.tsapps/main-processor/src/utils/helper/folder-search-helper.tsapps/renderer/src/App.tsxapps/renderer/src/components/SearchBar.tsxapps/renderer/src/hooks/useFolderSearch.tsapps/renderer/src/hooks/useMenuEvents.tsapps/renderer/src/types/component-types.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use TypeScript as the primary language for the application
Files:
apps/main-processor/__tests__/folder-search.test.tsapps/main-processor/src/ipc.tsapps/main-processor/src/utils/helper/folder-search-helper.tsapps/main-processor/src/folder-search.tsapps/renderer/src/hooks/useFolderSearch.tsapps/renderer/src/types/component-types.tsapps/renderer/src/components/SearchBar.tsxapps/renderer/src/App.tsxapps/renderer/src/hooks/useMenuEvents.ts
apps/main-processor/**/*.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use Marked for parsing Markdown content
Files:
apps/main-processor/__tests__/folder-search.test.tsapps/main-processor/src/ipc.tsapps/main-processor/src/utils/helper/folder-search-helper.tsapps/main-processor/src/folder-search.ts
**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use Vitest for testing
Files:
apps/main-processor/__tests__/folder-search.test.ts
⚙️ 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/main-processor/__tests__/folder-search.test.ts
**/*.{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/main-processor/__tests__/folder-search.test.ts
apps/main-processor/src/**/*.ts
⚙️ CodeRabbit configuration file
apps/main-processor/src/**/*.ts: Review as Electron main-process code.
- IPC handlers must use shared constants and validate renderer input.
- File/folder access must guard path traversal, missing files, permissions, symlinks, and deleted watched files.
- Watchers, menus, dialogs, and IPC listeners must be cleaned up.
- Do not expose Node/Electron internals or unrestricted filesystem access.
- Export/update/download flows must sanitize content, close resources, and avoid executing embedded scripts.
Files:
apps/main-processor/src/ipc.tsapps/main-processor/src/utils/helper/folder-search-helper.tsapps/main-processor/src/folder-search.ts
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/src/hooks/useFolderSearch.tsapps/renderer/src/types/component-types.tsapps/renderer/src/components/SearchBar.tsxapps/renderer/src/App.tsxapps/renderer/src/hooks/useMenuEvents.ts
apps/renderer/**/*.{ts,tsx,css}
📄 CodeRabbit inference engine (README.md)
Use Tailwind CSS for styling
Files:
apps/renderer/src/hooks/useFolderSearch.tsapps/renderer/src/types/component-types.tsapps/renderer/src/components/SearchBar.tsxapps/renderer/src/App.tsxapps/renderer/src/hooks/useMenuEvents.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/useFolderSearch.tsapps/renderer/src/types/component-types.tsapps/renderer/src/components/SearchBar.tsxapps/renderer/src/App.tsxapps/renderer/src/hooks/useMenuEvents.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/SearchBar.tsxapps/renderer/src/App.tsx
🔇 Additional comments (9)
apps/main-processor/__tests__/folder-search.test.ts (2)
7-17: Still using a shared temp directory.
tmpdir()/md-search-testcan collide across parallel Vitest runs. UsemkdtempSyncand clean up that unique directory in teardown. As per coding guidelines, “Use isolated temp directories for disk tests and clean them up.”
19-48: Still missing the per-file filesystem failure path.This suite covers a missing root directory, but it still does not exercise the recoverable
readFileerrors inapps/main-processor/src/folder-search.ts. Add a case where a discovered.mdfile becomes unreadable or disappears and assert the search skips it instead of aborting. As per coding guidelines, “Cover success and failure paths, especially IPC, filesystem, markdown rendering, search, settings, tabs, and exports.”apps/main-processor/src/ipc.ts (1)
179-186: This authorization check is still bypassed by Line 180.Adding
safeFolderPathtoallowedFolderRootsbefore thesome(...)check lets every resolved path authorize itself. Reject first, and only mutate the allow-list in the explicit folder-open flow. As per coding guidelines, “Do not expose Node/Electron internals or unrestricted filesystem access.”apps/renderer/src/types/component-types.ts (1)
109-109: LGTM!Also applies to: 120-128
apps/main-processor/src/utils/helper/folder-search-helper.ts (1)
14-22: LGTM!apps/main-processor/src/folder-search.ts (1)
19-26: LGTM!apps/renderer/src/hooks/useMenuEvents.ts (1)
30-31: LGTM!Also applies to: 64-65
apps/renderer/src/App.tsx (1)
124-127: LGTM!Also applies to: 187-187
apps/renderer/src/components/SearchBar.tsx (1)
27-30: LGTM!Also applies to: 62-62
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/renderer/src/hooks/useFolderSearch.ts (1)
12-17:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win
closeFolderSearchleavesisSearchingFolderstuck. It bumpsrequestId(good, so the in-flight response is ignored), but the in-flightfinallythen won't run itssetIsSearchingFolder(false)because the token no longer matches. Result: close during an active search and the loading flag staystrue, surfacing a phantom spinner on reopen.🛠️ Clear the flag on close
const closeFolderSearch = useCallback(() => { requestId.current += 1; setIsFolderSearchOpen(false); setFolderQuery(''); setFolderResults([]); + setIsSearchingFolder(false); }, []);🤖 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/src/hooks/useFolderSearch.ts` around lines 12 - 17, The closeFolderSearch callback currently increments requestId and clears query/results but doesn't clear the loading flag, leaving isSearchingFolder stuck true; update closeFolderSearch to also call setIsSearchingFolder(false) (alongside requestId.current += 1, setIsFolderSearchOpen(false), setFolderQuery(''), setFolderResults([])) so any visible spinner is cleared immediately when closing, ensuring the in-flight response being ignored won't leave the loading state set.
♻️ Duplicate comments (1)
apps/main-processor/__tests__/folder-search.test.ts (1)
7-17:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winStill using a fixed temp dir — collision risk across parallel runs.
DIRis a staticmd-search-testpath, so concurrent runs can clobber each other's fixtures. Switch to a per-runmkdtempSyncdirectory and clean it up in teardown.🧹 Proposed fix
-import { writeFileSync, mkdirSync, rmSync } from 'node:fs'; +import { writeFileSync, mkdtempSync, rmSync } from 'node:fs'; import { join } from 'node:path'; import { tmpdir } from 'node:os'; import { searchFolder } from '../src/folder-search'; -const DIR = join(tmpdir(), 'md-search-test'); +let DIR: string; beforeAll(() => { - mkdirSync(DIR, { recursive: true }); + DIR = mkdtempSync(join(tmpdir(), 'md-search-test-')); writeFileSync(join(DIR, 'README.md'), '# Project\nThis project uses React.\nReact is great.'); writeFileSync(join(DIR, 'CHANGELOG.md'), '# Changes\nVersion 1.0 released.'); writeFileSync(join(DIR, 'notes.txt'), 'not a markdown file'); }); afterAll(() => { rmSync(DIR, { recursive: true, force: true }); });As per coding guidelines, "Use isolated temp directories for disk tests and clean them up."
🤖 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/main-processor/__tests__/folder-search.test.ts` around lines 7 - 17, The test uses a fixed DIR constant which risks collisions; change setup to create a unique temp dir per run using mkdtempSync (replace the DIR constant with a variable created inside beforeAll), update beforeAll to call mkdtempSync(tmpdir() + pathSep or use join with a prefix) and write the fixture files into that new dir, and update afterAll to rmSync that variable; ensure references to DIR in the test are replaced by the new variable so tests use an isolated mkdtempSync directory and still clean it up in afterAll.
🤖 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/src/hooks/useFolderSearch.ts`:
- Around line 12-17: The closeFolderSearch callback currently increments
requestId and clears query/results but doesn't clear the loading flag, leaving
isSearchingFolder stuck true; update closeFolderSearch to also call
setIsSearchingFolder(false) (alongside requestId.current += 1,
setIsFolderSearchOpen(false), setFolderQuery(''), setFolderResults([])) so any
visible spinner is cleared immediately when closing, ensuring the in-flight
response being ignored won't leave the loading state set.
---
Duplicate comments:
In `@apps/main-processor/__tests__/folder-search.test.ts`:
- Around line 7-17: The test uses a fixed DIR constant which risks collisions;
change setup to create a unique temp dir per run using mkdtempSync (replace the
DIR constant with a variable created inside beforeAll), update beforeAll to call
mkdtempSync(tmpdir() + pathSep or use join with a prefix) and write the fixture
files into that new dir, and update afterAll to rmSync that variable; ensure
references to DIR in the test are replaced by the new variable so tests use an
isolated mkdtempSync directory and still clean it up in afterAll.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: b9d22c93-8328-45ce-b218-d7fdeaf466ef
📒 Files selected for processing (2)
apps/main-processor/__tests__/folder-search.test.tsapps/renderer/src/hooks/useFolderSearch.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use TypeScript as the primary language for the application
Files:
apps/main-processor/__tests__/folder-search.test.tsapps/renderer/src/hooks/useFolderSearch.ts
apps/main-processor/**/*.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use Marked for parsing Markdown content
Files:
apps/main-processor/__tests__/folder-search.test.ts
**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use Vitest for testing
Files:
apps/main-processor/__tests__/folder-search.test.ts
⚙️ 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/main-processor/__tests__/folder-search.test.ts
**/*.{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/main-processor/__tests__/folder-search.test.ts
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/src/hooks/useFolderSearch.ts
apps/renderer/**/*.{ts,tsx,css}
📄 CodeRabbit inference engine (README.md)
Use Tailwind CSS for styling
Files:
apps/renderer/src/hooks/useFolderSearch.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/useFolderSearch.ts
🔇 Additional comments (3)
apps/main-processor/__tests__/folder-search.test.ts (1)
42-47: LGTM!apps/renderer/src/hooks/useFolderSearch.ts (2)
22-25: Early-return still lets a stale response win. This branch clears results but never advancesrequestIdor clearsisSearchingFolder. If a search is already in flight when the query is emptied (orwindow.apiis missing), the older response at Line 30 still satisfiescurrent === requestId.currentand repopulatesfolderResultsfor what should be an empty search.🐛 Minimal fix
setFolderQuery(query); if (!folderPath || !query.trim() || !window.api?.searchFolder) { + requestId.current += 1; + setIsSearchingFolder(false); setFolderResults([]); return; }
1-11: LGTM!Also applies to: 26-49
There was a problem hiding this comment.
Actionable comments posted: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
.github/workflows/production.yml (1)
14-15:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winHarden checkout: disable credential persistence.
actions/checkoutpersists theGITHUB_TOKENin the runner's git config by default; the security/audit job in particular has no need for it. Settingpersist-credentials: falsereduces token-exfiltration surface (flagged by zizmorartipacked).🔧 Suggested fix (apply to both checkout steps)
- name: Checkout uses: actions/checkout@v4 + with: + persist-credentials: falseAlso applies to: 49-50
🤖 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 @.github/workflows/production.yml around lines 14 - 15, Update both checkout steps that use actions/checkout@v4 to disable credential persistence by adding persist-credentials: false to their step configuration; locate the steps invoking actions/checkout@v4 and set persist-credentials: false so the GITHUB_TOKEN is not written into the runner git config.apps/main-processor/src/index.ts (1)
64-66:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winHandle rejection on these async calls too.
sendFilePathToRendereris now async and can reject (e.g.resolveMarkdownFilePaththrows). Theopen-filehandler at Line 76 guards with.catch, but thedid-finish-loadcall here (and thesecond-instancecall at Line 92) are fire-and-forget → unhandled promise rejection. Apply the same.catchlogging for consistency.🛡️ Proposed fix
- if (filePathToOpen) { - sendFilePathToRenderer(filePathToOpen); - } + if (filePathToOpen) { + void sendFilePathToRenderer(filePathToOpen).catch((error) => { + console.error('Failed to open file:', error); + }); + }🤖 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/main-processor/src/index.ts` around lines 64 - 66, The calls to sendFilePathToRenderer in the did-finish-load branch and the second-instance handler are fire-and-forget but sendFilePathToRenderer is now async and can reject; update both invocations to attach a .catch that logs the error (e.g. processLogger.error("sendFilePathToRenderer failed", err)) so rejections are handled consistently like the open-file handler does; locate sendFilePathToRenderer usages in the did-finish-load handler and the second-instance handler and append .catch(...) with clear context in the log message.electron-builder.ts (1)
20-29: 🧹 Nitpick | 🔵 Trivial | 💤 Low valueRedundant copy of the notice.
{ from: 'assets', to: 'assets' }already shipsunsigned-install-notice.txtinsideresources/assets/. The second entry additionally places it atresources/UNSIGNED_INSTALL_NOTICE.txt. Keep it if root-level visibility is intended; otherwise it's a duplicate artifact.🤖 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 `@electron-builder.ts` around lines 20 - 29, The extraResources array currently contains two entries that copy the same file: the directory entry { from: 'assets', to: 'assets' } already includes assets/unsigned-install-notice.txt, so remove the duplicate file-level entry ({ from: 'assets/unsigned-install-notice.txt', to: 'UNSIGNED_INSTALL_NOTICE.txt' }) unless you intentionally need the notice at the root (UNSIGNED_INSTALL_NOTICE.txt); if root-level visibility is required keep the file-level mapping, otherwise delete that specific mapping to avoid creating duplicate artifacts.apps/renderer/src/hooks/useFileActions.ts (1)
34-40:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winGuard
window.apiinopenFileDialog.
openFolderbails on a missing bridge, butopenFileDialogcallswindow.api.openFileDialog()unguarded — it throws when preload is absent. Mirror the guard for consistency and resilience.As per coding guidelines: renderer code should be "resilient to missing preload APIs."🛡️ Proposed fix
const openFileDialog = useCallback(() => { + if (!window.api) return; void window.api.openFileDialog().then((chosenPath) => { if (chosenPath) { void loadFileInTab(chosenPath); } }); }, [loadFileInTab]);🤖 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/src/hooks/useFileActions.ts` around lines 34 - 40, openFileDialog currently calls window.api.openFileDialog() without guarding against a missing preload API, causing a crash if window.api is undefined; update the openFileDialog function to mirror the openFolder guard by checking that window.api and window.api.openFileDialog exist before calling, and return early if they don't (keeping the existing loadFileInTab flow unchanged when a path is returned).apps/main-processor/__tests__/file.test.ts (1)
42-84:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win
TEST_FILEwrites into the working dir and is never cleaned up.
'./test-file.md'is created relative tocwd(likely the package root) and the new tests at 67-84 keep writing to it without anunlink. Prefer a path undertest_dir(already a temp dir) and remove it in cleanup to avoid polluting the repo and risking cross-test state.As per coding guidelines: "Use isolated temp directories for disk tests and clean them up."🧹 Suggested adjustment
- const TEST_FILE = './test-file.md'; + const TEST_FILE = join(test_dir, 'watcher-test.md'); + + afterAll(() => { + try { unlinkSync(TEST_FILE); } catch { /* ignore */ } + });🤖 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/main-processor/__tests__/file.test.ts` around lines 42 - 84, Tests write ./test-file.md into repo root and never remove it; change TEST_FILE to point into the existing temporary test_dir (e.g. construct TEST_FILE with path.join(test_dir, 'test-file.md')) so each test uses an isolated temp path, and add cleanup to remove the file after tests (use unlink/unlinkSync in afterEach or afterAll). Update any references in these tests that use TEST_FILE and ensure unWatchFile/watchFile behavior is unchanged.
♻️ Duplicate comments (1)
apps/renderer/src/App.tsx (1)
147-155:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winError path still shows the "File updated" success toast.
When
loadFileInTabrejects, the.catchflipsshowToast, which renders themessage="File updated"toast at Line 219 — so a failed open looks like success. Use a dedicated error toast/message.🤖 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/src/App.tsx` around lines 147 - 155, The catch block in the onOpenFolderResult handler flips the generic showToast flag (setShowToast(true)), which causes the existing success toast (message="File updated") to appear on failure; instead, replace that behavior so loadFileInTab's rejection triggers a dedicated error toast/state (e.g., setErrorToast(true) or setToast({type: 'error', message: 'Failed to open file: <error>'})) rather than toggling the success showToast flag; update the onOpenFolderResult catch to capture the error and call the new error-toast setter (and/or set a toast payload) and update the toast render logic to show an error message when that error state/payload is present.
🤖 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 @.github/workflows/development.yml:
- Line 23: CI currently pins pnpm via packageManager and uses
pnpm/action-setup@v4 which is fine; update the workflow to run the security job
after the build by adding needs: build to the jobs.security definition (look for
the jobs.security block in the .github/workflows/development.yml and add the
needs dependency), ensuring scans (pnpm audit and Trivy steps) execute only
after the build/package steps complete.
In @.github/workflows/production.yml:
- Around line 52-53: The security job in production.yml uses
pnpm/action-setup@v4 without a pinned version while the build job sets with:
version: 10 and package.json declares packageManager: "pnpm@10.33.0", causing
inconsistent pnpm versions; update the security job to pass the exact same
version value (e.g., with: version: 10.33.0 or align both to "pnpm@10.33.0") to
match package.json and the build job, ensuring the pnpm/action-setup invocation
in both jobs uses an identical resolved version for deterministic installs.
In `@apps/main-processor/__tests__/folder.test.ts`:
- Around line 9-21: The test creates a real temp directory via mkdtemp (variable
root) but never removes it; wrap the test body that uses mkdtemp, mkdir,
writeFile and getFolder in a try/finally where you await cleanup in the finally
block (use fs.promises.rm or rm with recursive/force options) to remove root
after the test completes; locate the mkdtemp usage and the getFolder call in the
test (file variable root and function getFolder) and ensure the removal runs
regardless of assertions or errors.
In `@apps/renderer/src/components/SettingsPanel.tsx`:
- Around line 14-31: The modal currently sets focus but does not trap
Tab/Shift+Tab or restore the trigger's focus on close; update the effect that
runs when isOpen (the useEffect referencing dialogRef, isOpen, onClose) to (1)
save document.activeElement into a local variable (previouslyFocused) when
opening and restore it on cleanup/close, and (2) install a keydown handler (or
use focus-trap-react) that intercepts Tab/Shift+Tab and cycles focus inside
dialogRef by finding first/last focusable elements so focus cannot escape while
aria-modal="true"; ensure cleanup removes the handler and restores
previouslyFocused and still calls onClose on Escape/backdrop.
In `@apps/renderer/src/config/marked.ts`:
- Line 31: Replace the fragile index-based THEMES[1] usage in marked.ts with an
explicit stable reference or safe lookup: stop relying on array order and
instead set the theme variable to a concrete Theme (e.g., const theme: Theme =
'github-dark') or derive it via a safe lookup like THEMES.find(t => t ===
'github-dark') ?? 'github-dark'; update the variable named theme and any
downstream uses to use this explicit value so reordering THEMES won't change the
selected highlighting theme.
In `@apps/renderer/src/context/ThemeProvider.tsx`:
- Around line 18-27: The effect in ThemeProvider.tsx should seed the theme from
getSystemTheme() on mount (not only on media 'change') when there's no saved
override; update the useEffect to first check if
!localStorage.getItem('app-theme') then call setThemeState(getSystemTheme())
immediately, then create the MediaQueryList, attach onChange (which can remain
as setThemeState(getSystemTheme()) guard by the same localStorage check), and
keep the existing cleanup that calls media.removeEventListener('change',
onChange).
In `@apps/renderer/src/hooks/useMenuEvents.ts`:
- Around line 47-51: The SET_THEME IPC handler currently accepts any string and
force-casts to Theme; update the listener registered via window.api.onMenuEvent
for MENU_EVENTS.SET_THEME to first verify the incoming theme string is one of
the allowed values in APPTHEMES (e.g., APPTHEMES.includes(theme)) before calling
onSetTheme; only call onSetTheme(theme as Theme) when the membership check
passes, otherwise ignore or log an unexpected value.
In `@apps/renderer/src/hooks/useSettings.ts`:
- Around line 61-69: updateSettings in useSettings calls await
window.api.saveSettings(partial) without catching rejections, so a disk/IPC
failure will bubble up and leave the UI with stale state; update updateSettings
to perform an optimistic local setSettings((c)=>({...c,...partial}))
before/around the async call, wrap the await window.api.saveSettings(partial) in
try/catch, on success replace state with the returned next value
(setSettings(next)), and on failure log or surface the error (e.g., via
console.error or a provided error handler) while keeping the optimistic state so
the UI reflects the user’s intent; refer to the updateSettings function and
window.api.saveSettings symbols when making the change.
- Around line 10-19: The current hook swallows IPC/read errors and may apply an
invalid value from the main process; replace the empty catch on
window.api.getSettings() with a handler that logs the error (e.g., console.error
or processLogger) and does not call setSettings when savedSettings is falsy or
not an object; continue to call setSettings only when savedSettings is a valid
object (since getSettings already merges defaults). Also ensure the main-process
validateSettings function always returns an object (never undefined for missing
keys) so default merging in getSettings works correctly.
In `@apps/renderer/src/utils/helpers/heading-helper.ts`:
- Around line 16-21: The heading() renderer currently derives id from
stripHtml(text) which diverges from extractTOC()'s headingText() (which calls
parseInline(token.text)), and it also omits the duplicate-id suffix used by
extractTOC(), causing TOC mismatches; update heading() to derive plainText by
calling parseInline(text) (cast to string to maintain synchronous behavior like
headingText()), then compute id via getHeadingId(plainText), and implement the
same de-duplication/counter suffix logic used in extractTOC() so duplicate
headings produce matching, collision-safe ids; keep escapeHtml(stripHtml(...))
for inner text rendering if needed but ensure id generation follows parseInline
-> getHeadingId -> dedupe sequence.
In `@packages/shared-constants/src/menu-constants.ts`:
- Line 45: The OPEN_SETTINGS constant value breaks the channel naming
convention—update the value for OPEN_SETTINGS in menu-constants.ts (the
OPEN_SETTINGS export) from 'menu:open:settings' to the hyphenated convention
'menu:open-settings' so it matches other event names like SET_THEME and keeps
channel names consistent and greppable.
In `@packages/shared-constants/src/theme-constants.ts`:
- Around line 1-10: The Theme union in shared-types is hardcoded and must
instead be derived from the single source of truth in shared-constants to keep
runtime validation (THEMES) and compile-time types consistent; update
packages/shared-types/src/settings-type.ts to import and re-export the Theme
type (and/or import THEMES if needed) from the shared-constants package and add
shared-constants as a workspace dependency so the settings theme type uses the
exported Theme from shared-constants rather than its own hardcoded union,
ensuring apps validate against THEMES and type-check against the same symbol.
---
Outside diff comments:
In @.github/workflows/production.yml:
- Around line 14-15: Update both checkout steps that use actions/checkout@v4 to
disable credential persistence by adding persist-credentials: false to their
step configuration; locate the steps invoking actions/checkout@v4 and set
persist-credentials: false so the GITHUB_TOKEN is not written into the runner
git config.
In `@apps/main-processor/__tests__/file.test.ts`:
- Around line 42-84: Tests write ./test-file.md into repo root and never remove
it; change TEST_FILE to point into the existing temporary test_dir (e.g.
construct TEST_FILE with path.join(test_dir, 'test-file.md')) so each test uses
an isolated temp path, and add cleanup to remove the file after tests (use
unlink/unlinkSync in afterEach or afterAll). Update any references in these
tests that use TEST_FILE and ensure unWatchFile/watchFile behavior is unchanged.
In `@apps/main-processor/src/index.ts`:
- Around line 64-66: The calls to sendFilePathToRenderer in the did-finish-load
branch and the second-instance handler are fire-and-forget but
sendFilePathToRenderer is now async and can reject; update both invocations to
attach a .catch that logs the error (e.g.
processLogger.error("sendFilePathToRenderer failed", err)) so rejections are
handled consistently like the open-file handler does; locate
sendFilePathToRenderer usages in the did-finish-load handler and the
second-instance handler and append .catch(...) with clear context in the log
message.
In `@apps/renderer/src/hooks/useFileActions.ts`:
- Around line 34-40: openFileDialog currently calls window.api.openFileDialog()
without guarding against a missing preload API, causing a crash if window.api is
undefined; update the openFileDialog function to mirror the openFolder guard by
checking that window.api and window.api.openFileDialog exist before calling, and
return early if they don't (keeping the existing loadFileInTab flow unchanged
when a path is returned).
In `@electron-builder.ts`:
- Around line 20-29: The extraResources array currently contains two entries
that copy the same file: the directory entry { from: 'assets', to: 'assets' }
already includes assets/unsigned-install-notice.txt, so remove the duplicate
file-level entry ({ from: 'assets/unsigned-install-notice.txt', to:
'UNSIGNED_INSTALL_NOTICE.txt' }) unless you intentionally need the notice at the
root (UNSIGNED_INSTALL_NOTICE.txt); if root-level visibility is required keep
the file-level mapping, otherwise delete that specific mapping to avoid creating
duplicate artifacts.
---
Duplicate comments:
In `@apps/renderer/src/App.tsx`:
- Around line 147-155: The catch block in the onOpenFolderResult handler flips
the generic showToast flag (setShowToast(true)), which causes the existing
success toast (message="File updated") to appear on failure; instead, replace
that behavior so loadFileInTab's rejection triggers a dedicated error
toast/state (e.g., setErrorToast(true) or setToast({type: 'error', message:
'Failed to open file: <error>'})) rather than toggling the success showToast
flag; update the onOpenFolderResult catch to capture the error and call the new
error-toast setter (and/or set a toast payload) and update the toast render
logic to show an error message when that error state/payload is present.
🪄 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: 3bb2b33b-20f7-495c-b1bd-6a25187c8e96
⛔ Files ignored due to path filters (2)
apps/renderer/public/icons/app-icon.svgis excluded by!**/*.svgpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml,!pnpm-lock.yaml
📒 Files selected for processing (63)
.github/workflows/development.yml.github/workflows/production.yml.gitignore.husky/pre-push.prettierignoreapps/main-processor/__tests__/export.test.tsapps/main-processor/__tests__/file.test.tsapps/main-processor/__tests__/folder.test.tsapps/main-processor/__tests__/recent.test.tsapps/main-processor/__tests__/settings.test.tsapps/main-processor/setup.tsapps/main-processor/src/export/inlineImage.tsapps/main-processor/src/file.tsapps/main-processor/src/folder.tsapps/main-processor/src/index.tsapps/main-processor/src/ipc.tsapps/main-processor/src/menu.tsapps/main-processor/src/settings/get-settings.tsapps/main-processor/src/settings/save-settings.tsapps/main-processor/src/types/watch-file-types.tsapps/main-processor/src/utils/constants/path-constants.tsapps/main-processor/src/utils/constants/setting-constants.tsapps/main-processor/src/utils/helper/menu-helper.tsapps/main-processor/src/utils/helper/setting-helper.tsapps/main-processor/vitest.config.tsapps/preload/src/index.tsapps/preload/src/utils/menu-event-helper.tsapps/renderer/__tests__/hooks/useCollapsibleToc.test.tsapps/renderer/__tests__/renderer/toc.test.tsapps/renderer/index.htmlapps/renderer/src/App.tsxapps/renderer/src/components/SearchBar.tsxapps/renderer/src/components/SettingsPanel.tsxapps/renderer/src/components/Sidebar.tsxapps/renderer/src/config/marked.tsapps/renderer/src/context/ThemeProvider.tsxapps/renderer/src/hooks/useCollapsibleToc.tsapps/renderer/src/hooks/useFile.tsapps/renderer/src/hooks/useFileActions.tsapps/renderer/src/hooks/useFilePersistence.tsapps/renderer/src/hooks/useFolderSearch.tsapps/renderer/src/hooks/useMenuEvents.tsapps/renderer/src/hooks/useSettings.tsapps/renderer/src/renderer/toc.tsapps/renderer/src/store/tabStore.tsapps/renderer/src/types/component-types.tsapps/renderer/src/types/hook-types.tsapps/renderer/src/utils/helpers/heading-helper.tsapps/renderer/src/utils/helpers/sidebar-helper.tsapps/renderer/src/utils/helpers/tab-helper.tsxapps/renderer/src/utils/helpers/theme-helper.tsassets/unsigned-install-notice.txtelectron-builder.tselectron.vite.config.tspackage.jsonpackages/shared-constants/src/index.tspackages/shared-constants/src/menu-constants.tspackages/shared-constants/src/theme-constants.tspackages/shared-types/package.jsonpackages/shared-types/src/index.tspackages/shared-types/src/markdown-type.tspackages/shared-types/src/settings-default.tspackages/shared-types/src/settings-type.ts
💤 Files with no reviewable changes (1)
- electron.vite.config.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🧰 Additional context used
📓 Path-based instructions (15)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use TypeScript as the primary language for the application
Files:
apps/main-processor/src/utils/constants/path-constants.tsapps/main-processor/src/export/inlineImage.tsapps/main-processor/src/settings/get-settings.tsapps/renderer/src/utils/helpers/theme-helper.tsapps/main-processor/src/utils/helper/menu-helper.tsapps/main-processor/src/types/watch-file-types.tsapps/renderer/src/utils/helpers/tab-helper.tsxapps/main-processor/src/settings/save-settings.tsapps/renderer/src/hooks/useFile.tsapps/renderer/src/hooks/useFilePersistence.tspackages/shared-types/src/settings-default.tsapps/main-processor/vitest.config.tsapps/preload/src/utils/menu-event-helper.tsapps/renderer/src/hooks/useCollapsibleToc.tspackages/shared-constants/src/theme-constants.tsapps/main-processor/__tests__/export.test.tspackages/shared-constants/src/menu-constants.tsapps/main-processor/__tests__/folder.test.tsapps/main-processor/src/file.tsapps/renderer/__tests__/hooks/useCollapsibleToc.test.tselectron-builder.tsapps/renderer/src/utils/helpers/sidebar-helper.tsapps/main-processor/__tests__/file.test.tsapps/main-processor/src/utils/constants/setting-constants.tsapps/renderer/src/utils/helpers/heading-helper.tsapps/main-processor/src/index.tsapps/main-processor/src/menu.tsapps/main-processor/__tests__/settings.test.tsapps/renderer/src/renderer/toc.tsapps/renderer/__tests__/renderer/toc.test.tsapps/renderer/src/store/tabStore.tsapps/renderer/src/config/marked.tsapps/renderer/src/components/SettingsPanel.tsxpackages/shared-constants/src/index.tsapps/main-processor/src/ipc.tsapps/main-processor/setup.tsapps/renderer/src/hooks/useFolderSearch.tsapps/renderer/src/components/Sidebar.tsxpackages/shared-types/src/settings-type.tsapps/renderer/src/hooks/useFileActions.tspackages/shared-types/src/index.tsapps/main-processor/src/utils/helper/setting-helper.tsapps/main-processor/__tests__/recent.test.tsapps/preload/src/index.tsapps/renderer/src/context/ThemeProvider.tsxapps/renderer/src/hooks/useSettings.tsapps/renderer/src/components/SearchBar.tsxapps/main-processor/src/folder.tspackages/shared-types/src/markdown-type.tsapps/renderer/src/App.tsxapps/renderer/src/types/hook-types.tsapps/renderer/src/types/component-types.tsapps/renderer/src/hooks/useMenuEvents.ts
apps/main-processor/**/*.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use Marked for parsing Markdown content
Files:
apps/main-processor/src/utils/constants/path-constants.tsapps/main-processor/src/export/inlineImage.tsapps/main-processor/src/settings/get-settings.tsapps/main-processor/src/utils/helper/menu-helper.tsapps/main-processor/src/types/watch-file-types.tsapps/main-processor/src/settings/save-settings.tsapps/main-processor/vitest.config.tsapps/main-processor/__tests__/export.test.tsapps/main-processor/__tests__/folder.test.tsapps/main-processor/src/file.tsapps/main-processor/__tests__/file.test.tsapps/main-processor/src/utils/constants/setting-constants.tsapps/main-processor/src/index.tsapps/main-processor/src/menu.tsapps/main-processor/__tests__/settings.test.tsapps/main-processor/src/ipc.tsapps/main-processor/setup.tsapps/main-processor/src/utils/helper/setting-helper.tsapps/main-processor/__tests__/recent.test.tsapps/main-processor/src/folder.ts
apps/main-processor/src/**/*.ts
⚙️ CodeRabbit configuration file
apps/main-processor/src/**/*.ts: Review as Electron main-process code.
- IPC handlers must use shared constants and validate renderer input.
- File/folder access must guard path traversal, missing files, permissions, symlinks, and deleted watched files.
- Watchers, menus, dialogs, and IPC listeners must be cleaned up.
- Do not expose Node/Electron internals or unrestricted filesystem access.
- Export/update/download flows must sanitize content, close resources, and avoid executing embedded scripts.
Files:
apps/main-processor/src/utils/constants/path-constants.tsapps/main-processor/src/export/inlineImage.tsapps/main-processor/src/settings/get-settings.tsapps/main-processor/src/utils/helper/menu-helper.tsapps/main-processor/src/types/watch-file-types.tsapps/main-processor/src/settings/save-settings.tsapps/main-processor/src/file.tsapps/main-processor/src/utils/constants/setting-constants.tsapps/main-processor/src/index.tsapps/main-processor/src/menu.tsapps/main-processor/src/ipc.tsapps/main-processor/src/utils/helper/setting-helper.tsapps/main-processor/src/folder.ts
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/src/utils/helpers/theme-helper.tsapps/renderer/src/utils/helpers/tab-helper.tsxapps/renderer/src/hooks/useFile.tsapps/renderer/src/hooks/useFilePersistence.tsapps/renderer/src/hooks/useCollapsibleToc.tsapps/renderer/__tests__/hooks/useCollapsibleToc.test.tsapps/renderer/src/utils/helpers/sidebar-helper.tsapps/renderer/src/utils/helpers/heading-helper.tsapps/renderer/src/renderer/toc.tsapps/renderer/__tests__/renderer/toc.test.tsapps/renderer/src/store/tabStore.tsapps/renderer/src/config/marked.tsapps/renderer/src/components/SettingsPanel.tsxapps/renderer/src/hooks/useFolderSearch.tsapps/renderer/src/components/Sidebar.tsxapps/renderer/src/hooks/useFileActions.tsapps/renderer/src/context/ThemeProvider.tsxapps/renderer/src/hooks/useSettings.tsapps/renderer/src/components/SearchBar.tsxapps/renderer/src/App.tsxapps/renderer/src/types/hook-types.tsapps/renderer/src/types/component-types.tsapps/renderer/src/hooks/useMenuEvents.ts
apps/renderer/**/*.{ts,tsx,css}
📄 CodeRabbit inference engine (README.md)
Use Tailwind CSS for styling
Files:
apps/renderer/src/utils/helpers/theme-helper.tsapps/renderer/src/utils/helpers/tab-helper.tsxapps/renderer/src/hooks/useFile.tsapps/renderer/src/hooks/useFilePersistence.tsapps/renderer/src/hooks/useCollapsibleToc.tsapps/renderer/__tests__/hooks/useCollapsibleToc.test.tsapps/renderer/src/utils/helpers/sidebar-helper.tsapps/renderer/src/utils/helpers/heading-helper.tsapps/renderer/src/renderer/toc.tsapps/renderer/__tests__/renderer/toc.test.tsapps/renderer/src/store/tabStore.tsapps/renderer/src/config/marked.tsapps/renderer/src/components/SettingsPanel.tsxapps/renderer/src/hooks/useFolderSearch.tsapps/renderer/src/components/Sidebar.tsxapps/renderer/src/hooks/useFileActions.tsapps/renderer/src/context/ThemeProvider.tsxapps/renderer/src/hooks/useSettings.tsapps/renderer/src/components/SearchBar.tsxapps/renderer/src/App.tsxapps/renderer/src/types/hook-types.tsapps/renderer/src/types/component-types.tsapps/renderer/src/hooks/useMenuEvents.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/utils/helpers/theme-helper.tsapps/renderer/src/utils/helpers/tab-helper.tsxapps/renderer/src/hooks/useFile.tsapps/renderer/src/hooks/useFilePersistence.tsapps/renderer/src/hooks/useCollapsibleToc.tsapps/renderer/src/utils/helpers/sidebar-helper.tsapps/renderer/src/utils/helpers/heading-helper.tsapps/renderer/src/renderer/toc.tsapps/renderer/src/store/tabStore.tsapps/renderer/src/config/marked.tsapps/renderer/src/components/SettingsPanel.tsxapps/renderer/src/hooks/useFolderSearch.tsapps/renderer/src/components/Sidebar.tsxapps/renderer/src/hooks/useFileActions.tsapps/renderer/src/context/ThemeProvider.tsxapps/renderer/src/hooks/useSettings.tsapps/renderer/src/components/SearchBar.tsxapps/renderer/src/App.tsxapps/renderer/src/types/hook-types.tsapps/renderer/src/types/component-types.tsapps/renderer/src/hooks/useMenuEvents.ts
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/helpers/theme-helper.tsapps/renderer/src/utils/helpers/tab-helper.tsxapps/renderer/src/utils/helpers/sidebar-helper.tsapps/renderer/src/utils/helpers/heading-helper.tsapps/renderer/src/renderer/toc.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/utils/helpers/tab-helper.tsxapps/renderer/src/components/SettingsPanel.tsxapps/renderer/src/components/Sidebar.tsxapps/renderer/src/context/ThemeProvider.tsxapps/renderer/src/components/SearchBar.tsxapps/renderer/src/App.tsx
**/package.json
⚙️ CodeRabbit configuration file
**/package.json: Review scripts and dependencies.
- Scripts for lint, typecheck, test, coverage, build, and dist must fail on errors.
- Dependencies should live in the package that imports them.
- Runtime imports must not be placed only in devDependencies.
- Electron, Vite, React, TypeScript, Tailwind, and testing upgrades need compatibility attention.
Files:
packages/shared-types/package.jsonpackage.json
apps/preload/src/**/*.ts
⚙️ CodeRabbit configuration file
apps/preload/src/**/*.ts: Review as a strict preload boundary.
- Expose only typed contextBridge APIs, never raw ipcRenderer.
- Use shared IPC constants and shared payload/result types.
- Listener methods must return unsubscribe functions.
- Reject broad channel names, arbitrary invoke/send wrappers, and any-typed payloads.
Files:
apps/preload/src/utils/menu-event-helper.tsapps/preload/src/index.ts
**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (README.md)
Use Vitest for testing
Files:
apps/main-processor/__tests__/export.test.tsapps/main-processor/__tests__/folder.test.tsapps/renderer/__tests__/hooks/useCollapsibleToc.test.tsapps/main-processor/__tests__/file.test.tsapps/main-processor/__tests__/settings.test.tsapps/renderer/__tests__/renderer/toc.test.tsapps/main-processor/__tests__/recent.test.ts
⚙️ 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/main-processor/__tests__/export.test.tsapps/main-processor/__tests__/folder.test.tsapps/renderer/__tests__/hooks/useCollapsibleToc.test.tsapps/main-processor/__tests__/file.test.tsapps/main-processor/__tests__/settings.test.tsapps/renderer/__tests__/renderer/toc.test.tsapps/main-processor/__tests__/recent.test.ts
**/*.{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/main-processor/__tests__/export.test.tsapps/main-processor/__tests__/folder.test.tsapps/renderer/__tests__/hooks/useCollapsibleToc.test.tsapps/main-processor/__tests__/file.test.tsapps/main-processor/__tests__/settings.test.tsapps/renderer/__tests__/renderer/toc.test.tsapps/main-processor/__tests__/recent.test.ts
electron-builder.ts
⚙️ CodeRabbit configuration file
electron-builder.ts: Review packaging.
- Check appId, productName, files, asar, icons, targets, file associations, artifact names, and publish settings.
- Exclude source-only, test, coverage, cache, and map files from releases.
- Signing/notarisation/update config must not hardcode secrets.
- Platform targets should match expected Windows, macOS, and Linux release formats.
Files:
electron-builder.ts
{package.json,package-lock.json,yarn.lock,pnpm-lock.yaml,.github/dependabot.yml}
📄 CodeRabbit inference engine (SECURITY.md)
Keep dependencies updated and monitor GitHub Dependabot alerts for security vulnerabilities
Files:
package.json
.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/development.yml.github/workflows/production.yml
🪛 zizmor (1.25.2)
.github/workflows/development.yml
[error] 23-23: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[warning] 47-48: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 48-48: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 51-51: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 54-54: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 66-66: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
.github/workflows/production.yml
[error] 23-23: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[warning] 49-50: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 50-50: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 53-53: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 56-56: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
[error] 68-68: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🔇 Additional comments (55)
.husky/pre-push (1)
1-1: LGTM!.prettierignore (1)
4-9: LGTM!apps/preload/src/utils/menu-event-helper.ts (1)
1-7: LGTM!apps/renderer/src/types/hook-types.ts (1)
28-64: LGTM!apps/renderer/src/hooks/useMenuEvents.ts (1)
29-46: LGTM!apps/main-processor/src/ipc.ts (2)
198-212: ⚡ Quick winAuthorization check is defeated by the preceding
add.Line 204 adds
safeFolderPathtoallowedFolderRootsbefore theisAllowedcheck, so the check on Lines 205–210 always passes — any renderer-supplied folder is authorized. This is the same broad-filesystem-access risk raised previously; the guard only works if you stop auto-inserting the requested path. Let only explicit folder-open flows (OPEN_FOLDER_DIALOG/READ_FOLDER) mutateallowedFolderRoots.Note: the prefix check
startsWith(\${root}/`)assumes/separators; confirmresolveDirectoryPath` normalizes Windows paths so subfolder matching holds there too.As per coding guidelines: "Do not expose Node/Electron internals or unrestricted filesystem access."🔒 Proposed fix
const safeFolderPath = await resolveDirectoryPath(folderPath); - allowedFolderRoots.add(safeFolderPath); const isAllowed = Array.from(allowedFolderRoots).some( (root) => safeFolderPath === root || safeFolderPath.startsWith(`${root}/`) ); if (!isAllowed) { throw new Error('Folder path is not authorized'); } return await searchFolder(safeFolderPath, query);
120-139: LGTM!apps/main-processor/src/utils/constants/path-constants.ts (1)
14-14: LGTM!apps/main-processor/src/settings/get-settings.ts (1)
7-19: LGTM!apps/main-processor/src/types/watch-file-types.ts (1)
1-5: LGTM!apps/main-processor/src/file.ts (1)
18-83: LGTM!apps/main-processor/src/folder.ts (1)
7-58: LGTM!apps/main-processor/src/export/inlineImage.ts (1)
12-14: ⚡ Quick winConfirm
match[2]is the correct capture group for imagesrc
EXPORT_CONST.EXPORT_IMAGE_SRC_REGEXis/src=(["'])(?!https?:\/\/|data:|file:\/\/)(.*?)\1/gi, wherematch[1]is the quote andmatch[2]is the(.*?)image src. Soapps/main-processor/src/export/inlineImage.tsusingconst src = match[2];is correct and won’t makesrcbecomeundefined.assets/unsigned-install-notice.txt (1)
1-23: LGTM!apps/renderer/src/utils/helpers/tab-helper.tsx (1)
4-13: LGTM!electron-builder.ts (1)
60-67: ⚡ Quick win
licenseis set onnsis, notlinux.The summary states
linux.licensewas set, but the change applies the notice as the NSIS installer license page (Windows). If the intent was a Linux license/notice, this is in the wrong block; if Windows was intended, the summary is misleading. Confirm placement.apps/renderer/src/utils/helpers/sidebar-helper.ts (1)
4-20: LGTM!apps/renderer/src/store/tabStore.ts (1)
11-11: LGTM!apps/renderer/src/components/SettingsPanel.tsx (1)
32-101: LGTM!apps/renderer/src/types/component-types.ts (2)
113-184: LGTM!
70-86: ⚡ Quick win
querybeing optional is already handled inSearchBar.
SearchBarderivesactiveQueryas(isFolderMode ? folderQuery : query) ?? '', so the input is always driven by a string (localQuery). The match-count/status UI is also gated behindquery && !isFolderMode, with no directquery.length-style dereferences.apps/renderer/src/utils/helpers/theme-helper.ts (1)
4-6: ⚡ Quick winConfirm
getSystemTheme()returns validThemevalues.
Themeis defined as(typeof APPTHEMES)[number], andAPPTHEMESincludes both'github-light'and'github-dark', so the returned literals match theThemeunion.apps/main-processor/src/utils/helper/menu-helper.ts (1)
3-9: LGTM!apps/main-processor/src/utils/constants/setting-constants.ts (1)
3-14: LGTM!apps/main-processor/src/menu.ts (1)
63-98: LGTM!apps/main-processor/__tests__/settings.test.ts (1)
5-60: LGTM!apps/main-processor/src/utils/helper/setting-helper.ts (1)
14-112: LGTM!apps/preload/src/index.ts (1)
19-32: ⚡ Quick winPreload contract matches the shared
MarkdownReaderAPI.
apps/preload/src/index.tstypesapiContractasMarkdownReaderAPI, and the implementation aligns withpackages/shared-types/src/markdown-type.ts:searchFolder(path, query)matches the shared(string, string) => Promise<FolderSearchResult[]>, andonMenuEvent(...)matches(event: string, callback: (payload?: unknown) => void) => () => void(with unsubscribe removing the samehandler). The channel is still constrained viaisMenuEvent.apps/main-processor/src/settings/save-settings.ts (1)
12-22: 🏗️ Heavy liftDeadlock concern is invalid:
getSettings()does not re-enter the mutex
getSettings()(apps/main-processor/src/settings/get-settings.ts) readssettings.jsondirectly vianode:fs/promises.readFileand never callsrunExclusive.
runExclusiveis only defined inapps/main-processor/src/utils/helper/setting-helper.tsand only used inapps/main-processor/src/settings/save-settings.ts, so the proposed reentrant deadlock path cannot occur (yet).> Likely an incorrect or invalid review comment.apps/main-processor/__tests__/recent.test.ts (1)
1-5: ⚡ Quick winKeep the inline
electronmock removed—Electron is already mocked globally, and recent helpers still import it indirectly.
apps/main-processor/setup.tsalready doesvi.mock('electron', { app: { isPackaged: false, getPath: vi.fn() }}).
getUniqueRecentFileimportsMAX_RECENTfromapps/main-processor/src/utils/constants/path-constants.ts, and that module importsappfromelectron(even though the test only usesMAX_RECENT).So the tests rely on the global mock (not on recent code avoiding Electron). Expand the mock if future recent code starts using additional Electron exports beyond
app.> Likely an incorrect or invalid review comment.apps/renderer/index.html (1)
6-7: LGTM!apps/renderer/src/hooks/useFile.ts (1)
32-39: Good call sourcing the TOC from raw markdown.Parsing the original markdown instead of the sanitized HTML is the right move — DOMPurify can drop/rewrite nodes and break heading text. Just make sure the anchor IDs
extractTOCemits stay byte-for-byte identical to the ones produced by theheading()renderer, otherwise TOC clicks will scroll to nowhere. See the related note inheading-helper.ts..gitignore (1)
1-40: LGTM!package.json (1)
69-75: LGTM!packages/shared-types/package.json (1)
11-11: ⚡ Quick winEnsure
@package/shared-typesbuild output matches"type": "module"
packages/shared-types/package.jsonsets"type": "module", butpackages/shared-types/tsconfig.jsondoesn’t overridecompilerOptions.module(it onlyextends: ../../tsconfig.base.json), and the actual basemodule/moduleResolutionsettings weren’t checked—so we can’t rule out CJS emission and downstream breakage under Node. Repo usage is ESMimport-based (norequire('@package/shared-types')found), but external consumers could still hitERR_REQUIRE_ESM/export mismatches. Confirmtsconfig.base.jsonmodule settings and thatdist/src/index.jsis emitted as ESM (otherwise aligntsconfig/packagetype).apps/renderer/src/hooks/useFilePersistence.ts (1)
25-32: LGTM!apps/renderer/src/hooks/useCollapsibleToc.ts (1)
18-30: LGTM!Also applies to: 47-48, 62-68
apps/renderer/src/hooks/useFolderSearch.ts (1)
19-40: Stale/early-return handling now correct. Token advanced before bailout, bridge guarded, rejections caught and gated.apps/renderer/src/components/Sidebar.tsx (1)
10-13: LGTM!Also applies to: 39-65
apps/renderer/src/components/SearchBar.tsx (1)
22-32: LGTM!Also applies to: 121-140
apps/renderer/src/App.tsx (1)
134-146: LGTM!packages/shared-types/src/settings-type.ts (2)
3-3: ThisThemeunion duplicates the one derived fromTHEMESinshared-constants; tracked at the root intheme-constants.ts.
4-13: LGTM!packages/shared-types/src/settings-default.ts (1)
3-12: LGTM!apps/main-processor/vitest.config.ts (1)
9-9: LGTM!packages/shared-constants/src/index.ts (1)
6-15: LGTM!packages/shared-types/src/index.ts (1)
1-8: LGTM!apps/renderer/src/hooks/useSettings.ts (2)
32-41: LGTM!
43-59: LGTM!packages/shared-types/src/markdown-type.ts (1)
17-23: LGTM!apps/main-processor/__tests__/export.test.ts (1)
58-70: LGTM!apps/renderer/__tests__/hooks/useCollapsibleToc.test.ts (1)
23-35: LGTM!apps/renderer/__tests__/renderer/toc.test.ts (1)
51-65: LGTM!apps/main-processor/setup.ts (1)
1-8: LGTM!.github/workflows/development.yml (1)
43-72: 💤 Low valueSolid security job; one note on ordering.
pnpm audit --audit-level=highand Trivy withexit-code: 1onCRITICAL,HIGHcorrectly fail the pipeline — good. Note the job has noneeds: build, so it runs in parallel withbuildrather than after it (the PR summary says "after the build"). That's fine if intentional; addneeds: buildonly if you want gating.
Description
This PR adds folder wide search feature to the application and it also renames the test folder name.
Type of Change
Related Issue
Closes #41
Checklist
Electron main / preload
Renderer UI
Markdown rendering
Shared packages & types
Tests
Tooling / CI
@commitlint/clidev dep and added pnpm.overrides for several transitive deps.Docs
Packaging
Breaking changes