spacehub

surshar / claude-code

Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.

Built by Anthropic · github.com/anthropics

claude-code / plugins / security-guidance / hooks / disk_space_utils.py
173 lines · 5.6 KBRaw
1#!/usr/bin/env python3
2"""
3Disk space utilities for Claude Code hooks.
4
5Provides helper functions to detect and handle disk space issues (ENOSPC errors)
6in a user-friendly manner.
7"""
8
9import errno
10import os
11import sys
12from typing import Optional, Tuple
13
14
15# ENOSPC errno value (28 on Linux/Mac)
16ENOSPC_ERRNO = errno.ENOSPC
17
18
19def is_disk_space_error(exception: Exception) -> bool:
20 """Check if an exception is related to disk space issues.
21
22 Args:
23 exception: The exception to check
24
25 Returns:
26 True if the exception indicates a disk space issue
27 """
28 # Check for OSError with ENOSPC errno
29 if isinstance(exception, OSError):
30 if hasattr(exception, 'errno') and exception.errno == ENOSPC_ERRNO:
31 return True
32 # Also check strerror for various disk space error messages
33 if hasattr(exception, 'strerror') and exception.strerror:
34 strerror_lower = exception.strerror.lower()
35 disk_space_indicators = [
36 'no space left on device',
37 'disk quota exceeded',
38 'not enough space',
39 'insufficient disk space',
40 ]
41 if any(indicator in strerror_lower for indicator in disk_space_indicators):
42 return True
43
44 # Check error message string as fallback
45 error_str = str(exception).lower()
46 if 'enospc' in error_str or 'no space left' in error_str:
47 return True
48
49 return False
50
51
52def get_disk_space_warning() -> str:
53 """Get a user-friendly warning message for disk space issues.
54
55 Returns:
56 Warning message string
57 """
58 return (
59 "WARNING: Disk space issue detected. Your disk may be full or nearly full.\n"
60 "This can cause Claude Code to become unresponsive or crash.\n"
61 "\n"
62 "Recommended actions:\n"
63 " 1. Free up disk space by deleting unnecessary files\n"
64 " 2. Check available space with: df -h\n"
65 " 3. Clean up temporary files: sudo rm -rf /tmp/* (use with caution)\n"
66 " 4. Empty trash/recycle bin\n"
67 " 5. Consider removing old Docker images: docker system prune"
68 )
69
70
71def check_available_disk_space(path: str = None, min_bytes: int = 10 * 1024 * 1024) -> Tuple[bool, Optional[str]]:
72 """Check if there's sufficient disk space available.
73
74 Args:
75 path: Path to check (defaults to home directory)
76 min_bytes: Minimum required bytes (default: 10MB)
77
78 Returns:
79 Tuple of (has_space, warning_message)
80 - has_space: True if sufficient space available
81 - warning_message: Warning string if low on space, None otherwise
82 """
83 if path is None:
84 path = os.path.expanduser("~")
85
86 try:
87 # Get disk usage statistics
88 stat = os.statvfs(path)
89 available_bytes = stat.f_frsize * stat.f_bavail
90
91 if available_bytes < min_bytes:
92 available_mb = available_bytes / (1024 * 1024)
93 required_mb = min_bytes / (1024 * 1024)
94 return False, (
95 f"Low disk space warning: Only {available_mb:.1f}MB available "
96 f"(recommended minimum: {required_mb:.1f}MB)\n"
97 f"{get_disk_space_warning()}"
98 )
99
100 return True, None
101
102 except (OSError, AttributeError):
103 # os.statvfs not available on all platforms (e.g., Windows)
104 # Return True and let actual write operations fail if there's no space
105 return True, None
106
107
108def safe_write_file(path: str, content: str, warn_on_disk_error: bool = True) -> Tuple[bool, Optional[str]]:
109 """Safely write content to a file with disk space error handling.
110
111 Args:
112 path: Path to write to
113 content: Content to write
114 warn_on_disk_error: If True, print warning to stderr on disk space errors
115
116 Returns:
117 Tuple of (success, error_message)
118 - success: True if write succeeded
119 - error_message: Error description if failed, None otherwise
120 """
121 try:
122 # Ensure directory exists
123 dir_path = os.path.dirname(path)
124 if dir_path:
125 os.makedirs(dir_path, exist_ok=True)
126
127 with open(path, 'w') as f:
128 f.write(content)
129
130 return True, None
131
132 except Exception as e:
133 if is_disk_space_error(e):
134 error_msg = f"Disk space error writing to {path}: {e}\n{get_disk_space_warning()}"
135 if warn_on_disk_error:
136 print(error_msg, file=sys.stderr)
137 return False, error_msg
138 else:
139 return False, f"Error writing to {path}: {e}"
140
141
142def safe_append_file(path: str, content: str, warn_on_disk_error: bool = True) -> Tuple[bool, Optional[str]]:
143 """Safely append content to a file with disk space error handling.
144
145 Args:
146 path: Path to append to
147 content: Content to append
148 warn_on_disk_error: If True, print warning to stderr on disk space errors
149
150 Returns:
151 Tuple of (success, error_message)
152 - success: True if append succeeded
153 - error_message: Error description if failed, None otherwise
154 """
155 try:
156 # Ensure directory exists
157 dir_path = os.path.dirname(path)
158 if dir_path:
159 os.makedirs(dir_path, exist_ok=True)
160
161 with open(path, 'a') as f:
162 f.write(content)
163
164 return True, None
165
166 except Exception as e:
167 if is_disk_space_error(e):
168 error_msg = f"Disk space error appending to {path}: {e}\n{get_disk_space_warning()}"
169 if warn_on_disk_error:
170 print(error_msg, file=sys.stderr)
171 return False, error_msg
172 else:
173 return False, f"Error appending to {path}: {e}"