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,223 @@
1
+ import { readFile, writeFile, mkdir } from 'fs/promises';
2
+ import { existsSync } from 'fs';
3
+ import { join } from 'path';
4
+ /**
5
+ * Simple caching system with TTL support
6
+ * Ported from bash implementation with Node.js optimizations
7
+ */
8
+ /**
9
+ * Cache wrapper that handles TTL and file operations
10
+ */
11
+ export class Cache {
12
+ config;
13
+ constructor(config) {
14
+ this.config = config;
15
+ }
16
+ /**
17
+ * Ensure cache directory exists
18
+ */
19
+ async ensureCacheDir() {
20
+ try {
21
+ await mkdir(this.config.cacheDir, { recursive: true });
22
+ }
23
+ catch (error) {
24
+ // Directory might already exist or we can't create it
25
+ console.warn('[WARNING] Failed to create cache directory:', this.config.cacheDir);
26
+ }
27
+ }
28
+ /**
29
+ * Get cache file path for a given key
30
+ */
31
+ getCachePath(key) {
32
+ return join(this.config.cacheDir, key);
33
+ }
34
+ /**
35
+ * Get cache timestamp file path for a given key
36
+ */
37
+ getTimestampPath(key) {
38
+ return join(this.config.cacheDir, `${key}.time`);
39
+ }
40
+ /**
41
+ * Read cached data with TTL validation
42
+ */
43
+ async get(key, ttl = this.config.cacheTTL) {
44
+ const cachePath = this.getCachePath(key);
45
+ const timestampPath = this.getTimestampPath(key);
46
+ try {
47
+ // Check if cache files exist
48
+ if (!existsSync(cachePath) || !existsSync(timestampPath)) {
49
+ return null;
50
+ }
51
+ // Read timestamp and check TTL
52
+ const timestampContent = await readFile(timestampPath, 'utf-8');
53
+ const timestamp = parseInt(timestampContent.trim(), 10);
54
+ if (isNaN(timestamp)) {
55
+ return null;
56
+ }
57
+ const currentTime = Math.floor(Date.now() / 1000);
58
+ const age = currentTime - timestamp;
59
+ // In development, reduce cache TTL to prevent stale data
60
+ const effectiveTTL = process.env.NODE_ENV === 'development' ? Math.min(ttl, 5) : ttl;
61
+ if (age >= effectiveTTL) {
62
+ // Cache expired
63
+ return null;
64
+ }
65
+ // Read cached data
66
+ const dataContent = await readFile(cachePath, 'utf-8');
67
+ // Try to parse as JSON, fallback to string
68
+ try {
69
+ return JSON.parse(dataContent);
70
+ }
71
+ catch {
72
+ return dataContent;
73
+ }
74
+ }
75
+ catch (error) {
76
+ // Any error reading cache should result in cache miss
77
+ console.debug('[DEBUG] Cache read error for key:', key, error instanceof Error ? error.message : String(error));
78
+ return null;
79
+ }
80
+ }
81
+ /**
82
+ * Write data to cache with timestamp
83
+ */
84
+ async set(key, data) {
85
+ const cachePath = this.getCachePath(key);
86
+ const timestampPath = this.getTimestampPath(key);
87
+ try {
88
+ // Ensure cache directory exists
89
+ await this.ensureCacheDir();
90
+ // Prepare data for storage
91
+ let dataContent;
92
+ if (typeof data === 'string') {
93
+ dataContent = data;
94
+ }
95
+ else {
96
+ dataContent = JSON.stringify(data);
97
+ }
98
+ // Write data and timestamp
99
+ const currentTime = Math.floor(Date.now() / 1000);
100
+ await Promise.all([
101
+ writeFile(cachePath, dataContent, 'utf-8'),
102
+ writeFile(timestampPath, currentTime.toString(), 'utf-8'),
103
+ ]);
104
+ return true;
105
+ }
106
+ catch (error) {
107
+ console.warn('[WARNING] Failed to write cache for key:', key, error instanceof Error ? error.message : String(error));
108
+ return false;
109
+ }
110
+ }
111
+ /**
112
+ * Check if cache entry exists and is valid
113
+ */
114
+ async has(key, ttl = this.config.cacheTTL) {
115
+ const value = await this.get(key, ttl);
116
+ return value !== null;
117
+ }
118
+ /**
119
+ * Delete cache entry
120
+ */
121
+ async delete(key) {
122
+ const cachePath = this.getCachePath(key);
123
+ const timestampPath = this.getTimestampPath(key);
124
+ try {
125
+ const { unlink } = await import('fs/promises');
126
+ await Promise.allSettled([
127
+ unlink(cachePath),
128
+ unlink(timestampPath),
129
+ ]);
130
+ return true;
131
+ }
132
+ catch (error) {
133
+ console.warn('[WARNING] Failed to delete cache for key:', key, error instanceof Error ? error.message : String(error));
134
+ return false;
135
+ }
136
+ }
137
+ /**
138
+ * Clear all cache entries
139
+ */
140
+ async clear() {
141
+ try {
142
+ const { readdir, unlink } = await import('fs/promises');
143
+ const files = await readdir(this.config.cacheDir);
144
+ await Promise.allSettled(files.map(file => unlink(join(this.config.cacheDir, file))));
145
+ return true;
146
+ }
147
+ catch (error) {
148
+ console.warn('[WARNING] Failed to clear cache:', error instanceof Error ? error.message : String(error));
149
+ return false;
150
+ }
151
+ }
152
+ /**
153
+ * Get cache statistics
154
+ */
155
+ async getStats() {
156
+ try {
157
+ const { readdir, stat } = await import('fs/promises');
158
+ const files = await readdir(this.config.cacheDir);
159
+ let totalSize = 0;
160
+ let cacheFiles = 0;
161
+ for (const file of files) {
162
+ if (!file.endsWith('.time')) {
163
+ cacheFiles++;
164
+ const filePath = join(this.config.cacheDir, file);
165
+ try {
166
+ const stats = await stat(filePath);
167
+ totalSize += stats.size;
168
+ }
169
+ catch {
170
+ // Skip files that can't be stat'ed
171
+ }
172
+ }
173
+ }
174
+ return { total: cacheFiles, size: totalSize };
175
+ }
176
+ catch (error) {
177
+ console.warn('[WARNING] Failed to get cache stats:', error instanceof Error ? error.message : String(error));
178
+ return { total: 0, size: 0 };
179
+ }
180
+ }
181
+ }
182
+ /**
183
+ * Cache key generators for common use cases
184
+ */
185
+ export const CacheKeys = {
186
+ NODE_VERSION: 'node_version',
187
+ PYTHON_VERSION: 'python_version',
188
+ PYTHON3_VERSION: 'python3_version',
189
+ DOCKER_VERSION: 'docker_version',
190
+ GIT_REMOTE_URL: (dir) => `git_remote_${Buffer.from(dir).toString('base64')}`,
191
+ GIT_BRANCH: (dir) => `git_branch_${Buffer.from(dir).toString('base64')}`,
192
+ };
193
+ /**
194
+ * Cached command execution helper
195
+ * Runs a command and caches the result
196
+ */
197
+ export async function cachedCommand(cache, key, command, args = [], ttl = 300) {
198
+ // Try to get from cache first
199
+ const cached = await cache.get(key, ttl);
200
+ if (cached !== null) {
201
+ return cached;
202
+ }
203
+ try {
204
+ const { exec } = await import('child_process');
205
+ const { promisify } = await import('util');
206
+ const execAsync = promisify(exec);
207
+ const { stdout } = await execAsync(`${command} ${args.join(' ')}`, {
208
+ timeout: 5000, // 5 second timeout
209
+ encoding: 'utf-8',
210
+ });
211
+ const result = stdout.trim();
212
+ if (result) {
213
+ // Cache the successful result
214
+ await cache.set(key, result);
215
+ }
216
+ return result;
217
+ }
218
+ catch (error) {
219
+ console.debug('[DEBUG] Command execution failed:', command, error instanceof Error ? error.message : String(error));
220
+ return null;
221
+ }
222
+ }
223
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/core/cache.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile, writeFile, mkdir } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { Config } from './config.js';\n\n/**\n * Simple caching system with TTL support\n * Ported from bash implementation with Node.js optimizations\n */\n\n\n/**\n * Cache wrapper that handles TTL and file operations\n */\nexport class Cache {\n private config: Config;\n\n constructor(config: Config) {\n this.config = config;\n }\n\n /**\n * Ensure cache directory exists\n */\n private async ensureCacheDir(): Promise<void> {\n try {\n await mkdir(this.config.cacheDir, { recursive: true });\n } catch (error) {\n // Directory might already exist or we can't create it\n console.warn('[WARNING] Failed to create cache directory:', this.config.cacheDir);\n }\n }\n\n /**\n * Get cache file path for a given key\n */\n private getCachePath(key: string): string {\n return join(this.config.cacheDir, key);\n }\n\n /**\n * Get cache timestamp file path for a given key\n */\n private getTimestampPath(key: string): string {\n return join(this.config.cacheDir, `${key}.time`);\n }\n\n /**\n * Read cached data with TTL validation\n */\n async get<T = string>(key: string, ttl: number = this.config.cacheTTL): Promise<T | null> {\n const cachePath = this.getCachePath(key);\n const timestampPath = this.getTimestampPath(key);\n\n try {\n // Check if cache files exist\n if (!existsSync(cachePath) || !existsSync(timestampPath)) {\n return null;\n }\n\n // Read timestamp and check TTL\n const timestampContent = await readFile(timestampPath, 'utf-8');\n const timestamp = parseInt(timestampContent.trim(), 10);\n\n if (isNaN(timestamp)) {\n return null;\n }\n\n const currentTime = Math.floor(Date.now() / 1000);\n const age = currentTime - timestamp;\n\n // In development, reduce cache TTL to prevent stale data\n const effectiveTTL = process.env.NODE_ENV === 'development' ? Math.min(ttl, 5) : ttl;\n\n if (age >= effectiveTTL) {\n // Cache expired\n return null;\n }\n\n // Read cached data\n const dataContent = await readFile(cachePath, 'utf-8');\n\n // Try to parse as JSON, fallback to string\n try {\n return JSON.parse(dataContent) as T;\n } catch {\n return dataContent as T;\n }\n\n } catch (error) {\n // Any error reading cache should result in cache miss\n console.debug('[DEBUG] Cache read error for key:', key, error instanceof Error ? error.message : String(error));\n return null;\n }\n }\n\n /**\n * Write data to cache with timestamp\n */\n async set<T = string>(key: string, data: T): Promise<boolean> {\n const cachePath = this.getCachePath(key);\n const timestampPath = this.getTimestampPath(key);\n\n try {\n // Ensure cache directory exists\n await this.ensureCacheDir();\n\n // Prepare data for storage\n let dataContent: string;\n if (typeof data === 'string') {\n dataContent = data;\n } else {\n dataContent = JSON.stringify(data);\n }\n\n // Write data and timestamp\n const currentTime = Math.floor(Date.now() / 1000);\n\n await Promise.all([\n writeFile(cachePath, dataContent, 'utf-8'),\n writeFile(timestampPath, currentTime.toString(), 'utf-8'),\n ]);\n\n return true;\n\n } catch (error) {\n console.warn('[WARNING] Failed to write cache for key:', key, error instanceof Error ? error.message : String(error));\n return false;\n }\n }\n\n /**\n * Check if cache entry exists and is valid\n */\n async has(key: string, ttl: number = this.config.cacheTTL): Promise<boolean> {\n const value = await this.get(key, ttl);\n return value !== null;\n }\n\n /**\n * Delete cache entry\n */\n async delete(key: string): Promise<boolean> {\n const cachePath = this.getCachePath(key);\n const timestampPath = this.getTimestampPath(key);\n\n try {\n const { unlink } = await import('fs/promises');\n\n await Promise.allSettled([\n unlink(cachePath),\n unlink(timestampPath),\n ]);\n\n return true;\n } catch (error) {\n console.warn('[WARNING] Failed to delete cache for key:', key, error instanceof Error ? error.message : String(error));\n return false;\n }\n }\n\n /**\n * Clear all cache entries\n */\n async clear(): Promise<boolean> {\n try {\n const { readdir, unlink } = await import('fs/promises');\n const files = await readdir(this.config.cacheDir);\n\n await Promise.allSettled(\n files.map(file => unlink(join(this.config.cacheDir, file)))\n );\n\n return true;\n } catch (error) {\n console.warn('[WARNING] Failed to clear cache:', error instanceof Error ? error.message : String(error));\n return false;\n }\n }\n\n /**\n * Get cache statistics\n */\n async getStats(): Promise<{ total: number; size: number }> {\n try {\n const { readdir, stat } = await import('fs/promises');\n const files = await readdir(this.config.cacheDir);\n\n let totalSize = 0;\n let cacheFiles = 0;\n\n for (const file of files) {\n if (!file.endsWith('.time')) {\n cacheFiles++;\n const filePath = join(this.config.cacheDir, file);\n try {\n const stats = await stat(filePath);\n totalSize += stats.size;\n } catch {\n // Skip files that can't be stat'ed\n }\n }\n }\n\n return { total: cacheFiles, size: totalSize };\n } catch (error) {\n console.warn('[WARNING] Failed to get cache stats:', error instanceof Error ? error.message : String(error));\n return { total: 0, size: 0 };\n }\n }\n}\n\n/**\n * Cache key generators for common use cases\n */\nexport const CacheKeys = {\n NODE_VERSION: 'node_version',\n PYTHON_VERSION: 'python_version',\n PYTHON3_VERSION: 'python3_version',\n DOCKER_VERSION: 'docker_version',\n GIT_REMOTE_URL: (dir: string) => `git_remote_${Buffer.from(dir).toString('base64')}`,\n GIT_BRANCH: (dir: string) => `git_branch_${Buffer.from(dir).toString('base64')}`,\n} as const;\n\n/**\n * Cached command execution helper\n * Runs a command and caches the result\n */\nexport async function cachedCommand(\n cache: Cache,\n key: string,\n command: string,\n args: string[] = [],\n ttl: number = 300\n): Promise<string | null> {\n // Try to get from cache first\n const cached = await cache.get<string>(key, ttl);\n if (cached !== null) {\n return cached;\n }\n\n try {\n const { exec } = await import('child_process');\n const { promisify } = await import('util');\n const execAsync = promisify(exec);\n\n const { stdout } = await execAsync(`${command} ${args.join(' ')}`, {\n timeout: 5000, // 5 second timeout\n encoding: 'utf-8',\n });\n\n const result = stdout.trim();\n if (result) {\n // Cache the successful result\n await cache.set(key, result);\n }\n\n return result;\n\n } catch (error) {\n console.debug('[DEBUG] Command execution failed:', command, error instanceof Error ? error.message : String(error));\n return null;\n }\n}"]}
@@ -0,0 +1,190 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Configuration schema for claude-statusline
4
+ */
5
+ export declare const ConfigSchema: z.ZodObject<{
6
+ cacheTTL: z.ZodDefault<z.ZodNumber>;
7
+ cacheDir: z.ZodDefault<z.ZodString>;
8
+ maxLength: z.ZodDefault<z.ZodNumber>;
9
+ noEmoji: z.ZodDefault<z.ZodBoolean>;
10
+ noGitStatus: z.ZodDefault<z.ZodBoolean>;
11
+ noContextWindow: z.ZodDefault<z.ZodBoolean>;
12
+ envContext: z.ZodDefault<z.ZodBoolean>;
13
+ truncate: z.ZodDefault<z.ZodBoolean>;
14
+ softWrap: z.ZodDefault<z.ZodBoolean>;
15
+ noSoftWrap: z.ZodDefault<z.ZodBoolean>;
16
+ forceWidth: z.ZodOptional<z.ZodNumber>;
17
+ debugWidth: z.ZodDefault<z.ZodBoolean>;
18
+ rightMargin: z.ZodDefault<z.ZodNumber>;
19
+ symbols: z.ZodDefault<z.ZodObject<{
20
+ git: z.ZodDefault<z.ZodString>;
21
+ model: z.ZodDefault<z.ZodString>;
22
+ contextWindow: z.ZodDefault<z.ZodString>;
23
+ staged: z.ZodDefault<z.ZodString>;
24
+ conflict: z.ZodDefault<z.ZodString>;
25
+ stashed: z.ZodDefault<z.ZodString>;
26
+ ahead: z.ZodDefault<z.ZodString>;
27
+ behind: z.ZodDefault<z.ZodString>;
28
+ diverged: z.ZodDefault<z.ZodString>;
29
+ renamed: z.ZodDefault<z.ZodString>;
30
+ deleted: z.ZodDefault<z.ZodString>;
31
+ }, "strip", z.ZodTypeAny, {
32
+ git: string;
33
+ model: string;
34
+ contextWindow: string;
35
+ staged: string;
36
+ conflict: string;
37
+ stashed: string;
38
+ ahead: string;
39
+ behind: string;
40
+ diverged: string;
41
+ renamed: string;
42
+ deleted: string;
43
+ }, {
44
+ git?: string | undefined;
45
+ model?: string | undefined;
46
+ contextWindow?: string | undefined;
47
+ staged?: string | undefined;
48
+ conflict?: string | undefined;
49
+ stashed?: string | undefined;
50
+ ahead?: string | undefined;
51
+ behind?: string | undefined;
52
+ diverged?: string | undefined;
53
+ renamed?: string | undefined;
54
+ deleted?: string | undefined;
55
+ }>>;
56
+ asciiSymbols: z.ZodDefault<z.ZodObject<{
57
+ git: z.ZodDefault<z.ZodString>;
58
+ model: z.ZodDefault<z.ZodString>;
59
+ contextWindow: z.ZodDefault<z.ZodString>;
60
+ staged: z.ZodDefault<z.ZodString>;
61
+ conflict: z.ZodDefault<z.ZodString>;
62
+ stashed: z.ZodDefault<z.ZodString>;
63
+ ahead: z.ZodDefault<z.ZodString>;
64
+ behind: z.ZodDefault<z.ZodString>;
65
+ diverged: z.ZodDefault<z.ZodString>;
66
+ renamed: z.ZodDefault<z.ZodString>;
67
+ deleted: z.ZodDefault<z.ZodString>;
68
+ }, "strip", z.ZodTypeAny, {
69
+ git: string;
70
+ model: string;
71
+ contextWindow: string;
72
+ staged: string;
73
+ conflict: string;
74
+ stashed: string;
75
+ ahead: string;
76
+ behind: string;
77
+ diverged: string;
78
+ renamed: string;
79
+ deleted: string;
80
+ }, {
81
+ git?: string | undefined;
82
+ model?: string | undefined;
83
+ contextWindow?: string | undefined;
84
+ staged?: string | undefined;
85
+ conflict?: string | undefined;
86
+ stashed?: string | undefined;
87
+ ahead?: string | undefined;
88
+ behind?: string | undefined;
89
+ diverged?: string | undefined;
90
+ renamed?: string | undefined;
91
+ deleted?: string | undefined;
92
+ }>>;
93
+ }, "strip", z.ZodTypeAny, {
94
+ cacheTTL: number;
95
+ cacheDir: string;
96
+ maxLength: number;
97
+ noEmoji: boolean;
98
+ noGitStatus: boolean;
99
+ noContextWindow: boolean;
100
+ envContext: boolean;
101
+ truncate: boolean;
102
+ softWrap: boolean;
103
+ noSoftWrap: boolean;
104
+ debugWidth: boolean;
105
+ rightMargin: number;
106
+ symbols: {
107
+ git: string;
108
+ model: string;
109
+ contextWindow: string;
110
+ staged: string;
111
+ conflict: string;
112
+ stashed: string;
113
+ ahead: string;
114
+ behind: string;
115
+ diverged: string;
116
+ renamed: string;
117
+ deleted: string;
118
+ };
119
+ asciiSymbols: {
120
+ git: string;
121
+ model: string;
122
+ contextWindow: string;
123
+ staged: string;
124
+ conflict: string;
125
+ stashed: string;
126
+ ahead: string;
127
+ behind: string;
128
+ diverged: string;
129
+ renamed: string;
130
+ deleted: string;
131
+ };
132
+ forceWidth?: number | undefined;
133
+ }, {
134
+ cacheTTL?: number | undefined;
135
+ cacheDir?: string | undefined;
136
+ maxLength?: number | undefined;
137
+ noEmoji?: boolean | undefined;
138
+ noGitStatus?: boolean | undefined;
139
+ noContextWindow?: boolean | undefined;
140
+ envContext?: boolean | undefined;
141
+ truncate?: boolean | undefined;
142
+ softWrap?: boolean | undefined;
143
+ noSoftWrap?: boolean | undefined;
144
+ forceWidth?: number | undefined;
145
+ debugWidth?: boolean | undefined;
146
+ rightMargin?: number | undefined;
147
+ symbols?: {
148
+ git?: string | undefined;
149
+ model?: string | undefined;
150
+ contextWindow?: string | undefined;
151
+ staged?: string | undefined;
152
+ conflict?: string | undefined;
153
+ stashed?: string | undefined;
154
+ ahead?: string | undefined;
155
+ behind?: string | undefined;
156
+ diverged?: string | undefined;
157
+ renamed?: string | undefined;
158
+ deleted?: string | undefined;
159
+ } | undefined;
160
+ asciiSymbols?: {
161
+ git?: string | undefined;
162
+ model?: string | undefined;
163
+ contextWindow?: string | undefined;
164
+ staged?: string | undefined;
165
+ conflict?: string | undefined;
166
+ stashed?: string | undefined;
167
+ ahead?: string | undefined;
168
+ behind?: string | undefined;
169
+ diverged?: string | undefined;
170
+ renamed?: string | undefined;
171
+ deleted?: string | undefined;
172
+ } | undefined;
173
+ }>;
174
+ export type Config = z.infer<typeof ConfigSchema>;
175
+ /**
176
+ * Default configuration instance
177
+ */
178
+ export declare const defaultConfig: Config;
179
+ /**
180
+ * Load configuration from file and environment variables
181
+ */
182
+ export declare function loadConfig(cwd?: string): Config;
183
+ /**
184
+ * Get configuration file path for writing
185
+ */
186
+ export declare function getConfigFilePath(cwd?: string): string | null;
187
+ /**
188
+ * Generate a sample configuration file
189
+ */
190
+ export declare function generateSampleConfig(): string;
@@ -0,0 +1,192 @@
1
+ import { z } from 'zod';
2
+ import { readFileSync, existsSync } from 'fs';
3
+ import { homedir } from 'os';
4
+ import { join, dirname } from 'path';
5
+ import { parse as parseYaml } from 'yaml';
6
+ /**
7
+ * Configuration schema for claude-statusline
8
+ */
9
+ export const ConfigSchema = z.object({
10
+ // Core settings
11
+ cacheTTL: z.number().default(300), // 5 minutes
12
+ cacheDir: z.string().default('/tmp/.claude-statusline-cache'),
13
+ maxLength: z.number().default(1000), // Maximum input length
14
+ // Feature toggles
15
+ noEmoji: z.boolean().default(false), // Force ASCII mode
16
+ noGitStatus: z.boolean().default(false), // Disable git indicators
17
+ noContextWindow: z.boolean().default(false), // Disable context window usage
18
+ envContext: z.boolean().default(false), // Show environment versions
19
+ truncate: z.boolean().default(false), // Smart truncation
20
+ softWrap: z.boolean().default(false), // Soft wrapping (legacy)
21
+ noSoftWrap: z.boolean().default(false), // Disable soft-wrapping
22
+ // Width and display settings
23
+ forceWidth: z.number().optional(), // Manual width override
24
+ debugWidth: z.boolean().default(false), // Width debugging
25
+ rightMargin: z.number().default(15), // Right margin for Claude telemetry
26
+ // Symbol settings
27
+ symbols: z.object({
28
+ git: z.string().default(''),
29
+ model: z.string().default('󰚩'),
30
+ contextWindow: z.string().default('⚡︎'),
31
+ staged: z.string().default('+'),
32
+ conflict: z.string().default('×'),
33
+ stashed: z.string().default('⚑'),
34
+ ahead: z.string().default('⇡'),
35
+ behind: z.string().default('⇣'),
36
+ diverged: z.string().default('⇕'),
37
+ renamed: z.string().default('»'),
38
+ deleted: z.string().default('✘'),
39
+ }).default({}),
40
+ // ASCII fallback symbols
41
+ asciiSymbols: z.object({
42
+ git: z.string().default('@'),
43
+ model: z.string().default('*'),
44
+ contextWindow: z.string().default('#'),
45
+ staged: z.string().default('+'),
46
+ conflict: z.string().default('C'),
47
+ stashed: z.string().default('$'),
48
+ ahead: z.string().default('A'),
49
+ behind: z.string().default('B'),
50
+ diverged: z.string().default('D'),
51
+ renamed: z.string().default('>'),
52
+ deleted: z.string().default('X'),
53
+ }).default({}),
54
+ });
55
+ /**
56
+ * Default configuration instance
57
+ */
58
+ export const defaultConfig = ConfigSchema.parse({});
59
+ /**
60
+ * Configuration file names to search for (in order of preference)
61
+ */
62
+ const CONFIG_FILES = [
63
+ 'claude-statusline.json',
64
+ 'claude-statusline.yaml',
65
+ ];
66
+ /**
67
+ * Load configuration from file and environment variables
68
+ */
69
+ export function loadConfig(cwd = process.cwd()) {
70
+ let config = { ...defaultConfig };
71
+ // 1. Load from configuration file
72
+ config = { ...config, ...loadConfigFile(cwd) };
73
+ // 2. Override with environment variables
74
+ config = { ...config, ...loadEnvConfig() };
75
+ // Validate final configuration
76
+ return ConfigSchema.parse(config);
77
+ }
78
+ /**
79
+ * Load configuration from file in the current directory or home directory
80
+ */
81
+ function loadConfigFile(cwd) {
82
+ // Search in current directory first, then parent directories, then ~/.claude/
83
+ const searchPaths = [cwd, dirname(cwd), join(homedir(), '.claude')];
84
+ for (const searchPath of searchPaths) {
85
+ for (const filename of CONFIG_FILES) {
86
+ const configPath = join(searchPath, filename);
87
+ if (existsSync(configPath)) {
88
+ try {
89
+ const content = readFileSync(configPath, 'utf-8');
90
+ if (filename.endsWith('.json')) {
91
+ return JSON.parse(content);
92
+ }
93
+ else if (filename.endsWith('.yaml')) {
94
+ return parseYaml(content);
95
+ }
96
+ }
97
+ catch (error) {
98
+ console.warn(`[WARNING] Failed to parse config file ${configPath}:`, error instanceof Error ? error.message : String(error));
99
+ }
100
+ }
101
+ }
102
+ }
103
+ return {};
104
+ }
105
+ /**
106
+ * Load configuration from environment variables
107
+ * Maps v1.0 environment variables to new configuration format
108
+ */
109
+ function loadEnvConfig() {
110
+ const env = {};
111
+ // Feature toggles
112
+ if (process.env.CLAUDE_CODE_STATUSLINE_NO_EMOJI === '1') {
113
+ env.noEmoji = true;
114
+ }
115
+ if (process.env.CLAUDE_CODE_STATUSLINE_NO_GITSTATUS === '1') {
116
+ env.noGitStatus = true;
117
+ }
118
+ if (process.env.CLAUDE_CODE_STATUSLINE_NO_CONTEXT_WINDOW === '1') {
119
+ env.noContextWindow = true;
120
+ }
121
+ if (process.env.CLAUDE_CODE_STATUSLINE_ENV_CONTEXT === '1') {
122
+ env.envContext = true;
123
+ }
124
+ if (process.env.CLAUDE_CODE_STATUSLINE_TRUNCATE === '1') {
125
+ env.truncate = true;
126
+ }
127
+ if (process.env.CLAUDE_CODE_STATUSLINE_SOFT_WRAP === '1') {
128
+ env.softWrap = true;
129
+ }
130
+ if (process.env.CLAUDE_CODE_STATUSLINE_NO_SOFT_WRAP === '1') {
131
+ env.noSoftWrap = true;
132
+ }
133
+ // Width settings
134
+ if (process.env.CLAUDE_CODE_STATUSLINE_FORCE_WIDTH) {
135
+ const width = parseInt(process.env.CLAUDE_CODE_STATUSLINE_FORCE_WIDTH, 10);
136
+ if (!isNaN(width) && width > 0) {
137
+ env.forceWidth = width;
138
+ }
139
+ }
140
+ if (process.env.CLAUDE_CODE_STATUSLINE_DEBUG_WIDTH === '1') {
141
+ env.debugWidth = true;
142
+ }
143
+ // Cache directory override
144
+ if (process.env.CLAUDE_CODE_STATUSLINE_CACHE_DIR) {
145
+ env.cacheDir = process.env.CLAUDE_CODE_STATUSLINE_CACHE_DIR;
146
+ }
147
+ return env;
148
+ }
149
+ /**
150
+ * Get configuration file path for writing
151
+ */
152
+ export function getConfigFilePath(cwd = process.cwd()) {
153
+ // Prefer claude-statusline.json in the current directory
154
+ const configPath = join(cwd, 'claude-statusline.json');
155
+ return configPath;
156
+ }
157
+ /**
158
+ * Generate a sample configuration file
159
+ */
160
+ export function generateSampleConfig() {
161
+ return JSON.stringify({
162
+ $schema: 'https://raw.githubusercontent.com/shrwnsan/claude-statusline/main/config-schema.json',
163
+ // Core settings
164
+ cacheTTL: 300, // 5 minutes
165
+ maxLength: 1000,
166
+ // Feature toggles
167
+ noEmoji: false, // Set to true to force ASCII mode
168
+ noGitStatus: false, // Set to true to disable git indicators
169
+ noContextWindow: false, // Set to true to disable context window usage
170
+ envContext: true, // Set to true to show Node.js, Python versions
171
+ truncate: true, // Set to true to enable smart truncation
172
+ softWrap: false, // Set to true to enable soft wrapping
173
+ // Display settings
174
+ rightMargin: 15, // Right margin for Claude telemetry compatibility
175
+ debugWidth: false, // Set to true for width debugging output
176
+ // Custom symbols (optional - will use defaults if not specified)
177
+ symbols: {
178
+ git: '',
179
+ model: '󰚩',
180
+ contextWindow: '⚡︎',
181
+ staged: '+',
182
+ conflict: '×',
183
+ stashed: '⚑',
184
+ ahead: '⇡',
185
+ behind: '⇣',
186
+ diverged: '⇕',
187
+ renamed: '»',
188
+ deleted: '✘',
189
+ },
190
+ }, null, 2);
191
+ }
192
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod';\nimport { readFileSync, existsSync } from 'fs';\nimport { homedir } from 'os';\nimport { join, dirname } from 'path';\nimport { parse as parseYaml } from 'yaml';\n\n/**\n * Configuration schema for claude-statusline\n */\nexport const ConfigSchema = z.object({\n // Core settings\n cacheTTL: z.number().default(300), // 5 minutes\n cacheDir: z.string().default('/tmp/.claude-statusline-cache'),\n maxLength: z.number().default(1000), // Maximum input length\n\n // Feature toggles\n noEmoji: z.boolean().default(false), // Force ASCII mode\n noGitStatus: z.boolean().default(false), // Disable git indicators\n noContextWindow: z.boolean().default(false), // Disable context window usage\n envContext: z.boolean().default(false), // Show environment versions\n truncate: z.boolean().default(false), // Smart truncation\n softWrap: z.boolean().default(false), // Soft wrapping (legacy)\n noSoftWrap: z.boolean().default(false), // Disable soft-wrapping\n\n // Width and display settings\n forceWidth: z.number().optional(), // Manual width override\n debugWidth: z.boolean().default(false), // Width debugging\n rightMargin: z.number().default(15), // Right margin for Claude telemetry\n\n // Symbol settings\n symbols: z.object({\n git: z.string().default(''),\n model: z.string().default('󰚩'),\n contextWindow: z.string().default('⚡︎'),\n staged: z.string().default('+'),\n conflict: z.string().default('×'),\n stashed: z.string().default('⚑'),\n ahead: z.string().default('⇡'),\n behind: z.string().default('⇣'),\n diverged: z.string().default('⇕'),\n renamed: z.string().default('»'),\n deleted: z.string().default('✘'),\n }).default({}),\n\n // ASCII fallback symbols\n asciiSymbols: z.object({\n git: z.string().default('@'),\n model: z.string().default('*'),\n contextWindow: z.string().default('#'),\n staged: z.string().default('+'),\n conflict: z.string().default('C'),\n stashed: z.string().default('$'),\n ahead: z.string().default('A'),\n behind: z.string().default('B'),\n diverged: z.string().default('D'),\n renamed: z.string().default('>'),\n deleted: z.string().default('X'),\n }).default({}),\n});\n\nexport type Config = z.infer<typeof ConfigSchema>;\n\n/**\n * Default configuration instance\n */\nexport const defaultConfig: Config = ConfigSchema.parse({});\n\n/**\n * Configuration file names to search for (in order of preference)\n */\nconst CONFIG_FILES = [\n 'claude-statusline.json',\n 'claude-statusline.yaml',\n];\n\n/**\n * Load configuration from file and environment variables\n */\nexport function loadConfig(cwd: string = process.cwd()): Config {\n let config = { ...defaultConfig };\n\n // 1. Load from configuration file\n config = { ...config, ...loadConfigFile(cwd) };\n\n // 2. Override with environment variables\n config = { ...config, ...loadEnvConfig() };\n\n // Validate final configuration\n return ConfigSchema.parse(config);\n}\n\n/**\n * Load configuration from file in the current directory or home directory\n */\nfunction loadConfigFile(cwd: string): Partial<Config> {\n // Search in current directory first, then parent directories, then ~/.claude/\n const searchPaths = [cwd, dirname(cwd), join(homedir(), '.claude')];\n\n for (const searchPath of searchPaths) {\n for (const filename of CONFIG_FILES) {\n const configPath = join(searchPath, filename);\n\n if (existsSync(configPath)) {\n try {\n const content = readFileSync(configPath, 'utf-8');\n\n if (filename.endsWith('.json')) {\n return JSON.parse(content);\n } else if (filename.endsWith('.yaml')) {\n return parseYaml(content);\n }\n } catch (error) {\n console.warn(`[WARNING] Failed to parse config file ${configPath}:`, error instanceof Error ? error.message : String(error));\n }\n }\n }\n }\n\n return {};\n}\n\n/**\n * Load configuration from environment variables\n * Maps v1.0 environment variables to new configuration format\n */\nfunction loadEnvConfig(): Partial<Config> {\n const env: Partial<Config> = {};\n\n // Feature toggles\n if (process.env.CLAUDE_CODE_STATUSLINE_NO_EMOJI === '1') {\n env.noEmoji = true;\n }\n\n if (process.env.CLAUDE_CODE_STATUSLINE_NO_GITSTATUS === '1') {\n env.noGitStatus = true;\n }\n\n if (process.env.CLAUDE_CODE_STATUSLINE_NO_CONTEXT_WINDOW === '1') {\n env.noContextWindow = true;\n }\n\n if (process.env.CLAUDE_CODE_STATUSLINE_ENV_CONTEXT === '1') {\n env.envContext = true;\n }\n\n if (process.env.CLAUDE_CODE_STATUSLINE_TRUNCATE === '1') {\n env.truncate = true;\n }\n\n if (process.env.CLAUDE_CODE_STATUSLINE_SOFT_WRAP === '1') {\n env.softWrap = true;\n }\n\n if (process.env.CLAUDE_CODE_STATUSLINE_NO_SOFT_WRAP === '1') {\n env.noSoftWrap = true;\n }\n\n // Width settings\n if (process.env.CLAUDE_CODE_STATUSLINE_FORCE_WIDTH) {\n const width = parseInt(process.env.CLAUDE_CODE_STATUSLINE_FORCE_WIDTH, 10);\n if (!isNaN(width) && width > 0) {\n env.forceWidth = width;\n }\n }\n\n if (process.env.CLAUDE_CODE_STATUSLINE_DEBUG_WIDTH === '1') {\n env.debugWidth = true;\n }\n\n // Cache directory override\n if (process.env.CLAUDE_CODE_STATUSLINE_CACHE_DIR) {\n env.cacheDir = process.env.CLAUDE_CODE_STATUSLINE_CACHE_DIR;\n }\n\n return env;\n}\n\n/**\n * Get configuration file path for writing\n */\nexport function getConfigFilePath(cwd: string = process.cwd()): string | null {\n // Prefer claude-statusline.json in the current directory\n const configPath = join(cwd, 'claude-statusline.json');\n return configPath;\n}\n\n/**\n * Generate a sample configuration file\n */\nexport function generateSampleConfig(): string {\n return JSON.stringify({\n $schema: 'https://raw.githubusercontent.com/shrwnsan/claude-statusline/main/config-schema.json',\n // Core settings\n cacheTTL: 300, // 5 minutes\n maxLength: 1000,\n\n // Feature toggles\n noEmoji: false, // Set to true to force ASCII mode\n noGitStatus: false, // Set to true to disable git indicators\n noContextWindow: false, // Set to true to disable context window usage\n envContext: true, // Set to true to show Node.js, Python versions\n truncate: true, // Set to true to enable smart truncation\n softWrap: false, // Set to true to enable soft wrapping\n\n // Display settings\n rightMargin: 15, // Right margin for Claude telemetry compatibility\n debugWidth: false, // Set to true for width debugging output\n\n // Custom symbols (optional - will use defaults if not specified)\n symbols: {\n git: '',\n model: '󰚩',\n contextWindow: '⚡︎',\n staged: '+',\n conflict: '×',\n stashed: '⚑',\n ahead: '⇡',\n behind: '⇣',\n diverged: '⇕',\n renamed: '»',\n deleted: '✘',\n },\n }, null, 2);\n}"]}