Skip to content

fix(installer): replace fs-extra with native node:fs to prevent file loss#2253

Merged
bmadcode merged 2 commits intomainfrom
fix-fs-extra-graceful-fs
Apr 13, 2026
Merged

fix(installer): replace fs-extra with native node:fs to prevent file loss#2253
bmadcode merged 2 commits intomainfrom
fix-fs-extra-graceful-fs

Conversation

@bmadcode
Copy link
Copy Markdown
Collaborator

Summary

  • Replaces fs-extra dependency with a thin fs-native.js wrapper over native node:fs/promises and node:fs
  • Eliminates graceful-fs monkey-patching that causes non-deterministic file loss during multi-module installs on macOS (APFS)
  • Updates all 21 installer files + 1 test file + 1 migration script to use the new module
  • Removes fs-extra from package.json dependencies

Root Cause

fs-extra routes all operations through graceful-fs, which globally monkey-patches node:fs with a deferred EMFILE retry queue (setTimeout(retry, 0)). During multi-module installs (~500+ file ops), each module goes through a remove-then-copy cycle. Retried unlink operations from the remove phase can fire after subsequent copy operations have written files, silently deleting them. The exact files lost vary between runs (non-deterministic), and the installer reports success.

Fix

fs-native.js provides the same API surface (pathExists, ensureDir, remove, copy, etc.) using only stable native Node.js APIs with no global state or monkey-patching. File operations execute and complete in the order they are awaited.

Test plan

  • All 229 installation component tests pass
  • All 7 CSV file reference tests pass
  • ESLint clean (0 warnings)
  • Prettier clean
  • Markdownlint clean
  • Verified no remaining require('fs-extra') in source code

Closes #1779

…loss

fs-extra routes all operations through graceful-fs, which globally
monkey-patches node:fs with a deferred retry queue. During multi-module
installs (~500+ file ops), retried unlink operations from one module's
remove phase can fire after the next module's copy phase has written
files, silently deleting them non-deterministically.

Replace fs-extra with a thin fs-native.js wrapper over node:fs/promises
and node:fs. All 21 consumers now use native APIs with no global
monkey-patching, eliminating the retry-queue race condition entirely.

Closes #1779
@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented Apr 13, 2026

🤖 Augment PR Summary

Summary: This PR replaces the installer’s use of fs-extra with a new tools/installer/fs-native.js wrapper around native node:fs/node:fs/promises APIs.

Changes:

  • Removes fs-extra from package.json dependencies
  • Adds fs-native.js implementing a subset of fs-extra-style helpers (e.g., pathExists, ensureDir, remove, copy)
  • Updates installer commands/core/modules/UI and one test to import fs-native instead of fs-extra

Technical Notes: The intent is to avoid graceful-fs monkey-patching and the reported non-deterministic deletion race on macOS/APFS during multi-module installs.

🤖 Was this summary useful? React with 👍 or 👎

Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

Choose a reason for hiding this comment

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

Review completed. 2 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread tools/installer/fs-native.js
Comment thread tools/installer/fs-native.js
Add missing move() with cross-device fallback (rename → copy+rm on
EXDEV), needed by OfficialModules.createModuleDirectories for directory
migrations during upgrades.

Honor overwrite/errorOnExist options in copy() to match fs-extra
behavior for callers that pass these flags.
@bmadcode bmadcode merged commit 5456b26 into main Apr 13, 2026
5 checks passed
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 13, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

The PR systematically replaces the fs-extra dependency with a native Node.js-based alternative (fs-native) across the installer codebase to eliminate non-deterministic file loss on macOS caused by graceful-fs's global retry queue behavior.

Changes

Cohort / File(s) Summary
Dependency Management
package.json
Removed fs-extra from dependencies to eliminate graceful-fs's global monkey-patching of Node.js fs methods.
Native Filesystem Wrapper
tools/installer/fs-native.js
New module implementing drop-in replacement for fs-extra using native node:fs and node:fs/promises with helpers for pathExists, ensureDir, remove, copy (recursive), readJsonSync, and writeJson.
Installer Core Modules
tools/installer/core/installer.js, tools/installer/core/manifest.js, tools/installer/core/manifest-generator.js, tools/installer/core/existing-install.js, tools/installer/core/install-paths.js
Updated all core installer modules to import fs-native instead of fs-extra for filesystem operations.
Installer Command Modules
tools/installer/commands/status.js, tools/installer/commands/uninstall.js
Switched command modules to use fs-native for path existence checks and file operations.
IDE & Configuration Modules
tools/installer/ide/_config-driven.js, tools/installer/ide/platform-codes.js, tools/installer/ide/shared/skill-manifest.js
Updated IDE-related modules to use fs-native for directory reads, file parsing, and existence checks.
Module Manager Modules
tools/installer/modules/community-manager.js, tools/installer/modules/custom-module-manager.js, tools/installer/modules/external-manager.js, tools/installer/modules/official-modules.js, tools/installer/modules/plugin-resolver.js
Switched all module manager implementations to use fs-native for directory operations and file manipulation.
File Operations & Utilities
tools/installer/file-ops.js, tools/installer/message-loader.js, tools/installer/ui.js, tools/installer/project-root.js, tools/migrate-custom-module-paths.js
Updated utility modules to use fs-native for file reads, writes, and filesystem checks.
Tests
test/test-installation-components.js
Updated test file to import filesystem utilities from tools/installer/fs-native instead of fs-extra.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately summarizes the main change: replacing fs-extra with native node:fs to prevent file loss, which is the core objective of this changeset.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the root cause, the fix approach, and test results that validate the changes made.
Linked Issues check ✅ Passed The PR fully addresses the linked issue #1779 by replacing fs-extra with a native Node.js wrapper module, eliminating graceful-fs monkey-patching, and updating all 23 files (21 installer + 1 test + 1 migration) to use the new fs-native module.
Out of Scope Changes check ✅ Passed All changes are directly related to replacing fs-extra with fs-native and removing the fs-extra dependency. No unrelated modifications were introduced outside the scope of fixing the file-loss issue.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-fs-extra-graceful-fs

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 and usage tips.

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.

Installer non-deterministic file loss on macOS due to fs-extra/graceful-fs

1 participant