claude-statusline 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/LICENSE +203 -0
  2. package/README.md +362 -0
  3. package/bin/claude-statusline +22 -0
  4. package/dist/core/cache.d.ts +67 -0
  5. package/dist/core/cache.js +223 -0
  6. package/dist/core/cache.js.map +1 -0
  7. package/dist/core/config.d.ts +190 -0
  8. package/dist/core/config.js +192 -0
  9. package/dist/core/config.js.map +1 -0
  10. package/dist/core/security.d.ts +27 -0
  11. package/dist/core/security.js +154 -0
  12. package/dist/core/security.js.map +1 -0
  13. package/dist/env/context.d.ts +92 -0
  14. package/dist/env/context.js +295 -0
  15. package/dist/env/context.js.map +1 -0
  16. package/dist/git/native.d.ts +35 -0
  17. package/dist/git/native.js +141 -0
  18. package/dist/git/native.js.map +1 -0
  19. package/dist/git/status.d.ts +65 -0
  20. package/dist/git/status.js +256 -0
  21. package/dist/git/status.js.map +1 -0
  22. package/dist/index.bundle.js +11 -0
  23. package/dist/index.d.ts +9 -0
  24. package/dist/index.js +396 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/metafile.prod.json +473 -0
  27. package/dist/ui/symbols.d.ts +31 -0
  28. package/dist/ui/symbols.js +308 -0
  29. package/dist/ui/symbols.js.map +1 -0
  30. package/dist/ui/width.d.ts +29 -0
  31. package/dist/ui/width.js +261 -0
  32. package/dist/ui/width.js.map +1 -0
  33. package/dist/utils/runtime.d.ts +31 -0
  34. package/dist/utils/runtime.js +82 -0
  35. package/dist/utils/runtime.js.map +1 -0
  36. package/docs/ARCHITECTURE.md +336 -0
  37. package/docs/FEATURE_COMPARISON.md +178 -0
  38. package/docs/MIGRATION.md +354 -0
  39. package/docs/README.md +101 -0
  40. package/docs/eval-01-terminal-widths.md +519 -0
  41. package/docs/guide-01-configuration.md +277 -0
  42. package/docs/guide-02-troubleshooting.md +416 -0
  43. package/docs/guide-03-performance.md +183 -0
  44. package/docs/prd-01-typescript-perf-optimization.md +480 -0
  45. package/docs/research-01-sandbox-detection.md +169 -0
  46. package/docs/research-02-competitive-analysis.md +226 -0
  47. package/docs/research-03-platform-analysis.md +142 -0
  48. package/package.json +89 -0
@@ -0,0 +1,27 @@
1
+ import { Config } from './config.js';
2
+ /**
3
+ * Validates JSON input from Claude Code
4
+ * Implements the same security checks as the bash version
5
+ */
6
+ export declare function validateInput(input: string, config: Config): boolean;
7
+ /**
8
+ * Validates file system paths to prevent directory traversal and command injection
9
+ */
10
+ export declare function validatePath(path: string): boolean;
11
+ /**
12
+ * Sanitizes string input for safe display
13
+ * Removes or escapes potentially dangerous characters
14
+ */
15
+ export declare function sanitizeString(input: string, maxLength?: number): string;
16
+ /**
17
+ * Validates that a directory exists and is accessible
18
+ */
19
+ export declare function validateDirectory(path: string): Promise<boolean>;
20
+ /**
21
+ * Security configuration object
22
+ */
23
+ export declare const SECURITY_CONFIG: {
24
+ readonly MAX_INPUT_LENGTH: 1000;
25
+ readonly MAX_PATH_LENGTH: 4096;
26
+ readonly DANGEROUS_PATH_PATTERNS: RegExp[];
27
+ };
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Security-focused input validation
3
+ * Ported from bash script with enhanced TypeScript safety
4
+ */
5
+ /**
6
+ * Maximum allowed input length (matches bash CONFIG_MAX_LENGTH)
7
+ */
8
+ const MAX_INPUT_LENGTH = 1000;
9
+ /**
10
+ * Maximum allowed path length (prevents buffer overflow attacks)
11
+ */
12
+ const MAX_PATH_LENGTH = 4096;
13
+ /**
14
+ * Dangerous characters and patterns to check in paths
15
+ */
16
+ const DANGEROUS_PATH_PATTERNS = [
17
+ /\.\./, // Directory traversal
18
+ /\.\.\\/, // Windows traversal
19
+ /\[/, // Potential command injection
20
+ /;/, // Command separator
21
+ /&/, // Background execution
22
+ /</, // Input redirection
23
+ />/, // Output redirection
24
+ /`/, // Command substitution
25
+ ];
26
+ /**
27
+ * Validates JSON input from Claude Code
28
+ * Implements the same security checks as the bash version
29
+ */
30
+ export function validateInput(input, config) {
31
+ // Basic input sanity checks
32
+ if (!input || typeof input !== 'string') {
33
+ return false;
34
+ }
35
+ // Strip trailing whitespace
36
+ const cleanedInput = input.trimEnd();
37
+ // Length validation
38
+ if (cleanedInput.length === 0 || cleanedInput.length > config.maxLength) {
39
+ return false;
40
+ }
41
+ // Basic JSON structure validation
42
+ if (!cleanedInput.includes('{') || !cleanedInput.includes('}')) {
43
+ return false;
44
+ }
45
+ // Quote validation - must have balanced quotes
46
+ const quoteCount = (cleanedInput.match(/"/g) || []).length;
47
+ if (quoteCount === 0 || quoteCount % 2 !== 0) {
48
+ return false;
49
+ }
50
+ // Try to parse JSON to ensure it's valid
51
+ try {
52
+ JSON.parse(cleanedInput);
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ return true;
58
+ }
59
+ /**
60
+ * Validates file system paths to prevent directory traversal and command injection
61
+ */
62
+ export function validatePath(path) {
63
+ // Basic input validation
64
+ if (!path || typeof path !== 'string') {
65
+ return false;
66
+ }
67
+ // Length validation
68
+ if (path.length > MAX_PATH_LENGTH) {
69
+ return false;
70
+ }
71
+ // Check for dangerous patterns
72
+ for (const pattern of DANGEROUS_PATH_PATTERNS) {
73
+ if (pattern.test(path)) {
74
+ return false;
75
+ }
76
+ }
77
+ // Additional safety checks for common attack vectors
78
+ if (path.includes('${') || path.includes('`') || path.includes('$(')) {
79
+ return false;
80
+ }
81
+ // Normalize path and check for resolved traversal attempts
82
+ try {
83
+ // This would require importing path module, but for now we'll do basic checks
84
+ const normalized = path.replace(/\/+/g, '/').replace(/\\+/g, '\\');
85
+ // Still contains traversal after normalization?
86
+ if (normalized.includes('../') || normalized.includes('..\\')) {
87
+ return false;
88
+ }
89
+ // Check for absolute paths that might be suspicious
90
+ if (normalized.startsWith('/') && !normalized.startsWith('/home/') && !normalized.startsWith('/Users/') && !normalized.startsWith('/tmp/')) {
91
+ // Allow common safe absolute paths but be cautious
92
+ const safeRoots = ['/home', '/Users', '/tmp', '/var', '/opt'];
93
+ const isSafeRoot = safeRoots.some(root => normalized.startsWith(root));
94
+ if (!isSafeRoot) {
95
+ return false;
96
+ }
97
+ }
98
+ // Windows path checks
99
+ if (normalized.includes(':') && /^[A-Za-z]:/.test(normalized)) {
100
+ // Windows drive letter - check if it's a reasonable path
101
+ const driveLetter = normalized.charAt(0).toUpperCase();
102
+ if (driveLetter < 'C' || driveLetter > 'Z') {
103
+ return false;
104
+ }
105
+ }
106
+ }
107
+ catch {
108
+ return false;
109
+ }
110
+ return true;
111
+ }
112
+ /**
113
+ * Sanitizes string input for safe display
114
+ * Removes or escapes potentially dangerous characters
115
+ */
116
+ export function sanitizeString(input, maxLength = 200) {
117
+ if (!input || typeof input !== 'string') {
118
+ return '';
119
+ }
120
+ // Remove control characters except common safe ones
121
+ let sanitized = input.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '');
122
+ // Limit length
123
+ if (sanitized.length > maxLength) {
124
+ sanitized = sanitized.substring(0, maxLength);
125
+ }
126
+ return sanitized;
127
+ }
128
+ /**
129
+ * Validates that a directory exists and is accessible
130
+ */
131
+ export async function validateDirectory(path) {
132
+ if (!validatePath(path)) {
133
+ return false;
134
+ }
135
+ try {
136
+ // Use dynamic import for fs/promises to avoid issues in some environments
137
+ const { access } = await import('fs/promises');
138
+ const { constants } = await import('fs');
139
+ await access(path, constants.R_OK);
140
+ return true;
141
+ }
142
+ catch {
143
+ return false;
144
+ }
145
+ }
146
+ /**
147
+ * Security configuration object
148
+ */
149
+ export const SECURITY_CONFIG = {
150
+ MAX_INPUT_LENGTH,
151
+ MAX_PATH_LENGTH,
152
+ DANGEROUS_PATH_PATTERNS,
153
+ };
154
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/core/security.ts"],"names":[],"mappings":"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","sourcesContent":["import { Config } from './config.js';\n\n/**\n * Security-focused input validation\n * Ported from bash script with enhanced TypeScript safety\n */\n\n/**\n * Maximum allowed input length (matches bash CONFIG_MAX_LENGTH)\n */\nconst MAX_INPUT_LENGTH = 1000;\n\n/**\n * Maximum allowed path length (prevents buffer overflow attacks)\n */\nconst MAX_PATH_LENGTH = 4096;\n\n/**\n * Dangerous characters and patterns to check in paths\n */\nconst DANGEROUS_PATH_PATTERNS = [\n /\\.\\./, // Directory traversal\n /\\.\\.\\\\/, // Windows traversal\n /\\[/, // Potential command injection\n /;/, // Command separator\n /&/, // Background execution\n /</, // Input redirection\n />/, // Output redirection\n /`/, // Command substitution\n];\n\n/**\n * Validates JSON input from Claude Code\n * Implements the same security checks as the bash version\n */\nexport function validateInput(input: string, config: Config): boolean {\n // Basic input sanity checks\n if (!input || typeof input !== 'string') {\n return false;\n }\n\n // Strip trailing whitespace\n const cleanedInput = input.trimEnd();\n\n // Length validation\n if (cleanedInput.length === 0 || cleanedInput.length > config.maxLength) {\n return false;\n }\n\n // Basic JSON structure validation\n if (!cleanedInput.includes('{') || !cleanedInput.includes('}')) {\n return false;\n }\n\n // Quote validation - must have balanced quotes\n const quoteCount = (cleanedInput.match(/\"/g) || []).length;\n if (quoteCount === 0 || quoteCount % 2 !== 0) {\n return false;\n }\n\n // Try to parse JSON to ensure it's valid\n try {\n JSON.parse(cleanedInput);\n } catch {\n return false;\n }\n\n return true;\n}\n\n/**\n * Validates file system paths to prevent directory traversal and command injection\n */\nexport function validatePath(path: string): boolean {\n // Basic input validation\n if (!path || typeof path !== 'string') {\n return false;\n }\n\n // Length validation\n if (path.length > MAX_PATH_LENGTH) {\n return false;\n }\n\n // Check for dangerous patterns\n for (const pattern of DANGEROUS_PATH_PATTERNS) {\n if (pattern.test(path)) {\n return false;\n }\n }\n\n // Additional safety checks for common attack vectors\n if (path.includes('${') || path.includes('`') || path.includes('$(')) {\n return false;\n }\n\n // Normalize path and check for resolved traversal attempts\n try {\n // This would require importing path module, but for now we'll do basic checks\n const normalized = path.replace(/\\/+/g, '/').replace(/\\\\+/g, '\\\\');\n\n // Still contains traversal after normalization?\n if (normalized.includes('../') || normalized.includes('..\\\\')) {\n return false;\n }\n\n // Check for absolute paths that might be suspicious\n if (normalized.startsWith('/') && !normalized.startsWith('/home/') && !normalized.startsWith('/Users/') && !normalized.startsWith('/tmp/')) {\n // Allow common safe absolute paths but be cautious\n const safeRoots = ['/home', '/Users', '/tmp', '/var', '/opt'];\n const isSafeRoot = safeRoots.some(root => normalized.startsWith(root));\n if (!isSafeRoot) {\n return false;\n }\n }\n\n // Windows path checks\n if (normalized.includes(':') && /^[A-Za-z]:/.test(normalized)) {\n // Windows drive letter - check if it's a reasonable path\n const driveLetter = normalized.charAt(0).toUpperCase();\n if (driveLetter < 'C' || driveLetter > 'Z') {\n return false;\n }\n }\n\n } catch {\n return false;\n }\n\n return true;\n}\n\n/**\n * Sanitizes string input for safe display\n * Removes or escapes potentially dangerous characters\n */\nexport function sanitizeString(input: string, maxLength: number = 200): string {\n if (!input || typeof input !== 'string') {\n return '';\n }\n\n // Remove control characters except common safe ones\n let sanitized = input.replace(/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F]/g, '');\n\n // Limit length\n if (sanitized.length > maxLength) {\n sanitized = sanitized.substring(0, maxLength);\n }\n\n return sanitized;\n}\n\n/**\n * Validates that a directory exists and is accessible\n */\nexport async function validateDirectory(path: string): Promise<boolean> {\n if (!validatePath(path)) {\n return false;\n }\n\n try {\n // Use dynamic import for fs/promises to avoid issues in some environments\n const { access } = await import('fs/promises');\n const { constants } = await import('fs');\n\n await access(path, constants.R_OK);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Security configuration object\n */\nexport const SECURITY_CONFIG = {\n MAX_INPUT_LENGTH,\n MAX_PATH_LENGTH,\n DANGEROUS_PATH_PATTERNS,\n} as const;"]}
@@ -0,0 +1,92 @@
1
+ import { Config } from '../core/config.js';
2
+ import { Cache } from '../core/cache.js';
3
+ import { getEnvironmentSymbols } from '../ui/symbols.js';
4
+ /**
5
+ * Environment version information interface
6
+ */
7
+ export interface EnvironmentInfo {
8
+ node?: string;
9
+ python?: string;
10
+ docker?: string;
11
+ }
12
+ /**
13
+ * Environment context detection
14
+ * Ported from bash implementation with enhanced TypeScript safety
15
+ */
16
+ export declare class EnvironmentDetector {
17
+ private config;
18
+ private cache;
19
+ constructor(config: Config, cache: Cache);
20
+ /**
21
+ * Get environment information if context is enabled
22
+ */
23
+ getEnvironmentInfo(): Promise<EnvironmentInfo | null>;
24
+ /**
25
+ * Get Node.js version with caching
26
+ */
27
+ private getNodeVersion;
28
+ /**
29
+ * Get Python version with caching (tries python3 first, then python)
30
+ */
31
+ private getPythonVersion;
32
+ /**
33
+ * Get Docker version with caching
34
+ */
35
+ private getDockerVersion;
36
+ /**
37
+ * Format environment information for display
38
+ */
39
+ formatEnvironmentInfo(envInfo: EnvironmentInfo, symbols: ReturnType<typeof getEnvironmentSymbols>): string;
40
+ /**
41
+ * Get additional tool versions (for future expansion)
42
+ */
43
+ getAdditionalTools(): Promise<{
44
+ [key: string]: string;
45
+ }>;
46
+ /**
47
+ * Check if a specific tool is available in the environment
48
+ */
49
+ isToolAvailable(tool: string): Promise<boolean>;
50
+ /**
51
+ * Get shell environment information
52
+ */
53
+ getShellEnvironment(): {
54
+ shell: string;
55
+ shellVersion?: string;
56
+ };
57
+ /**
58
+ * Get operating system information
59
+ */
60
+ getOSInfo(): {
61
+ platform: string;
62
+ arch: string;
63
+ release?: string;
64
+ };
65
+ }
66
+ /**
67
+ * Environment information formatter for different display modes
68
+ */
69
+ export declare class EnvironmentFormatter {
70
+ private symbols;
71
+ constructor(symbols: ReturnType<typeof getEnvironmentSymbols>);
72
+ /**
73
+ * Format environment info in different styles
74
+ */
75
+ format(envInfo: EnvironmentInfo, style?: 'compact' | 'verbose' | 'minimal'): string;
76
+ /**
77
+ * Compact format: Node22.17 Py3.13 Docker28.3
78
+ */
79
+ private formatCompact;
80
+ /**
81
+ * Verbose format: Node.js v22.17.1 • Python 3.13.5 • Docker 28.3.3
82
+ */
83
+ private formatVerbose;
84
+ /**
85
+ * Minimal format: N22 P17 D28 (just major versions)
86
+ */
87
+ private formatMinimal;
88
+ /**
89
+ * Format with icons: 22.17 3.13 28.3
90
+ */
91
+ formatWithIcons(envInfo: EnvironmentInfo): string;
92
+ }
@@ -0,0 +1,295 @@
1
+ import { cachedCommand, CacheKeys } from '../core/cache.js';
2
+ /**
3
+ * Environment context detection
4
+ * Ported from bash implementation with enhanced TypeScript safety
5
+ */
6
+ export class EnvironmentDetector {
7
+ config;
8
+ cache;
9
+ constructor(config, cache) {
10
+ this.config = config;
11
+ this.cache = cache;
12
+ }
13
+ /**
14
+ * Get environment information if context is enabled
15
+ */
16
+ async getEnvironmentInfo() {
17
+ if (!this.config.envContext) {
18
+ return null;
19
+ }
20
+ const envInfo = {};
21
+ // Get version information in parallel for better performance
22
+ const [nodeVersion, pythonVersion, dockerVersion] = await Promise.allSettled([
23
+ this.getNodeVersion(),
24
+ this.getPythonVersion(),
25
+ this.getDockerVersion(),
26
+ ]);
27
+ if (nodeVersion.status === 'fulfilled' && nodeVersion.value) {
28
+ envInfo.node = nodeVersion.value;
29
+ }
30
+ if (pythonVersion.status === 'fulfilled' && pythonVersion.value) {
31
+ envInfo.python = pythonVersion.value;
32
+ }
33
+ if (dockerVersion.status === 'fulfilled' && dockerVersion.value) {
34
+ envInfo.docker = dockerVersion.value;
35
+ }
36
+ // Return null if no environment versions were found
37
+ if (Object.keys(envInfo).length === 0) {
38
+ return null;
39
+ }
40
+ return envInfo;
41
+ }
42
+ /**
43
+ * Get Node.js version with caching
44
+ */
45
+ async getNodeVersion() {
46
+ const cacheKey = CacheKeys.NODE_VERSION;
47
+ // Environment versions change rarely, cache for 8 hours (96x default TTL)
48
+ // Covers a full workday - users rarely update Node/Python/Docker multiple times per day
49
+ const envCacheTTL = this.config.cacheTTL * 96;
50
+ // Try cache first
51
+ const cached = await this.cache.get(cacheKey, envCacheTTL);
52
+ if (cached) {
53
+ return cached;
54
+ }
55
+ try {
56
+ // Method 1: node --version
57
+ let version = await cachedCommand(this.cache, cacheKey, 'node', ['--version'], envCacheTTL);
58
+ if (version) {
59
+ // Remove 'v' prefix and clean up
60
+ return version.replace(/^v/, '').trim();
61
+ }
62
+ return null;
63
+ }
64
+ catch (error) {
65
+ console.debug('[DEBUG] Failed to get Node.js version:', error instanceof Error ? error.message : String(error));
66
+ return null;
67
+ }
68
+ }
69
+ /**
70
+ * Get Python version with caching (tries python3 first, then python)
71
+ */
72
+ async getPythonVersion() {
73
+ const python3Key = CacheKeys.PYTHON3_VERSION;
74
+ const pythonKey = CacheKeys.PYTHON_VERSION;
75
+ // Environment versions change rarely, cache for 8 hours (96x default TTL)
76
+ // Covers a full workday - users rarely update Node/Python/Docker multiple times per day
77
+ const envCacheTTL = this.config.cacheTTL * 96;
78
+ // Try python3 first
79
+ try {
80
+ let version = await cachedCommand(this.cache, python3Key, 'python3', ['--version'], envCacheTTL);
81
+ if (version) {
82
+ // Extract version number from "Python 3.x.y" format
83
+ const versionMatch = version.match(/(\d+\.\d+\.\d+)/);
84
+ if (versionMatch) {
85
+ return versionMatch[1] || null;
86
+ }
87
+ }
88
+ }
89
+ catch {
90
+ // python3 not available, try python
91
+ }
92
+ // Fallback to python
93
+ try {
94
+ let version = await cachedCommand(this.cache, pythonKey, 'python', ['--version'], envCacheTTL);
95
+ if (version) {
96
+ // Extract version number from "Python 3.x.y" or "Python 2.x.y" format
97
+ const versionMatch = version.match(/(\d+\.\d+\.\d+)/);
98
+ if (versionMatch) {
99
+ return versionMatch[1] || null;
100
+ }
101
+ }
102
+ }
103
+ catch {
104
+ // python not available either
105
+ }
106
+ return null;
107
+ }
108
+ /**
109
+ * Get Docker version with caching
110
+ */
111
+ async getDockerVersion() {
112
+ const cacheKey = 'docker_version';
113
+ try {
114
+ let version = await cachedCommand(this.cache, cacheKey, 'docker', ['--version'], this.config.cacheTTL * 96 // Longer TTL for Docker (8 hours vs 5 minutes)
115
+ );
116
+ if (version) {
117
+ // Extract version number from "Docker version 20.x.y" format
118
+ const versionMatch = version.match(/Docker version (\d+\.\d+\.\d+)/);
119
+ if (versionMatch) {
120
+ return versionMatch[1] || null;
121
+ }
122
+ }
123
+ return null;
124
+ }
125
+ catch (error) {
126
+ console.debug('[DEBUG] Failed to get Docker version:', error instanceof Error ? error.message : String(error));
127
+ return null;
128
+ }
129
+ }
130
+ /**
131
+ * Format environment information for display
132
+ */
133
+ formatEnvironmentInfo(envInfo, symbols) {
134
+ const parts = [];
135
+ if (envInfo.node) {
136
+ parts.push(`${symbols.node}${envInfo.node}`);
137
+ }
138
+ if (envInfo.python) {
139
+ parts.push(`${symbols.python}${envInfo.python}`);
140
+ }
141
+ if (envInfo.docker) {
142
+ parts.push(`${symbols.docker}${envInfo.docker}`);
143
+ }
144
+ return parts.join(' ');
145
+ }
146
+ /**
147
+ * Get additional tool versions (for future expansion)
148
+ */
149
+ async getAdditionalTools() {
150
+ const additionalTools = {};
151
+ // Future tools could include:
152
+ // - Go version
153
+ // - Rust version
154
+ // - Java version
155
+ // - Ruby version
156
+ // - Kubernetes version
157
+ // - Helm version
158
+ // - etc.
159
+ return additionalTools;
160
+ }
161
+ /**
162
+ * Check if a specific tool is available in the environment
163
+ */
164
+ async isToolAvailable(tool) {
165
+ try {
166
+ const { exec } = await import('child_process');
167
+ const { promisify } = await import('util');
168
+ const execAsync = promisify(exec);
169
+ await execAsync(`command -v ${tool}`, { timeout: 2000 });
170
+ return true;
171
+ }
172
+ catch {
173
+ return false;
174
+ }
175
+ }
176
+ /**
177
+ * Get shell environment information
178
+ */
179
+ getShellEnvironment() {
180
+ const shell = process.env.SHELL || 'unknown';
181
+ // Try to extract shell version (basic implementation)
182
+ let shellVersion;
183
+ if (shell.includes('bash')) {
184
+ shellVersion = process.env.BASH_VERSION;
185
+ }
186
+ else if (shell.includes('zsh')) {
187
+ shellVersion = process.env.ZSH_VERSION;
188
+ }
189
+ else if (shell.includes('fish')) {
190
+ shellVersion = process.env.FISH_VERSION;
191
+ }
192
+ return shellVersion ? { shell, shellVersion } : { shell };
193
+ }
194
+ /**
195
+ * Get operating system information
196
+ */
197
+ getOSInfo() {
198
+ const platform = process.platform;
199
+ const arch = process.arch;
200
+ const release = process.env.OSTYPE || process.env.OS;
201
+ return release ? { platform, arch, release } : { platform, arch };
202
+ }
203
+ }
204
+ /**
205
+ * Environment information formatter for different display modes
206
+ */
207
+ export class EnvironmentFormatter {
208
+ symbols;
209
+ constructor(symbols) {
210
+ this.symbols = symbols;
211
+ }
212
+ /**
213
+ * Format environment info in different styles
214
+ */
215
+ format(envInfo, style = 'compact') {
216
+ switch (style) {
217
+ case 'compact':
218
+ return this.formatCompact(envInfo);
219
+ case 'verbose':
220
+ return this.formatVerbose(envInfo);
221
+ case 'minimal':
222
+ return this.formatMinimal(envInfo);
223
+ default:
224
+ return this.formatCompact(envInfo);
225
+ }
226
+ }
227
+ /**
228
+ * Compact format: Node22.17 Py3.13 Docker28.3
229
+ */
230
+ formatCompact(envInfo) {
231
+ const parts = [];
232
+ if (envInfo.node) {
233
+ parts.push(`Node${envInfo.node}`);
234
+ }
235
+ if (envInfo.python) {
236
+ parts.push(`Py${envInfo.python}`);
237
+ }
238
+ if (envInfo.docker) {
239
+ parts.push(`Docker${envInfo.docker}`);
240
+ }
241
+ return parts.join(' ');
242
+ }
243
+ /**
244
+ * Verbose format: Node.js v22.17.1 • Python 3.13.5 • Docker 28.3.3
245
+ */
246
+ formatVerbose(envInfo) {
247
+ const parts = [];
248
+ if (envInfo.node) {
249
+ parts.push(`Node.js v${envInfo.node}`);
250
+ }
251
+ if (envInfo.python) {
252
+ parts.push(`Python ${envInfo.python}`);
253
+ }
254
+ if (envInfo.docker) {
255
+ parts.push(`Docker ${envInfo.docker}`);
256
+ }
257
+ return parts.join(' • ');
258
+ }
259
+ /**
260
+ * Minimal format: N22 P17 D28 (just major versions)
261
+ */
262
+ formatMinimal(envInfo) {
263
+ const parts = [];
264
+ if (envInfo.node) {
265
+ const majorVersion = envInfo.node.split('.')[0];
266
+ parts.push(`N${majorVersion}`);
267
+ }
268
+ if (envInfo.python) {
269
+ const majorVersion = envInfo.python.split('.')[0];
270
+ parts.push(`P${majorVersion}`);
271
+ }
272
+ if (envInfo.docker) {
273
+ const majorVersion = envInfo.docker.split('.')[0];
274
+ parts.push(`D${majorVersion}`);
275
+ }
276
+ return parts.join(' ');
277
+ }
278
+ /**
279
+ * Format with icons: 22.17 3.13 28.3
280
+ */
281
+ formatWithIcons(envInfo) {
282
+ const parts = [];
283
+ if (envInfo.node) {
284
+ parts.push(`${this.symbols.node}${envInfo.node}`);
285
+ }
286
+ if (envInfo.python) {
287
+ parts.push(`${this.symbols.python}${envInfo.python}`);
288
+ }
289
+ if (envInfo.docker) {
290
+ parts.push(`${this.symbols.docker}${envInfo.docker}`);
291
+ }
292
+ return parts.join(' ');
293
+ }
294
+ }
295
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/env/context.ts"],"names":[],"mappings":"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","sourcesContent":["import { Config } from '../core/config.js';\nimport { Cache, cachedCommand, CacheKeys } from '../core/cache.js';\nimport { getEnvironmentSymbols } from '../ui/symbols.js';\n\n/**\n * Environment version information interface\n */\nexport interface EnvironmentInfo {\n node?: string;\n python?: string;\n docker?: string;\n}\n\n/**\n * Environment context detection\n * Ported from bash implementation with enhanced TypeScript safety\n */\nexport class EnvironmentDetector {\n private config: Config;\n private cache: Cache;\n\n constructor(config: Config, cache: Cache) {\n this.config = config;\n this.cache = cache;\n }\n\n /**\n * Get environment information if context is enabled\n */\n async getEnvironmentInfo(): Promise<EnvironmentInfo | null> {\n if (!this.config.envContext) {\n return null;\n }\n\n const envInfo: EnvironmentInfo = {};\n\n // Get version information in parallel for better performance\n const [nodeVersion, pythonVersion, dockerVersion] = await Promise.allSettled([\n this.getNodeVersion(),\n this.getPythonVersion(),\n this.getDockerVersion(),\n ]);\n\n if (nodeVersion.status === 'fulfilled' && nodeVersion.value) {\n envInfo.node = nodeVersion.value;\n }\n\n if (pythonVersion.status === 'fulfilled' && pythonVersion.value) {\n envInfo.python = pythonVersion.value;\n }\n\n if (dockerVersion.status === 'fulfilled' && dockerVersion.value) {\n envInfo.docker = dockerVersion.value;\n }\n\n // Return null if no environment versions were found\n if (Object.keys(envInfo).length === 0) {\n return null;\n }\n\n return envInfo;\n }\n\n /**\n * Get Node.js version with caching\n */\n private async getNodeVersion(): Promise<string | null> {\n const cacheKey = CacheKeys.NODE_VERSION;\n // Environment versions change rarely, cache for 8 hours (96x default TTL)\n // Covers a full workday - users rarely update Node/Python/Docker multiple times per day\n const envCacheTTL = this.config.cacheTTL * 96;\n\n // Try cache first\n const cached = await this.cache.get<string>(cacheKey, envCacheTTL);\n if (cached) {\n return cached;\n }\n\n try {\n // Method 1: node --version\n let version = await cachedCommand(\n this.cache,\n cacheKey,\n 'node',\n ['--version'],\n envCacheTTL\n );\n\n if (version) {\n // Remove 'v' prefix and clean up\n return version.replace(/^v/, '').trim();\n }\n\n return null;\n\n } catch (error) {\n console.debug('[DEBUG] Failed to get Node.js version:', error instanceof Error ? error.message : String(error));\n return null;\n }\n }\n\n /**\n * Get Python version with caching (tries python3 first, then python)\n */\n private async getPythonVersion(): Promise<string | null> {\n const python3Key = CacheKeys.PYTHON3_VERSION;\n const pythonKey = CacheKeys.PYTHON_VERSION;\n // Environment versions change rarely, cache for 8 hours (96x default TTL)\n // Covers a full workday - users rarely update Node/Python/Docker multiple times per day\n const envCacheTTL = this.config.cacheTTL * 96;\n\n // Try python3 first\n try {\n let version = await cachedCommand(\n this.cache,\n python3Key,\n 'python3',\n ['--version'],\n envCacheTTL\n );\n\n if (version) {\n // Extract version number from \"Python 3.x.y\" format\n const versionMatch = version.match(/(\\d+\\.\\d+\\.\\d+)/);\n if (versionMatch) {\n return versionMatch[1] || null;\n }\n }\n } catch {\n // python3 not available, try python\n }\n\n // Fallback to python\n try {\n let version = await cachedCommand(\n this.cache,\n pythonKey,\n 'python',\n ['--version'],\n envCacheTTL\n );\n\n if (version) {\n // Extract version number from \"Python 3.x.y\" or \"Python 2.x.y\" format\n const versionMatch = version.match(/(\\d+\\.\\d+\\.\\d+)/);\n if (versionMatch) {\n return versionMatch[1] || null;\n }\n }\n } catch {\n // python not available either\n }\n\n return null;\n }\n\n /**\n * Get Docker version with caching\n */\n private async getDockerVersion(): Promise<string | null> {\n const cacheKey = 'docker_version';\n\n try {\n let version = await cachedCommand(\n this.cache,\n cacheKey,\n 'docker',\n ['--version'],\n this.config.cacheTTL * 96 // Longer TTL for Docker (8 hours vs 5 minutes)\n );\n\n if (version) {\n // Extract version number from \"Docker version 20.x.y\" format\n const versionMatch = version.match(/Docker version (\\d+\\.\\d+\\.\\d+)/);\n if (versionMatch) {\n return versionMatch[1] || null;\n }\n }\n\n return null;\n\n } catch (error) {\n console.debug('[DEBUG] Failed to get Docker version:', error instanceof Error ? error.message : String(error));\n return null;\n }\n }\n\n /**\n * Format environment information for display\n */\n formatEnvironmentInfo(envInfo: EnvironmentInfo, symbols: ReturnType<typeof getEnvironmentSymbols>): string {\n const parts: string[] = [];\n\n if (envInfo.node) {\n parts.push(`${symbols.node}${envInfo.node}`);\n }\n\n if (envInfo.python) {\n parts.push(`${symbols.python}${envInfo.python}`);\n }\n\n if (envInfo.docker) {\n parts.push(`${symbols.docker}${envInfo.docker}`);\n }\n\n return parts.join(' ');\n }\n\n /**\n * Get additional tool versions (for future expansion)\n */\n async getAdditionalTools(): Promise<{ [key: string]: string }> {\n const additionalTools: { [key: string]: string } = {};\n\n // Future tools could include:\n // - Go version\n // - Rust version\n // - Java version\n // - Ruby version\n // - Kubernetes version\n // - Helm version\n // - etc.\n\n return additionalTools;\n }\n\n /**\n * Check if a specific tool is available in the environment\n */\n async isToolAvailable(tool: string): Promise<boolean> {\n try {\n const { exec } = await import('child_process');\n const { promisify } = await import('util');\n const execAsync = promisify(exec);\n\n await execAsync(`command -v ${tool}`, { timeout: 2000 });\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * Get shell environment information\n */\n getShellEnvironment(): { shell: string; shellVersion?: string } {\n const shell = process.env.SHELL || 'unknown';\n\n // Try to extract shell version (basic implementation)\n let shellVersion: string | undefined;\n\n if (shell.includes('bash')) {\n shellVersion = process.env.BASH_VERSION;\n } else if (shell.includes('zsh')) {\n shellVersion = process.env.ZSH_VERSION;\n } else if (shell.includes('fish')) {\n shellVersion = process.env.FISH_VERSION;\n }\n\n return shellVersion ? { shell, shellVersion } : { shell };\n }\n\n /**\n * Get operating system information\n */\n getOSInfo(): { platform: string; arch: string; release?: string } {\n const platform = process.platform;\n const arch = process.arch;\n const release = process.env.OSTYPE || process.env.OS;\n\n return release ? { platform, arch, release } : { platform, arch };\n }\n}\n\n/**\n * Environment information formatter for different display modes\n */\nexport class EnvironmentFormatter {\n private symbols: ReturnType<typeof getEnvironmentSymbols>;\n\n constructor(symbols: ReturnType<typeof getEnvironmentSymbols>) {\n this.symbols = symbols;\n }\n\n /**\n * Format environment info in different styles\n */\n format(envInfo: EnvironmentInfo, style: 'compact' | 'verbose' | 'minimal' = 'compact'): string {\n switch (style) {\n case 'compact':\n return this.formatCompact(envInfo);\n case 'verbose':\n return this.formatVerbose(envInfo);\n case 'minimal':\n return this.formatMinimal(envInfo);\n default:\n return this.formatCompact(envInfo);\n }\n }\n\n /**\n * Compact format: Node22.17 Py3.13 Docker28.3\n */\n private formatCompact(envInfo: EnvironmentInfo): string {\n const parts: string[] = [];\n\n if (envInfo.node) {\n parts.push(`Node${envInfo.node}`);\n }\n\n if (envInfo.python) {\n parts.push(`Py${envInfo.python}`);\n }\n\n if (envInfo.docker) {\n parts.push(`Docker${envInfo.docker}`);\n }\n\n return parts.join(' ');\n }\n\n /**\n * Verbose format: Node.js v22.17.1 • Python 3.13.5 • Docker 28.3.3\n */\n private formatVerbose(envInfo: EnvironmentInfo): string {\n const parts: string[] = [];\n\n if (envInfo.node) {\n parts.push(`Node.js v${envInfo.node}`);\n }\n\n if (envInfo.python) {\n parts.push(`Python ${envInfo.python}`);\n }\n\n if (envInfo.docker) {\n parts.push(`Docker ${envInfo.docker}`);\n }\n\n return parts.join(' • ');\n }\n\n /**\n * Minimal format: N22 P17 D28 (just major versions)\n */\n private formatMinimal(envInfo: EnvironmentInfo): string {\n const parts: string[] = [];\n\n if (envInfo.node) {\n const majorVersion = envInfo.node.split('.')[0];\n parts.push(`N${majorVersion}`);\n }\n\n if (envInfo.python) {\n const majorVersion = envInfo.python.split('.')[0];\n parts.push(`P${majorVersion}`);\n }\n\n if (envInfo.docker) {\n const majorVersion = envInfo.docker.split('.')[0];\n parts.push(`D${majorVersion}`);\n }\n\n return parts.join(' ');\n }\n\n /**\n * Format with icons: 22.17 3.13 28.3\n */\n formatWithIcons(envInfo: EnvironmentInfo): string {\n const parts: string[] = [];\n\n if (envInfo.node) {\n parts.push(`${this.symbols.node}${envInfo.node}`);\n }\n\n if (envInfo.python) {\n parts.push(`${this.symbols.python}${envInfo.python}`);\n }\n\n if (envInfo.docker) {\n parts.push(`${this.symbols.docker}${envInfo.docker}`);\n }\n\n return parts.join(' ');\n }\n}"]}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Execute a git command using child_process.spawn
3
+ * Provides native git execution without external dependencies
4
+ */
5
+ export declare function executeGitCommand(args: string[], options?: {
6
+ cwd?: string;
7
+ timeout?: number;
8
+ }): Promise<string>;
9
+ /**
10
+ * Check if directory is a git repository
11
+ */
12
+ export declare function checkIsRepo(cwd?: string): Promise<boolean>;
13
+ /**
14
+ * Get current branch name using multiple fallback methods
15
+ */
16
+ export declare function getCurrentBranch(cwd?: string): Promise<string | null>;
17
+ /**
18
+ * Get git status in porcelain format
19
+ */
20
+ export declare function getPorcelainStatus(cwd?: string): Promise<string>;
21
+ /**
22
+ * Get stash list
23
+ */
24
+ export declare function getStashList(cwd?: string): Promise<string>;
25
+ /**
26
+ * Get upstream branch reference
27
+ */
28
+ export declare function getUpstreamRef(cwd?: string): Promise<string>;
29
+ /**
30
+ * Get ahead/behind counts
31
+ */
32
+ export declare function getAheadBehind(cwd?: string): Promise<{
33
+ ahead: number;
34
+ behind: number;
35
+ }>;