1"""Type-safe configuration for dependency injection.

2

3 This module provides type-safe configuration classes for the Oneiric-backed

4 service container, replacing string-based keys with proper type-based

5 dependency resolution.

6

7 Phase: Week 7 Day 1 - ACB DI Refactoring

8"""

9

10 from __future__ import annotations

11

12 import os

13 from dataclasses import dataclass

14 from pathlib import Path

15

16

17@dataclass(frozen=True)

18 class SessionPaths:

19 """Type-safe path configuration for session management.

20

21 This class replaces string-based DI keys (like "paths.claude_dir") with

22 a proper type-based configuration object that works correctly with Bevy's

23 type checking system.

24

25 Attributes:

26 claude_dir: Root directory for Claude session data (~/.claude)

27 logs_dir: Directory for session logs (~/.claude/logs)

28 commands_dir: Directory for slash commands (~/.claude/commands)

29 data_dir: Directory for database storage (~/.claude/data)

30

31 Example:

32 >>> paths = SessionPaths.from_home()

33 >>> print(paths.claude_dir)

34 PosixPath('/Users/username/.claude')

35

36 >>> # Use with DI container

37 >>> depends.set(SessionPaths, paths)

38 >>> resolved = depends.get_sync(SessionPaths)

39

40 """

41

42 claude_dir: Path

43 logs_dir: Path

44 commands_dir: Path

45 data_dir: Path

46

47 @classmethod

48 def from_home(cls, home: Path | None = None) -> SessionPaths:

49 """Create SessionPaths from home directory.

50

51 Args:

52 home: Optional home directory path. If None, uses current user's home

53 directory via os.path.expanduser("~"). This method respects the

54 HOME environment variable, making it test-friendly.

55

56 Returns:

57 SessionPaths instance with directories based on the home path.

58

59 Example:

60 >>> # Use default home directory

61 >>> paths = SessionPaths.from_home()

62

63 >>> # Use custom home (useful for testing)

64 >>> test_home = Path("/tmp/test_home")

65 >>> paths = SessionPaths.from_home(test_home)

66

67 """

68 if home is None:

69 # Use os.path.expanduser to respect HOME environment variable

70 # This is test-friendly, unlike Path.home() which uses system APIs

71 home = Path(os.path.expanduser("~"))

72

73 claude_dir = home / ".claude"

74

75 return cls(

76 claude_dir=claude_dir,

77 logs_dir=claude_dir / "logs",

78 commands_dir=claude_dir / "commands",

79 data_dir=claude_dir / "data",

80 )

81

82 def ensure_directories(self) -> None:

83 """Create all configured directories if they don't exist.

84

85 This method is idempotent and safe to call multiple times.

86 Uses mkdir(parents=True, exist_ok=True) to handle missing parent

87 directories gracefully.

88

89 Example:

90 >>> paths = SessionPaths.from_home()

91 >>> paths.ensure_directories()

92 >>> assert paths.claude_dir.exists()

93 >>> assert paths.logs_dir.exists()

94 >>> assert paths.data_dir.exists()

95

96 """

97 self.claude_dir.mkdir(parents=True, exist_ok=True)

98 self.logs_dir.mkdir(parents=True, exist_ok=True)

99 self.commands_dir.mkdir(parents=True, exist_ok=True)

100 self.data_dir.mkdir(parents=True, exist_ok=True)