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.
- package/LICENSE +203 -0
- package/README.md +362 -0
- package/bin/claude-statusline +22 -0
- package/dist/core/cache.d.ts +67 -0
- package/dist/core/cache.js +223 -0
- package/dist/core/cache.js.map +1 -0
- package/dist/core/config.d.ts +190 -0
- package/dist/core/config.js +192 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/security.d.ts +27 -0
- package/dist/core/security.js +154 -0
- package/dist/core/security.js.map +1 -0
- package/dist/env/context.d.ts +92 -0
- package/dist/env/context.js +295 -0
- package/dist/env/context.js.map +1 -0
- package/dist/git/native.d.ts +35 -0
- package/dist/git/native.js +141 -0
- package/dist/git/native.js.map +1 -0
- package/dist/git/status.d.ts +65 -0
- package/dist/git/status.js +256 -0
- package/dist/git/status.js.map +1 -0
- package/dist/index.bundle.js +11 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +396 -0
- package/dist/index.js.map +1 -0
- package/dist/metafile.prod.json +473 -0
- package/dist/ui/symbols.d.ts +31 -0
- package/dist/ui/symbols.js +308 -0
- package/dist/ui/symbols.js.map +1 -0
- package/dist/ui/width.d.ts +29 -0
- package/dist/ui/width.js +261 -0
- package/dist/ui/width.js.map +1 -0
- package/dist/utils/runtime.d.ts +31 -0
- package/dist/utils/runtime.js +82 -0
- package/dist/utils/runtime.js.map +1 -0
- package/docs/ARCHITECTURE.md +336 -0
- package/docs/FEATURE_COMPARISON.md +178 -0
- package/docs/MIGRATION.md +354 -0
- package/docs/README.md +101 -0
- package/docs/eval-01-terminal-widths.md +519 -0
- package/docs/guide-01-configuration.md +277 -0
- package/docs/guide-02-troubleshooting.md +416 -0
- package/docs/guide-03-performance.md +183 -0
- package/docs/prd-01-typescript-perf-optimization.md +480 -0
- package/docs/research-01-sandbox-detection.md +169 -0
- package/docs/research-02-competitive-analysis.md +226 -0
- package/docs/research-03-platform-analysis.md +142 -0
- 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":"AAEA;;;GAGG;AAEH;;GAEG;AACH,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAE9B;;GAEG;AACH,MAAM,eAAe,GAAG,IAAI,CAAC;AAE7B;;GAEG;AACH,MAAM,uBAAuB,GAAG;IAC9B,MAAM,EAAE,sBAAsB;IAC9B,QAAQ,EAAE,oBAAoB;IAC9B,IAAI,EAAE,8BAA8B;IACpC,GAAG,EAAE,oBAAoB;IACzB,GAAG,EAAE,uBAAuB;IAC5B,GAAG,EAAE,oBAAoB;IACzB,GAAG,EAAE,qBAAqB;IAC1B,GAAG,EAAE,uBAAuB;CAC7B,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,MAAc;IACzD,4BAA4B;IAC5B,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,4BAA4B;IAC5B,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;IAErC,oBAAoB;IACpB,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,YAAY,CAAC,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QACxE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,kCAAkC;IAClC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/D,OAAO,KAAK,CAAC;IACf,CAAC;IAED,+CAA+C;IAC/C,MAAM,UAAU,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;IAC3D,IAAI,UAAU,KAAK,CAAC,IAAI,UAAU,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,yCAAyC;IACzC,IAAI,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,yBAAyB;IACzB,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,oBAAoB;IACpB,IAAI,IAAI,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QAClC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,+BAA+B;IAC/B,KAAK,MAAM,OAAO,IAAI,uBAAuB,EAAE,CAAC;QAC9C,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,qDAAqD;IACrD,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACrE,OAAO,KAAK,CAAC;IACf,CAAC;IAED,2DAA2D;IAC3D,IAAI,CAAC;QACH,8EAA8E;QAC9E,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAEnE,gDAAgD;QAChD,IAAI,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9D,OAAO,KAAK,CAAC;QACf,CAAC;QAED,oDAAoD;QACpD,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3I,mDAAmD;YACnD,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;YAC9D,MAAM,UAAU,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;YACvE,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QAED,sBAAsB;QACtB,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9D,yDAAyD;YACzD,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;YACvD,IAAI,WAAW,GAAG,GAAG,IAAI,WAAW,GAAG,GAAG,EAAE,CAAC;gBAC3C,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;IAEH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa,EAAE,YAAoB,GAAG;IACnE,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,oDAAoD;IACpD,IAAI,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,mCAAmC,EAAE,EAAE,CAAC,CAAC;IAEvE,eAAe;IACf,IAAI,SAAS,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QACjC,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAChD,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAY;IAClD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC;QACH,0EAA0E;QAC1E,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QAC/C,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QAEzC,MAAM,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,gBAAgB;IAChB,eAAe;IACf,uBAAuB;CACf,CAAC","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
|
+
}>;
|