Skip to content

fix: handle cross-device config writes#162

Open
han-dreamer wants to merge 2 commits into
MiniMax-AI:mainfrom
han-dreamer:fix/config-write-exdev
Open

fix: handle cross-device config writes#162
han-dreamer wants to merge 2 commits into
MiniMax-AI:mainfrom
han-dreamer:fix/config-write-exdev

Conversation

@han-dreamer
Copy link
Copy Markdown

Summary

Fix config writes when renameSync(tmp, path) fails with EXDEV.

This addresses #61.

Changes

  • Keep the existing atomic renameSync path for normal config writes.
  • Add an EXDEV fallback that copies the temp config file to the final path and then removes the temp file.
  • Preserve existing behavior for non-EXDEV errors by rethrowing them.
  • Add tests for:
    • EXDEV fallback behavior.
    • Non-EXDEV error rethrowing.
    • Normal config write path.

Why

Issue #61 reports:

EXDEV: cross-device link not permitted, rename '...\config.json.tmp' -> '...\config.json'

Copy link
Copy Markdown

@TumCucTom TumCucTom left a comment

Choose a reason for hiding this comment

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

oh — I also opened a competing fix for #61 (PR #171) without realising yours was already in flight, the user moved fast and I didn't sweep the open list. closing #171 in favor of yours.

your design is the better one: exporting renameWithCrossDeviceFallback as a generic helper (not just for the config file) with the ops parameter for DI is much cleaner than what I did. the three tests covering happy/fallback/rethrow are the right minimum.

one small thing: the EXDEV-fallback and rethrow tests only check the sequence of mocked calls, not that the file actually gets written. an end-to-end test that injects a throwing renameWithCrossDeviceFallback into writeConfigFile and verifies the file content lands would close the loop on user-facing behavior. if a future refactor breaks the wiring between writeConfigFile and the helper, neither of the current tests would catch it.

style nit: (err as NodeJS.ErrnoException).code !== 'EXDEV' — a tiny isExdevError type guard would read cleaner than the cast.

approved. thanks for the better design.

@han-dreamer
Copy link
Copy Markdown
Author

Thanks for the detailed review!

I pushed a follow-up commit that addresses both suggestions:

  • Added isCrossDeviceError() to make the EXDEV check more readable.
  • Added an end-to-end writeConfigFile test that injects an EXDEV rename failure, uses the real copy/unlink fallback, and asserts the final config file content.

Validation:

  • npx bun test test/config/loader.test.ts test/commands/config/set.test.ts
  • npx tsc --noEmit
  • npx eslint src/config/loader.ts test/config/loader.test.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants