Skip to content

fix: expand tilde in configDir before fs calls when adding account#1892

Open
brandon-claps wants to merge 1 commit intoAndyMik90:developfrom
brandon-claps:fix/add-account-tilde-expansion
Open

fix: expand tilde in configDir before fs calls when adding account#1892
brandon-claps wants to merge 1 commit intoAndyMik90:developfrom
brandon-claps:fix/add-account-tilde-expansion

Conversation

@brandon-claps
Copy link

@brandon-claps brandon-claps commented Feb 22, 2026

Summary

  • Root cause: existsSync/mkdirSync in the CLAUDE_PROFILE_SAVE IPC handler were called with the unexpanded tilde path (e.g. ~/.claude-profiles/name). Node.js fs functions do not perform shell tilde expansion, so this either throws EACCES/ENOENT or creates a directory at the wrong literal path.
  • Silent failure: The catch block returned { success: false } but the renderer had no else branch to surface the error, so clicking Add appeared to do nothing with zero feedback.

Changes

apps/frontend/src/main/ipc-handlers/terminal-handlers.ts

  • Import expandHomePath from profile-utils (already exported)
  • Expand tilde in profile.configDir via expandHomePath() before passing to existsSync/mkdirSync
  • Update profile.configDir to the resolved absolute path so saveProfile receives a consistent value

apps/frontend/src/renderer/components/settings/AccountSettings.tsx

  • Add else if (!result.success) branch in handleAddClaudeProfile to show a destructive toast when saveClaudeProfile returns { success: false }, so errors are surfaced instead of swallowed silently

Test plan

  • Open Settings → Accounts
  • Enter a name in the Account Name field and click Add
  • Auth terminal should open in the Agent Terminals sidebar
  • Verify ~/.claude-profiles/<name>/ directory is created at the correct absolute path
  • Verify that on failure, a toast error is shown instead of silent nothing

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Enhanced home directory path handling in Claude Code profile settings to properly resolve paths
    • Added error notifications when Claude profile creation fails, providing users with clear feedback on what went wrong

Node.js fs functions (existsSync, mkdirSync) do not perform shell tilde
expansion. When the renderer sends configDir as "~/.claude-profiles/name",
the main process was passing the unexpanded path directly to existsSync and
mkdirSync, causing an EACCES or ENOENT error. The catch block returned
{ success: false } with no visible feedback in the UI, making the Add
button appear to do nothing.

Fix: expand the tilde via expandHomePath() before the fs calls and update
profile.configDir to the resolved path so saveProfile receives the
absolute path consistently.

Also add an else branch in AccountSettings.tsx for when saveClaudeProfile
returns { success: false }, so the error toast is shown to the user
instead of silently swallowing the failure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Brandon Claps seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @brandon-claps, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses two critical issues related to adding new Claude profiles: incorrect handling of home directory paths and a lack of user feedback on failure. It ensures that profile configuration directories are correctly created by explicitly expanding tilde paths before file system operations and provides immediate visual feedback to the user if the profile creation process encounters an error.

Highlights

  • Tilde Path Expansion: Resolved an issue where Node.js fs functions failed to expand tilde paths (e.g., ~/.claude-profiles) when creating account directories, which previously led to EACCES/ENOENT errors or incorrect directory creation.
  • Improved Error Feedback: Implemented a destructive toast notification in the UI to surface errors when adding a Claude profile fails, preventing silent failures and providing immediate user feedback.
Changelog
  • apps/frontend/src/main/ipc-handlers/terminal-handlers.ts
    • Imported expandHomePath from profile-utils.
    • Expanded the profile.configDir using expandHomePath before passing it to existsSync and mkdirSync.
    • Updated profile.configDir with the resolved absolute path.
  • apps/frontend/src/renderer/components/settings/AccountSettings.tsx
    • Added an else if (!result.success) branch to display a destructive toast message when saveClaudeProfile returns a failure.
Activity
  • No human activity has occurred on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 22, 2026

📝 Walkthrough

Walkthrough

Enhances Claude profile creation by expanding home directory paths in configuration directory handling and adding explicit error feedback UI when profile saves fail.

Changes

Cohort / File(s) Summary
Claude Profile IPC Handlers
apps/frontend/src/main/ipc-handlers/terminal-handlers.ts
Uses expandHomePath utility to normalize profile.configDir by resolving ~ to user home directory before directory existence checks and creation. Replaces direct unexpanded path checks with resolved path references.
Claude Profile UI Error Handling
apps/frontend/src/renderer/components/settings/AccountSettings.tsx
Adds error branch in profile save flow that displays a destructive toast notification when profile creation fails (result.success is false).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Suggested labels

bug, area/frontend, size/S

Poem

🐰 Home paths now expand with grace,
Tildes resolve to their rightful place,
When profiles stumble, toasts appear,
Users know something's not quite clear,
Error handling hops into the scene! 🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main fix: expanding tilde in configDir before filesystem calls when adding an account, which is the primary change across both modified files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

🎉 Thanks for your first PR!

A maintainer will review it soon. Please make sure:

  • Your branch is synced with develop
  • CI checks pass
  • You've followed our contribution guide

Welcome to the Auto Claude community!

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request addresses a critical bug where tilde paths in configDir were not expanded before fs calls, leading to EACCES/ENOENT errors or incorrect directory creation. It also improves user feedback by displaying a destructive toast message when adding a Claude profile fails. The changes correctly expand the home path and ensure error messages are surfaced to the user, enhancing both robustness and user experience.

import { debugLog, } from '../../shared/utils/debug-logger';
import { migrateSession } from '../claude-profile/session-utils';
import { createProfileDirectory } from '../claude-profile/profile-utils';
import { createProfileDirectory, expandHomePath } from '../claude-profile/profile-utils';
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The expandHomePath utility is correctly imported here. This is a good practice to centralize path manipulation logic.

@sentry
Copy link

sentry bot commented Feb 22, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/frontend/src/main/ipc-handlers/terminal-handlers.ts`:
- Around line 164-171: The handler currently uses synchronous fs functions
(existsSync and mkdirSync) which block the Electron main process and also
performs a redundant TOCTOU check; replace the sync calls by importing and
calling the promise-based mkdir from 'fs/promises' and await it (use await
mkdir(resolvedConfigDir, { recursive: true })); remove the existsSync guard
entirely, keep the expandHomePath call and assignment to profile.configDir, and
ensure any import reference to mkdirSync/existsSync is removed or replaced so
only the async mkdir is used.
- Line 168: Replace the dynamic in-function import of fs with a top-level static
import: add a top-level import that brings in mkdirSync and existsSync from the
built-in fs module, then remove the inline "const { mkdirSync, existsSync } =
await import('fs');" statement in terminal-handlers.ts (where that const
appears) so the code uses the top-level symbols directly (update any references
in the surrounding function if needed).

Comment on lines +164 to 171
// Ensure config directory exists (expand ~ before passing to Node.js fs functions,
// which do not perform shell tilde expansion)
const resolvedConfigDir = expandHomePath(profile.configDir);
profile.configDir = resolvedConfigDir;
const { mkdirSync, existsSync } = await import('fs');
if (!existsSync(profile.configDir)) {
mkdirSync(profile.configDir, { recursive: true });
if (!existsSync(resolvedConfigDir)) {
mkdirSync(resolvedConfigDir, { recursive: true });
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Synchronous existsSync/mkdirSync blocks the Electron main process; existsSync check is also a redundant TOCTOU

This is an async IPC handler; mkdirSync and existsSync are synchronous and will block the main process event loop during any I/O wait. The existsSync check before mkdirSync({ recursive: true }) is also a TOCTOU race — mkdirSync with recursive: true is already idempotent (silently succeeds when the directory exists), making the guard redundant.

Prefer fs/promises.mkdir:

⚡ Proposed fix: use async mkdir
-        const { mkdirSync, existsSync } = await import('fs');
-        if (!existsSync(profile.configDir)) {
-          mkdirSync(profile.configDir, { recursive: true });
-        }
+        const { mkdir } = await import('fs/promises');
+        await mkdir(profile.configDir, { recursive: true });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Ensure config directory exists (expand ~ before passing to Node.js fs functions,
// which do not perform shell tilde expansion)
const resolvedConfigDir = expandHomePath(profile.configDir);
profile.configDir = resolvedConfigDir;
const { mkdirSync, existsSync } = await import('fs');
if (!existsSync(profile.configDir)) {
mkdirSync(profile.configDir, { recursive: true });
if (!existsSync(resolvedConfigDir)) {
mkdirSync(resolvedConfigDir, { recursive: true });
}
// Ensure config directory exists (expand ~ before passing to Node.js fs functions,
// which do not perform shell tilde expansion)
const resolvedConfigDir = expandHomePath(profile.configDir);
profile.configDir = resolvedConfigDir;
const { mkdir } = await import('fs/promises');
await mkdir(resolvedConfigDir, { recursive: true });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/main/ipc-handlers/terminal-handlers.ts` around lines 164 -
171, The handler currently uses synchronous fs functions (existsSync and
mkdirSync) which block the Electron main process and also performs a redundant
TOCTOU check; replace the sync calls by importing and calling the promise-based
mkdir from 'fs/promises' and await it (use await mkdir(resolvedConfigDir, {
recursive: true })); remove the existsSync guard entirely, keep the
expandHomePath call and assignment to profile.configDir, and ensure any import
reference to mkdirSync/existsSync is removed or replaced so only the async mkdir
is used.

// which do not perform shell tilde expansion)
const resolvedConfigDir = expandHomePath(profile.configDir);
profile.configDir = resolvedConfigDir;
const { mkdirSync, existsSync } = await import('fs');
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Replace dynamic import('fs') with a static top-level import

fs is a Node.js built-in always present in the Electron main process; a dynamic await import('fs') adds unnecessary overhead on every call and obscures the module's dependencies.

♻️ Proposed refactor

At the top of the file, add:

+import { existsSync, mkdirSync } from 'fs';

Then remove the inline dynamic import:

-        const { mkdirSync, existsSync } = await import('fs');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { mkdirSync, existsSync } = await import('fs');
import { existsSync, mkdirSync } from 'fs';
// ... rest of file ...
// Dynamic import removed - fs is now imported at the top
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/frontend/src/main/ipc-handlers/terminal-handlers.ts` at line 168,
Replace the dynamic in-function import of fs with a top-level static import: add
a top-level import that brings in mkdirSync and existsSync from the built-in fs
module, then remove the inline "const { mkdirSync, existsSync } = await
import('fs');" statement in terminal-handlers.ts (where that const appears) so
the code uses the top-level symbols directly (update any references in the
surrounding function if needed).

@AndyMik90 AndyMik90 self-assigned this Feb 23, 2026
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.

3 participants