Skip to content

feat: Add XDG Base Directory Specification support for config paths#125

Merged
ryoppippi merged 4 commits intomainfrom
feat/xdg-basedir-support
Jun 20, 2025
Merged

feat: Add XDG Base Directory Specification support for config paths#125
ryoppippi merged 4 commits intomainfrom
feat/xdg-basedir-support

Conversation

@ryoppippi
Copy link
Owner

@ryoppippi ryoppippi commented Jun 20, 2025

Summary

  • Replace hardcoded ~/.config paths with XDG-compliant configuration directory resolution
  • Add xdg-basedir dependency for proper XDG Base Directory Specification support
  • Maintain backward compatibility with existing ~/.claude directory structure
  • Update all path resolution logic across data-loader, debug, and constants modules

Changes Made

Dependencies

  • Added `xdg-basedir` as dev dependency for XDG directory specification compliance

Constants Module (`_consts.ts`)

  • Import `xdgConfig` from xdg-basedir library
  • Update `DEFAULT_CLAUDE_CONFIG_PATH` to use `XDG_CONFIG_HOME` when available, fallback to `~/.config/claude`
  • Add `XDG_CONFIG_DIR` constant for future extensibility
  • Reorder constant definitions to fix dependency order issues

Data Loader Module (`data-loader.ts`)

  • Replace hardcoded path construction with XDG-aware constants
  • Use `DEFAULT_CLAUDE_CONFIG_PATH` directly in `getClaudePaths()` function
  • Update error messages to show XDG-resolved paths
  • Maintain full backward compatibility with existing ~/.claude directory

Debug Module (`debug.ts`)

  • Replace `DEFAULT_CLAUDE_CODE_PATH` with `DEFAULT_CLAUDE_CONFIG_PATH` for default path resolution
  • Remove unused `USER_HOME_DIR` import
  • Use XDG-aware path resolution for Claude directory detection

Benefits

  1. Standards Compliance: Follows XDG Base Directory Specification for proper Linux/Unix config directory handling
  2. User Control: Respects `XDG_CONFIG_HOME` environment variable when set by users
  3. Backward Compatibility: Continues to work with existing ~/.claude installations
  4. Cross-Platform: Works consistently across different Unix-like systems
  5. Future-Proof: Provides foundation for other XDG directory types (data, cache, etc.)

Testing

  • All existing tests pass without modification
  • XDG path resolution tested in multiple scenarios
  • Backward compatibility verified with legacy ~/.claude directories
  • Environment variable handling tested for `CLAUDE_CONFIG_DIR` and `XDG_CONFIG_HOME`

Migration Impact

No breaking changes - existing users will see no difference in behavior unless they specifically set `XDG_CONFIG_HOME` environment variable.

Summary by CodeRabbit

  • New Features

    • Improved configuration directory handling to support XDG config directories, providing better compatibility with various operating systems.
  • Chores

    • Added "xdg-basedir" as a development dependency for enhanced config path management.
  • Refactor

    • Updated internal logic to use dynamic configuration paths based on the XDG standard, replacing hardcoded paths and centralizing home directory access.

@coderabbitai
Copy link

coderabbitai bot commented Jun 20, 2025

Warning

Rate limit exceeded

@ryoppippi has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 0 minutes and 39 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 3c939ad175aa1b8622cb3759835ed20454691853 and f0471e8.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • CLAUDE.md (1 hunks)
  • package.json (1 hunks)
  • src/_consts.ts (2 hunks)
  • src/data-loader.ts (3 hunks)
  • src/debug.ts (2 hunks)

Walkthrough

The changes update the handling of the default Claude configuration directory to use the XDG config directory by integrating the xdg-basedir package. Path constants and internal logic are refactored to dynamically resolve configuration paths according to XDG standards, replacing previous hardcoded or home-directory-based paths.

Changes

Files Change Summary
package.json Added "xdg-basedir" as a new development dependency.
src/_consts.ts Introduced xdg-basedir usage; added USER_HOME_DIR and XDG_CONFIG_DIR constants; updated config path logic.
src/data-loader.ts Refactored config path construction and checks to use new XDG-based constants and logic.
src/debug.ts Updated imports and path usage to rely on the new XDG-based config path constant.

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant xdg-basedir
    participant OS

    App->>xdg-basedir: Request XDG config directory
    xdg-basedir->>OS: Lookup XDG_CONFIG_HOME environment variable
    xdg-basedir-->>App: Return XDG config path or undefined
    App->>App: Set config path to xdgConfig/claude or fallback to $HOME/.config/claude
    App->>Filesystem: Access config at resolved path
Loading

Possibly related PRs

Poem

In the warren of code, a new path appears,
XDG guides us, allaying old fears.
No more hardcoding, the config now flows,
Where the standards direct, the directory goes.
🐇 With a hop and a skip, our settings align—
To the rhythm of XDG, all works just fine!

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jun 20, 2025

Open in StackBlitz

npm i https://pkg.pr.new/ryoppippi/ccusage@125

commit: f0471e8

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.

Summary of Changes

Hello @ryoppippi, 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 significantly enhances the application's configuration path handling by integrating support for the XDG Base Directory Specification. The primary goal is to standardize where configuration files are stored, aligning with common Linux/Unix conventions, while meticulously preserving backward compatibility for existing user setups. This change centralizes and clarifies path resolution logic throughout the codebase.

Highlights

  • XDG Base Directory Support: Implemented support for the XDG Base Directory Specification to manage configuration paths, moving away from hardcoded ~/.config paths for improved standards compliance on Unix-like systems.
  • Dependency Addition: Added the xdg-basedir package as a development dependency to correctly resolve XDG-compliant directories.
  • Backward Compatibility: Ensured that existing ~/.claude directory structures remain functional, providing a seamless transition for users without breaking changes.
  • Centralized Path Resolution: Updated path resolution logic across _consts.ts, data-loader.ts, and debug.ts modules to leverage new XDG-aware constants, simplifying future path management.
  • Constants Refinement: Introduced USER_HOME_DIR and XDG_CONFIG_DIR constants in _consts.ts and updated DEFAULT_CLAUDE_CONFIG_PATH to prioritize XDG standards while providing a fallback.
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 in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

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 issue 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 is currently in preview and 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 to provide feedback.

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.

@socket-security
Copy link

socket-security bot commented Jun 20, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedxdg-basedir@​5.1.01001008976100

View full report

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 introduces support for the XDG Base Directory Specification for configuration paths, enhancing standards compliance and user control. It adds the xdg-basedir dependency and updates path resolution logic in _consts.ts, data-loader.ts, and debug.ts. Backward compatibility with the ~/.claude directory is largely maintained, especially in data loading.

One area for consideration is the default path resolution in src/debug.ts, which could be made more consistent with the fallback mechanisms used elsewhere to improve user experience for those with legacy setups. Overall, the changes are well-implemented and improve the application's configuration handling.

src/debug.ts Outdated
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 default path for claudeDir now uses DEFAULT_CLAUDE_CONFIG_PATH. This constant resolves to the XDG standard path (e.g., ~/.config/claude/projects) or a path under XDG_CONFIG_HOME if set. Consequently, if claudePath is not provided, this function will no longer check ~/.claude/projects by default.

While the main data loading functions in data-loader.ts (like getClaudePaths and getDefaultClaudePath) maintain backward compatibility by checking multiple locations (including ~/.claude), this debug function's default behavior has diverged. This could lead to confusion if a user with data only in the legacy ~/.claude location runs a debug command without specifying a path, as detectMismatches might not find any files.

To ensure consistent default path resolution, consider using getDefaultClaudePath() from data-loader.ts. This function already implements the logic to check the environment variable, the new XDG path, and the old ~/.claude path as a fallback.

This would involve:

  1. Importing getDefaultClaudePath from ../data-loader.ts (you'd add it to the existing import from data-loader.ts on line 5).
    Example: import { CLAUDE_PROJECTS_DIR_NAME, DEBUG_MATCH_THRESHOLD_PERCENT, DEFAULT_CLAUDE_CONFIG_PATH, USAGE_DATA_GLOB_PATTERN, getDefaultClaudePath } from './_consts.ts';
  2. Modifying this line to use the imported function.
const claudeDir = claudePath ?? path.join(getDefaultClaudePath(), CLAUDE_PROJECTS_DIR_NAME);

@ryoppippi ryoppippi force-pushed the feat/xdg-basedir-support branch from 3c939ad to 3125e07 Compare June 20, 2025 11:23
Copy link

@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: 0

🧹 Nitpick comments (2)
src/_consts.ts (2)

40-44: Fix TypeScript type safety issues.

The static analysis flags unsafe assignment/call for homedir(). While homedir() should return a string, TypeScript might be inferring it could throw an error.

Consider adding explicit type annotation or error handling:

/**
 * User's home directory path
 * Centralized access to OS home directory for consistent path building
 */
-export const USER_HOME_DIR = homedir();
+export const USER_HOME_DIR: string = homedir();

83-86: Fix TypeScript type safety issue and clarify naming.

The static analysis flags unsafe assignment for xdgConfig. Also, consider if this constant is needed given DEFAULT_CLAUDE_CONFIG_PATH already handles the XDG logic.

/**
 * XDG config directory path
 * Uses XDG_CONFIG_HOME if set, otherwise falls back to ~/.config
 */
-export const XDG_CONFIG_DIR = xdgConfig ?? `${USER_HOME_DIR}/.config`;
+export const XDG_CONFIG_DIR: string = xdgConfig ?? `${USER_HOME_DIR}/.config`;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 12c6ad6 and 3c939ad175aa1b8622cb3759835ed20454691853.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • package.json (1 hunks)
  • src/_consts.ts (3 hunks)
  • src/data-loader.ts (3 hunks)
  • src/debug.ts (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/debug.ts (1)
src/_consts.ts (2)
  • DEFAULT_CLAUDE_CONFIG_PATH (56-56)
  • CLAUDE_PROJECTS_DIR_NAME (68-68)
src/data-loader.ts (1)
src/_consts.ts (2)
  • DEFAULT_CLAUDE_CONFIG_PATH (56-56)
  • CLAUDE_PROJECTS_DIR_NAME (68-68)
🪛 ESLint
src/debug.ts

[error] 67-67: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 67-67: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 67-67: Unsafe member access .join on an error typed value.

(ts/no-unsafe-member-access)

src/data-loader.ts

[error] 103-103: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 103-103: Unsafe member access .join on an error typed value.

(ts/no-unsafe-member-access)

src/_consts.ts

[error] 44-44: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)


[error] 44-44: Unsafe call of a(n) error type typed value.

(ts/no-unsafe-call)


[error] 86-86: Unsafe assignment of an error typed value.

(ts/no-unsafe-assignment)

🔇 Additional comments (8)
package.json (1)

81-81: Verify package version and security status.

Please ensure the xdg-basedir version ^5.1.0 is the latest stable version and check for any known security vulnerabilities.

What is the latest version of the xdg-basedir npm package and are there any known security vulnerabilities?
src/_consts.ts (2)

2-2: Verify xdg-basedir import and handle potential type issues.

The import looks correct, but ensure the xdg-basedir package exports are properly typed.


56-56: LGTM - XDG path resolution logic is correct.

The fallback logic properly implements XDG Base Directory Specification with appropriate fallback to ~/.config/claude when XDG_CONFIG_HOME is not set.

src/debug.ts (2)

5-5: LGTM - Import changes align with XDG migration.

The updated imports correctly reflect the new XDG-aware constants structure.


67-67: ```shell
#!/bin/bash

Locate and inspect type definitions of the constants

rg -n "DEFAULT_CLAUDE_CONFIG_PATH" -n src
rg -n "CLAUDE_PROJECTS_DIR_NAME" -n src


</details>
<details>
<summary>src/data-loader.ts (3)</summary>

`82-82`: **LGTM: Correct XDG path integration.**

The change properly uses `DEFAULT_CLAUDE_CONFIG_PATH` directly since it now resolves to the full XDG config directory path or fallback. This aligns with the XDG Base Directory Specification implementation.

---

`103-103`: **LGTM: Error message correctly reflects XDG path structure.**

The error message now properly displays the resolved XDG config directory path. The static analysis hint about "unsafe call of error type" appears to be a false positive since `path.join()` is operating on string paths.

---

`131-132`: **LGTM: Backward compatibility maintained with XDG support.**

The deprecated function correctly uses the resolved `DEFAULT_CLAUDE_CONFIG_PATH` and maintains backward compatibility while supporting XDG Base Directory Specification. The comment accurately reflects the new behavior.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Add xdg-basedir as dev dependency to support proper XDG base directory specification for config path resolution
@ryoppippi ryoppippi force-pushed the feat/xdg-basedir-support branch from 3125e07 to c8d5425 Compare June 20, 2025 11:23
@ryoppippi ryoppippi requested a review from Copilot June 20, 2025 11:23
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Adds support for the XDG Base Directory Specification by replacing hardcoded ~/.config and ~/.claude paths with XDG-aware resolution, while preserving backward compatibility with legacy directories.

  • Swap hardcoded config paths for XDG-based constants throughout modules
  • Update _consts.ts to compute DEFAULT_CLAUDE_CONFIG_PATH from xdgConfig and add XDG_CONFIG_DIR
  • Adjust data-loader.ts and debug.ts to use the new constants and remove legacy home-dir imports

Reviewed Changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 2 comments.

File Description
src/_consts.ts Compute XDG config path, add USER_HOME_DIR and XDG_CONFIG_DIR
src/data-loader.ts Use DEFAULT_CLAUDE_CONFIG_PATH in path arrays and error messages
src/debug.ts Replace legacy home-dir logic with DEFAULT_CLAUDE_CONFIG_PATH
package.json Added xdg-basedir under devDependencies (used at runtime)
Comments suppressed due to low confidence (2)

src/data-loader.ts:82

  • [nitpick] The comment refers to the generic XDG config directory, but DEFAULT_CLAUDE_CONFIG_PATH already includes the claude subfolder. Consider clarifying the comment to reflect that this is the app-specific config path.
		DEFAULT_CLAUDE_CONFIG_PATH, // New default: XDG config directory

src/data-loader.ts:80

  • [nitpick] Ensure there are tests covering scenarios where XDG_CONFIG_HOME is set and unset, as well as legacy ~/.claude fallback, to verify path resolution behaves correctly.
	// Add default paths if they exist

"unplugin-macros": "^0.17.0",
"unplugin-unused": "^0.5.1",
"vitest": "^3.2.4",
"xdg-basedir": "^5.1.0",
Copy link

Copilot AI Jun 20, 2025

Choose a reason for hiding this comment

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

The xdg-basedir package is required at runtime but is declared under devDependencies. It should be moved to dependencies to ensure it’s available in production builds.

Suggested change
"xdg-basedir": "^5.1.0",

Copilot uses AI. Check for mistakes.
src/_consts.ts Outdated
* Uses XDG_CONFIG_HOME if set, otherwise falls back to ~/.config/claude
*/
export const DEFAULT_CLAUDE_CONFIG_PATH = '.config/claude';
export const DEFAULT_CLAUDE_CONFIG_PATH = `${xdgConfig ?? `${USER_HOME_DIR}/.config`}/claude`;
Copy link

Copilot AI Jun 20, 2025

Choose a reason for hiding this comment

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

[nitpick] To avoid duplicating fallback logic, consider building this path from the new XDG_CONFIG_DIR constant (e.g., path.join(XDG_CONFIG_DIR, 'claude')).

Copilot uses AI. Check for mistakes.
…ility

Replace hardcoded DEFAULT_CLAUDE_CONFIG_PATH with getDefaultClaudePath() function to ensure backward compatibility with legacy ~/.claude directories, addressing Gemini review feedback about potential missing files when running debug commands.
…tant organization

- Add explicit string type annotations to USER_HOME_DIR and XDG_CONFIG_DIR to fix unsafe assignment warnings reported by CodeRabbit

- Extract XDG_CONFIG_DIR as internal constant and use it in DEFAULT_CLAUDE_CONFIG_PATH to avoid code duplication as suggested by Copilot

- Reorder constants to fix dependency order and ensure XDG_CONFIG_DIR is defined before use

- Make XDG_CONFIG_DIR non-exported since it is only used internally within _consts.ts
Document important principles for code organization:

- Only export constants/functions/types that are used by other modules

- Keep internal/private items non-exported to minimize public API surface

- Always add dependencies as devDependencies unless explicitly requested

This ensures consistent code organization and prevents unnecessary exports that clutter the module interface.
@ryoppippi ryoppippi merged commit 0c92e0c into main Jun 20, 2025
10 checks passed
@ryoppippi ryoppippi deleted the feat/xdg-basedir-support branch June 20, 2025 11:33
ryoppippi added a commit that referenced this pull request Jun 22, 2025
feat: Add XDG Base Directory Specification support for config paths
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