/ utils / xdg.ts
xdg.ts
 1  /**
 2   * XDG Base Directory utilities for Claude CLI Native Installer
 3   *
 4   * Implements the XDG Base Directory specification for organizing
 5   * native installer components across appropriate system directories.
 6   *
 7   * @see https://specifications.freedesktop.org/basedir-spec/latest/
 8   */
 9  
10  import { homedir as osHomedir } from 'os'
11  import { join } from 'path'
12  
13  type EnvLike = Record<string, string | undefined>
14  
15  type XDGOptions = {
16    env?: EnvLike
17    homedir?: string
18  }
19  
20  function resolveOptions(options?: XDGOptions): { env: EnvLike; home: string } {
21    return {
22      env: options?.env ?? process.env,
23      home: options?.homedir ?? process.env.HOME ?? osHomedir(),
24    }
25  }
26  
27  /**
28   * Get XDG state home directory
29   * Default: ~/.local/state
30   * @param options Optional env and homedir overrides for testing
31   */
32  export function getXDGStateHome(options?: XDGOptions): string {
33    const { env, home } = resolveOptions(options)
34    return env.XDG_STATE_HOME ?? join(home, '.local', 'state')
35  }
36  
37  /**
38   * Get XDG cache home directory
39   * Default: ~/.cache
40   * @param options Optional env and homedir overrides for testing
41   */
42  export function getXDGCacheHome(options?: XDGOptions): string {
43    const { env, home } = resolveOptions(options)
44    return env.XDG_CACHE_HOME ?? join(home, '.cache')
45  }
46  
47  /**
48   * Get XDG data home directory
49   * Default: ~/.local/share
50   * @param options Optional env and homedir overrides for testing
51   */
52  export function getXDGDataHome(options?: XDGOptions): string {
53    const { env, home } = resolveOptions(options)
54    return env.XDG_DATA_HOME ?? join(home, '.local', 'share')
55  }
56  
57  /**
58   * Get user bin directory (not technically XDG but follows the convention)
59   * Default: ~/.local/bin
60   * @param options Optional homedir override for testing
61   */
62  export function getUserBinDir(options?: XDGOptions): string {
63    const { home } = resolveOptions(options)
64    return join(home, '.local', 'bin')
65  }