@sylphx/flow 1.8.0 → 1.8.1

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 (126) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/assets/output-styles/silent.md +141 -8
  3. package/assets/rules/core.md +19 -2
  4. package/package.json +2 -12
  5. package/src/commands/flow/execute.ts +470 -0
  6. package/src/commands/flow/index.ts +11 -0
  7. package/src/commands/flow/prompt.ts +35 -0
  8. package/src/commands/flow/setup.ts +312 -0
  9. package/src/commands/flow/targets.ts +18 -0
  10. package/src/commands/flow/types.ts +47 -0
  11. package/src/commands/flow-command.ts +18 -967
  12. package/src/commands/flow-orchestrator.ts +14 -5
  13. package/src/commands/hook-command.ts +1 -1
  14. package/src/commands/init-core.ts +12 -3
  15. package/src/commands/run-command.ts +1 -1
  16. package/src/config/rules.ts +1 -1
  17. package/src/core/error-handling.ts +1 -1
  18. package/src/core/loop-controller.ts +1 -1
  19. package/src/core/state-detector.ts +1 -1
  20. package/src/core/target-manager.ts +1 -1
  21. package/src/index.ts +1 -1
  22. package/src/shared/files/index.ts +1 -1
  23. package/src/shared/processing/index.ts +1 -1
  24. package/src/targets/claude-code.ts +3 -3
  25. package/src/targets/opencode.ts +3 -3
  26. package/src/utils/agent-enhancer.ts +2 -2
  27. package/src/utils/{mcp-config.ts → config/mcp-config.ts} +4 -4
  28. package/src/utils/{paths.ts → config/paths.ts} +1 -1
  29. package/src/utils/{settings.ts → config/settings.ts} +1 -1
  30. package/src/utils/{target-config.ts → config/target-config.ts} +5 -5
  31. package/src/utils/{target-utils.ts → config/target-utils.ts} +3 -3
  32. package/src/utils/display/banner.ts +25 -0
  33. package/src/utils/display/status.ts +55 -0
  34. package/src/utils/{file-operations.ts → files/file-operations.ts} +2 -2
  35. package/src/utils/files/jsonc.ts +36 -0
  36. package/src/utils/{sync-utils.ts → files/sync-utils.ts} +3 -3
  37. package/src/utils/index.ts +42 -61
  38. package/src/utils/version.ts +47 -0
  39. package/src/components/benchmark-monitor.tsx +0 -331
  40. package/src/components/reindex-progress.tsx +0 -261
  41. package/src/composables/functional/index.ts +0 -14
  42. package/src/composables/functional/useEnvironment.ts +0 -171
  43. package/src/composables/functional/useFileSystem.ts +0 -139
  44. package/src/composables/index.ts +0 -4
  45. package/src/composables/useEnv.ts +0 -13
  46. package/src/composables/useRuntimeConfig.ts +0 -27
  47. package/src/core/ai-sdk.ts +0 -603
  48. package/src/core/app-factory.ts +0 -381
  49. package/src/core/builtin-agents.ts +0 -9
  50. package/src/core/command-system.ts +0 -550
  51. package/src/core/config-system.ts +0 -550
  52. package/src/core/connection-pool.ts +0 -390
  53. package/src/core/di-container.ts +0 -155
  54. package/src/core/headless-display.ts +0 -96
  55. package/src/core/interfaces/index.ts +0 -22
  56. package/src/core/interfaces/repository.interface.ts +0 -91
  57. package/src/core/interfaces/service.interface.ts +0 -133
  58. package/src/core/interfaces.ts +0 -96
  59. package/src/core/result.ts +0 -351
  60. package/src/core/service-config.ts +0 -252
  61. package/src/core/session-service.ts +0 -121
  62. package/src/core/storage-factory.ts +0 -115
  63. package/src/core/stream-handler.ts +0 -288
  64. package/src/core/type-utils.ts +0 -427
  65. package/src/core/unified-storage.ts +0 -456
  66. package/src/core/validation/limit.ts +0 -46
  67. package/src/core/validation/query.ts +0 -20
  68. package/src/db/auto-migrate.ts +0 -322
  69. package/src/db/base-database-client.ts +0 -144
  70. package/src/db/cache-db.ts +0 -218
  71. package/src/db/cache-schema.ts +0 -75
  72. package/src/db/database.ts +0 -70
  73. package/src/db/index.ts +0 -252
  74. package/src/db/memory-db.ts +0 -153
  75. package/src/db/memory-schema.ts +0 -29
  76. package/src/db/schema.ts +0 -289
  77. package/src/db/session-repository.ts +0 -733
  78. package/src/domains/index.ts +0 -6
  79. package/src/domains/utilities/index.ts +0 -6
  80. package/src/domains/utilities/time/index.ts +0 -5
  81. package/src/domains/utilities/time/tools.ts +0 -291
  82. package/src/services/agent-service.ts +0 -273
  83. package/src/services/evaluation-service.ts +0 -271
  84. package/src/services/functional/evaluation-logic.ts +0 -296
  85. package/src/services/functional/file-processor.ts +0 -273
  86. package/src/services/functional/index.ts +0 -12
  87. package/src/services/memory.service.ts +0 -476
  88. package/src/types/api/batch.ts +0 -108
  89. package/src/types/api/errors.ts +0 -118
  90. package/src/types/api/index.ts +0 -55
  91. package/src/types/api/requests.ts +0 -76
  92. package/src/types/api/responses.ts +0 -180
  93. package/src/types/api/websockets.ts +0 -85
  94. package/src/types/benchmark.ts +0 -49
  95. package/src/types/database.types.ts +0 -510
  96. package/src/types/memory-types.ts +0 -63
  97. package/src/utils/advanced-tokenizer.ts +0 -191
  98. package/src/utils/ai-model-fetcher.ts +0 -19
  99. package/src/utils/async-file-operations.ts +0 -516
  100. package/src/utils/audio-player.ts +0 -345
  101. package/src/utils/codebase-helpers.ts +0 -211
  102. package/src/utils/console-ui.ts +0 -79
  103. package/src/utils/database-errors.ts +0 -140
  104. package/src/utils/debug-logger.ts +0 -49
  105. package/src/utils/file-scanner.ts +0 -259
  106. package/src/utils/help.ts +0 -20
  107. package/src/utils/immutable-cache.ts +0 -106
  108. package/src/utils/jsonc.ts +0 -158
  109. package/src/utils/memory-tui.ts +0 -414
  110. package/src/utils/models-dev.ts +0 -91
  111. package/src/utils/parallel-operations.ts +0 -487
  112. package/src/utils/process-manager.ts +0 -155
  113. package/src/utils/prompts.ts +0 -120
  114. package/src/utils/search-tool-builder.ts +0 -214
  115. package/src/utils/session-manager.ts +0 -168
  116. package/src/utils/session-title.ts +0 -87
  117. package/src/utils/simplified-errors.ts +0 -410
  118. package/src/utils/template-engine.ts +0 -94
  119. package/src/utils/test-audio.ts +0 -71
  120. package/src/utils/todo-context.ts +0 -46
  121. package/src/utils/token-counter.ts +0 -288
  122. /package/src/utils/{cli-output.ts → display/cli-output.ts} +0 -0
  123. /package/src/utils/{logger.ts → display/logger.ts} +0 -0
  124. /package/src/utils/{notifications.ts → display/notifications.ts} +0 -0
  125. /package/src/utils/{secret-utils.ts → security/secret-utils.ts} +0 -0
  126. /package/src/utils/{security.ts → security/security.ts} +0 -0
@@ -1,345 +0,0 @@
1
- /**
2
- * Cross-Platform Audio Player
3
- * Detects and uses available audio players across different platforms
4
- *
5
- * Supported players (in priority order):
6
- * - macOS: afplay (built-in)
7
- * - Linux: mpg123, mpg321, play (sox), aplay, mplayer, cvlc
8
- * - Windows: powershell (built-in), cmdmp3
9
- * - Universal: mplayer, omxplayer (Raspberry Pi)
10
- */
11
-
12
- import { spawn } from 'child_process';
13
- import { existsSync } from 'fs';
14
- import { join } from 'path';
15
-
16
- /**
17
- * Audio player configuration
18
- */
19
- interface AudioPlayer {
20
- name: string;
21
- command: string;
22
- args: (filePath: string) => string[];
23
- platforms: NodeJS.Platform[];
24
- checkAvailability?: () => Promise<boolean>;
25
- }
26
-
27
- /**
28
- * Available audio players in priority order
29
- */
30
- const AUDIO_PLAYERS: AudioPlayer[] = [
31
- // macOS built-in
32
- {
33
- name: 'afplay',
34
- command: 'afplay',
35
- args: (file) => [file],
36
- platforms: ['darwin'],
37
- },
38
-
39
- // Linux players (in priority order)
40
- {
41
- name: 'mpg123',
42
- command: 'mpg123',
43
- args: (file) => ['-q', file], // quiet mode
44
- platforms: ['linux', 'freebsd', 'openbsd'],
45
- },
46
- {
47
- name: 'mpg321',
48
- command: 'mpg321',
49
- args: (file) => ['-q', file], // quiet mode
50
- platforms: ['linux', 'freebsd', 'openbsd'],
51
- },
52
- {
53
- name: 'play',
54
- command: 'play',
55
- args: (file) => ['-q', file], // sox play command
56
- platforms: ['linux', 'freebsd', 'openbsd', 'darwin'],
57
- },
58
- {
59
- name: 'aplay',
60
- command: 'aplay',
61
- args: (file) => ['-q', file], // ALSA player
62
- platforms: ['linux'],
63
- },
64
- {
65
- name: 'mplayer',
66
- command: 'mplayer',
67
- args: (file) => ['-really-quiet', file],
68
- platforms: ['linux', 'freebsd', 'openbsd', 'darwin', 'win32'],
69
- },
70
- {
71
- name: 'cvlc',
72
- command: 'cvlc',
73
- args: (file) => ['--play-and-exit', '--quiet', file], // VLC command-line
74
- platforms: ['linux', 'freebsd', 'openbsd', 'darwin', 'win32'],
75
- },
76
- {
77
- name: 'omxplayer',
78
- command: 'omxplayer',
79
- args: (file) => ['-o', 'local', file], // Raspberry Pi
80
- platforms: ['linux'],
81
- },
82
-
83
- // Windows players
84
- {
85
- name: 'powershell',
86
- command: 'powershell',
87
- args: (file) => [
88
- '-NoProfile',
89
- '-NonInteractive',
90
- '-Command',
91
- `(New-Object Media.SoundPlayer "${file}").PlaySync()`
92
- ],
93
- platforms: ['win32'],
94
- // PowerShell Media.SoundPlayer only supports WAV files
95
- checkAvailability: async () => {
96
- // Check if we're on Windows and file is WAV
97
- return process.platform === 'win32';
98
- }
99
- },
100
- {
101
- name: 'cmdmp3',
102
- command: 'cmdmp3',
103
- args: (file) => [file],
104
- platforms: ['win32'],
105
- },
106
- ];
107
-
108
- /**
109
- * Cached available player to avoid repeated checks
110
- */
111
- let cachedPlayer: AudioPlayer | null = null;
112
- let cacheChecked = false;
113
-
114
- /**
115
- * Check if a command is available in PATH
116
- */
117
- async function isCommandAvailable(command: string): Promise<boolean> {
118
- return new Promise((resolve) => {
119
- // Try to execute the command with --version or --help
120
- const proc = spawn(command, ['--version'], {
121
- stdio: 'ignore',
122
- shell: true
123
- });
124
-
125
- proc.on('error', () => resolve(false));
126
- proc.on('exit', (code) => {
127
- // Some commands return non-zero for --version, so just check if they exist
128
- resolve(true);
129
- });
130
-
131
- // Timeout after 1 second
132
- setTimeout(() => {
133
- proc.kill();
134
- resolve(false);
135
- }, 1000);
136
- });
137
- }
138
-
139
- /**
140
- * Detect the first available audio player for current platform
141
- */
142
- export async function detectAudioPlayer(): Promise<AudioPlayer | null> {
143
- if (cacheChecked && cachedPlayer) {
144
- return cachedPlayer;
145
- }
146
-
147
- const currentPlatform = process.platform;
148
-
149
- // Filter players for current platform
150
- const compatiblePlayers = AUDIO_PLAYERS.filter(
151
- (player) => player.platforms.includes(currentPlatform)
152
- );
153
-
154
- // Check each player in priority order
155
- for (const player of compatiblePlayers) {
156
- // Custom availability check if provided
157
- if (player.checkAvailability) {
158
- const isAvailable = await player.checkAvailability();
159
- if (!isAvailable) continue;
160
- }
161
-
162
- // Check if command is available
163
- const isAvailable = await isCommandAvailable(player.command);
164
- if (isAvailable) {
165
- cachedPlayer = player;
166
- cacheChecked = true;
167
- return player;
168
- }
169
- }
170
-
171
- cacheChecked = true;
172
- return null;
173
- }
174
-
175
- /**
176
- * Play audio file using the best available player
177
- * @param filePath Absolute path to audio file
178
- * @param options Playback options
179
- * @returns Promise that resolves when playback completes or rejects on error
180
- */
181
- export async function playSound(
182
- filePath: string,
183
- options?: {
184
- volume?: number; // 0-100 (not supported by all players)
185
- background?: boolean; // Play in background (default: true)
186
- timeout?: number; // Max playback duration in ms (default: 5000)
187
- }
188
- ): Promise<void> {
189
- const {
190
- background = true,
191
- timeout = 5000
192
- } = options || {};
193
-
194
- // Check if file exists
195
- if (!existsSync(filePath)) {
196
- throw new Error(`Audio file not found: ${filePath}`);
197
- }
198
-
199
- // Detect available player
200
- const player = await detectAudioPlayer();
201
- if (!player) {
202
- throw new Error('No audio player available on this system');
203
- }
204
-
205
- return new Promise((resolve, reject) => {
206
- const args = player.args(filePath);
207
- const proc = spawn(player.command, args, {
208
- stdio: 'ignore',
209
- detached: background,
210
- });
211
-
212
- // If background mode, unref and resolve immediately
213
- if (background) {
214
- proc.unref();
215
- resolve();
216
- return;
217
- }
218
-
219
- // Otherwise wait for completion
220
- let timeoutId: NodeJS.Timeout | null = null;
221
-
222
- proc.on('error', (error) => {
223
- if (timeoutId) clearTimeout(timeoutId);
224
- reject(new Error(`Audio player error: ${error.message}`));
225
- });
226
-
227
- proc.on('exit', (code) => {
228
- if (timeoutId) clearTimeout(timeoutId);
229
- if (code === 0) {
230
- resolve();
231
- } else {
232
- reject(new Error(`Audio player exited with code ${code}`));
233
- }
234
- });
235
-
236
- // Timeout protection
237
- if (timeout > 0) {
238
- timeoutId = setTimeout(() => {
239
- proc.kill();
240
- reject(new Error(`Audio playback timeout after ${timeout}ms`));
241
- }, timeout);
242
- }
243
- });
244
- }
245
-
246
- /**
247
- * Get information about the detected audio player
248
- */
249
- export async function getAudioPlayerInfo(): Promise<{
250
- available: boolean;
251
- player: string | null;
252
- platform: string;
253
- }> {
254
- const player = await detectAudioPlayer();
255
-
256
- return {
257
- available: player !== null,
258
- player: player?.name || null,
259
- platform: process.platform
260
- };
261
- }
262
-
263
- /**
264
- * Built-in system sounds for different platforms
265
- */
266
- export const SYSTEM_SOUNDS = {
267
- // macOS system sounds
268
- darwin: {
269
- glass: '/System/Library/Sounds/Glass.aiff',
270
- hero: '/System/Library/Sounds/Hero.aiff',
271
- pop: '/System/Library/Sounds/Pop.aiff',
272
- ping: '/System/Library/Sounds/Ping.aiff',
273
- purr: '/System/Library/Sounds/Purr.aiff',
274
- submarine: '/System/Library/Sounds/Submarine.aiff',
275
- blow: '/System/Library/Sounds/Blow.aiff',
276
- bottle: '/System/Library/Sounds/Bottle.aiff',
277
- frog: '/System/Library/Sounds/Frog.aiff',
278
- funk: '/System/Library/Sounds/Funk.aiff',
279
- morse: '/System/Library/Sounds/Morse.aiff',
280
- },
281
- // Linux typical locations (may vary)
282
- linux: {
283
- complete: '/usr/share/sounds/freedesktop/stereo/complete.oga',
284
- message: '/usr/share/sounds/freedesktop/stereo/message.oga',
285
- bell: '/usr/share/sounds/freedesktop/stereo/bell.oga',
286
- dialog: '/usr/share/sounds/freedesktop/stereo/dialog-information.oga',
287
- },
288
- // Windows - would need .wav files
289
- win32: {
290
- // Windows Media directory sounds
291
- notify: 'C:\\Windows\\Media\\Windows Notify.wav',
292
- ding: 'C:\\Windows\\Media\\Windows Ding.wav',
293
- chord: 'C:\\Windows\\Media\\chord.wav',
294
- }
295
- } as const;
296
-
297
- /**
298
- * Get default system sound for current platform
299
- */
300
- export function getDefaultSystemSound(): string | null {
301
- const platform = process.platform;
302
-
303
- if (platform === 'darwin') {
304
- return SYSTEM_SOUNDS.darwin.glass;
305
- } else if (platform === 'linux') {
306
- // Check which sound exists
307
- const sounds = Object.values(SYSTEM_SOUNDS.linux);
308
- for (const sound of sounds) {
309
- if (existsSync(sound)) {
310
- return sound;
311
- }
312
- }
313
- } else if (platform === 'win32') {
314
- // Check which sound exists
315
- const sounds = Object.values(SYSTEM_SOUNDS.win32);
316
- for (const sound of sounds) {
317
- if (existsSync(sound)) {
318
- return sound;
319
- }
320
- }
321
- }
322
-
323
- return null;
324
- }
325
-
326
- /**
327
- * Play system notification sound
328
- */
329
- export async function playNotificationSound(): Promise<void> {
330
- const soundPath = getDefaultSystemSound();
331
-
332
- if (!soundPath) {
333
- // No system sound available, just return silently
334
- return;
335
- }
336
-
337
- try {
338
- await playSound(soundPath, { background: true, timeout: 3000 });
339
- } catch (error) {
340
- // Fail silently - don't crash on sound playback errors
341
- if (process.env.DEBUG) {
342
- console.error('[Audio] Failed to play notification sound:', error);
343
- }
344
- }
345
- }
@@ -1,211 +0,0 @@
1
- /**
2
- * Codebase indexing helper functions
3
- * Utility functions for file scanning and language detection
4
- */
5
-
6
- import fs from 'node:fs';
7
- import path from 'node:path';
8
- import ignore, { type Ignore } from 'ignore';
9
-
10
- /**
11
- * Detect programming language from file extension
12
- */
13
- export function detectLanguage(filePath: string): string | undefined {
14
- const ext = path.extname(filePath).toLowerCase();
15
- const languageMap: Record<string, string> = {
16
- '.ts': 'TypeScript',
17
- '.tsx': 'TSX',
18
- '.js': 'JavaScript',
19
- '.jsx': 'JSX',
20
- '.py': 'Python',
21
- '.java': 'Java',
22
- '.go': 'Go',
23
- '.rs': 'Rust',
24
- '.c': 'C',
25
- '.cpp': 'C++',
26
- '.cs': 'C#',
27
- '.rb': 'Ruby',
28
- '.php': 'PHP',
29
- '.swift': 'Swift',
30
- '.kt': 'Kotlin',
31
- '.md': 'Markdown',
32
- '.json': 'JSON',
33
- '.yaml': 'YAML',
34
- '.yml': 'YAML',
35
- '.toml': 'TOML',
36
- '.sql': 'SQL',
37
- '.sh': 'Shell',
38
- '.bash': 'Bash',
39
- };
40
- return languageMap[ext];
41
- }
42
-
43
- /**
44
- * Check if file is text-based (not binary)
45
- */
46
- export function isTextFile(filePath: string): boolean {
47
- const textExtensions = new Set([
48
- '.ts',
49
- '.tsx',
50
- '.js',
51
- '.jsx',
52
- '.py',
53
- '.java',
54
- '.go',
55
- '.rs',
56
- '.c',
57
- '.cpp',
58
- '.h',
59
- '.hpp',
60
- '.cs',
61
- '.rb',
62
- '.php',
63
- '.swift',
64
- '.kt',
65
- '.md',
66
- '.txt',
67
- '.json',
68
- '.yaml',
69
- '.yml',
70
- '.toml',
71
- '.xml',
72
- '.sql',
73
- '.sh',
74
- '.bash',
75
- '.zsh',
76
- '.fish',
77
- '.dockerfile',
78
- '.gitignore',
79
- '.env',
80
- '.env.example',
81
- '.env.local',
82
- '.env.development',
83
- '.env.production',
84
- ]);
85
-
86
- const ext = path.extname(filePath).toLowerCase();
87
- return textExtensions.has(ext) || !ext; // Files without extension might be text
88
- }
89
-
90
- /**
91
- * Load .gitignore file and create ignore filter
92
- */
93
- export function loadGitignore(codebaseRoot: string): Ignore {
94
- const ig = ignore();
95
-
96
- // Add default ignore patterns
97
- ig.add([
98
- 'node_modules',
99
- '.git',
100
- '.svn',
101
- '.hg',
102
- '.DS_Store',
103
- '.idea',
104
- '.vscode',
105
- '*.suo',
106
- '*.ntvs*',
107
- '*.njsproj',
108
- '*.sln',
109
- '*.swp',
110
- '.sylphx-flow',
111
- '.cache',
112
- 'dist',
113
- 'build',
114
- 'coverage',
115
- '.nyc_output',
116
- ]);
117
-
118
- const gitignorePath = path.join(codebaseRoot, '.gitignore');
119
-
120
- if (fs.existsSync(gitignorePath)) {
121
- try {
122
- const content = fs.readFileSync(gitignorePath, 'utf8');
123
- ig.add(content);
124
- } catch (error) {
125
- console.warn(`[WARN] Failed to read .gitignore: ${error}`);
126
- }
127
- }
128
-
129
- return ig;
130
- }
131
-
132
- /**
133
- * Scan directory recursively for files
134
- */
135
- export interface ScanOptions {
136
- ignoreFilter?: Ignore;
137
- codebaseRoot?: string;
138
- }
139
-
140
- export interface ScanResult {
141
- path: string;
142
- absolutePath: string;
143
- content: string;
144
- size: number;
145
- mtime: number;
146
- }
147
-
148
- /**
149
- * Scan files in directory with .gitignore support
150
- */
151
- export function scanFiles(dir: string, options: ScanOptions = {}): ScanResult[] {
152
- const results: ScanResult[] = [];
153
- const ignoreFilter = options.ignoreFilter;
154
- const codebaseRoot = options.codebaseRoot || dir;
155
-
156
- function scan(currentDir: string) {
157
- const entries = fs.readdirSync(currentDir, { withFileTypes: true });
158
-
159
- for (const entry of entries) {
160
- const fullPath = path.join(currentDir, entry.name);
161
- const relativePath = path.relative(codebaseRoot, fullPath);
162
-
163
- // Skip ignored files
164
- if (ignoreFilter?.ignores(relativePath)) {
165
- continue;
166
- }
167
-
168
- if (entry.isDirectory()) {
169
- scan(fullPath);
170
- } else if (entry.isFile()) {
171
- try {
172
- const stats = fs.statSync(fullPath);
173
- const _ext = path.extname(fullPath);
174
-
175
- // Only process text files
176
- if (!isTextFile(fullPath)) {
177
- continue;
178
- }
179
-
180
- const content = fs.readFileSync(fullPath, 'utf8');
181
-
182
- results.push({
183
- path: relativePath,
184
- absolutePath: fullPath,
185
- content,
186
- size: stats.size,
187
- mtime: stats.mtimeMs,
188
- });
189
- } catch (error) {
190
- console.warn(`[WARN] Failed to read file: ${relativePath}`, error);
191
- }
192
- }
193
- }
194
- }
195
-
196
- scan(dir);
197
- return results;
198
- }
199
-
200
- /**
201
- * Calculate simple hash for file content (for change detection)
202
- */
203
- export function simpleHash(content: string): string {
204
- let hash = 0;
205
- for (let i = 0; i < content.length; i++) {
206
- const char = content.charCodeAt(i);
207
- hash = (hash << 5) - hash + char;
208
- hash &= hash; // Convert to 32-bit integer
209
- }
210
- return hash.toString(36);
211
- }
@@ -1,79 +0,0 @@
1
- /**
2
- * Modern console UI utilities
3
- * Progressive output with beautiful formatting
4
- */
5
-
6
- import chalk from 'chalk';
7
-
8
- export const ui = {
9
- // Headers
10
- header: (text: string) => {
11
- console.log('');
12
- console.log(chalk.cyan.bold(`▸ ${text}`));
13
- },
14
-
15
- subheader: (text: string) => {
16
- console.log(chalk.gray(` ${text}`));
17
- },
18
-
19
- // Status messages
20
- success: (text: string) => {
21
- console.log(chalk.green(`✓ ${text}`));
22
- },
23
-
24
- error: (text: string) => {
25
- console.log(chalk.red(`✗ ${text}`));
26
- },
27
-
28
- warning: (text: string) => {
29
- console.log(chalk.yellow(`⚠ ${text}`));
30
- },
31
-
32
- info: (text: string) => {
33
- console.log(chalk.cyan(`ℹ ${text}`));
34
- },
35
-
36
- // Progress
37
- step: (text: string) => {
38
- console.log(chalk.gray(` • ${text}`));
39
- },
40
-
41
- loading: (text: string) => {
42
- console.log(chalk.cyan(`⏳ ${text}`));
43
- },
44
-
45
- // Fields
46
- field: (label: string, value: string, secret = false) => {
47
- const displayValue = secret ? '•'.repeat(Math.min(8, value.length)) : value;
48
- console.log(` ${chalk.gray(label)}: ${chalk.white(displayValue)}`);
49
- },
50
-
51
- // Dividers
52
- divider: () => {
53
- console.log(chalk.gray(' ─'.repeat(40)));
54
- },
55
-
56
- spacer: () => {
57
- console.log('');
58
- },
59
-
60
- // Lists
61
- list: (items: string[]) => {
62
- items.forEach((item) => {
63
- console.log(chalk.gray(` • ${item}`));
64
- });
65
- },
66
-
67
- // Input prompt (for simple inputs)
68
- prompt: (label: string, required = false) => {
69
- const indicator = required ? chalk.red('*') : '';
70
- return `${chalk.cyan('❯')} ${label}${indicator}: `;
71
- },
72
-
73
- // Section
74
- section: (title: string, content: () => void) => {
75
- console.log('');
76
- console.log(chalk.cyan.bold(`▸ ${title}`));
77
- content();
78
- },
79
- };