@sylphx/flow 1.7.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 (131) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/assets/agents/coder.md +72 -119
  3. package/assets/agents/orchestrator.md +26 -90
  4. package/assets/agents/reviewer.md +76 -47
  5. package/assets/agents/writer.md +82 -63
  6. package/assets/output-styles/silent.md +141 -8
  7. package/assets/rules/code-standards.md +9 -33
  8. package/assets/rules/core.md +67 -59
  9. package/package.json +2 -12
  10. package/src/commands/flow/execute.ts +470 -0
  11. package/src/commands/flow/index.ts +11 -0
  12. package/src/commands/flow/prompt.ts +35 -0
  13. package/src/commands/flow/setup.ts +312 -0
  14. package/src/commands/flow/targets.ts +18 -0
  15. package/src/commands/flow/types.ts +47 -0
  16. package/src/commands/flow-command.ts +18 -967
  17. package/src/commands/flow-orchestrator.ts +14 -5
  18. package/src/commands/hook-command.ts +1 -1
  19. package/src/commands/init-core.ts +12 -3
  20. package/src/commands/run-command.ts +1 -1
  21. package/src/config/rules.ts +1 -1
  22. package/src/core/error-handling.ts +1 -1
  23. package/src/core/loop-controller.ts +1 -1
  24. package/src/core/state-detector.ts +1 -1
  25. package/src/core/target-manager.ts +1 -1
  26. package/src/index.ts +1 -1
  27. package/src/shared/files/index.ts +1 -1
  28. package/src/shared/processing/index.ts +1 -1
  29. package/src/targets/claude-code.ts +3 -3
  30. package/src/targets/opencode.ts +3 -3
  31. package/src/utils/agent-enhancer.ts +2 -2
  32. package/src/utils/{mcp-config.ts → config/mcp-config.ts} +4 -4
  33. package/src/utils/{paths.ts → config/paths.ts} +1 -1
  34. package/src/utils/{settings.ts → config/settings.ts} +1 -1
  35. package/src/utils/{target-config.ts → config/target-config.ts} +5 -5
  36. package/src/utils/{target-utils.ts → config/target-utils.ts} +3 -3
  37. package/src/utils/display/banner.ts +25 -0
  38. package/src/utils/display/status.ts +55 -0
  39. package/src/utils/{file-operations.ts → files/file-operations.ts} +2 -2
  40. package/src/utils/files/jsonc.ts +36 -0
  41. package/src/utils/{sync-utils.ts → files/sync-utils.ts} +3 -3
  42. package/src/utils/index.ts +42 -61
  43. package/src/utils/version.ts +47 -0
  44. package/src/components/benchmark-monitor.tsx +0 -331
  45. package/src/components/reindex-progress.tsx +0 -261
  46. package/src/composables/functional/index.ts +0 -14
  47. package/src/composables/functional/useEnvironment.ts +0 -171
  48. package/src/composables/functional/useFileSystem.ts +0 -139
  49. package/src/composables/index.ts +0 -4
  50. package/src/composables/useEnv.ts +0 -13
  51. package/src/composables/useRuntimeConfig.ts +0 -27
  52. package/src/core/ai-sdk.ts +0 -603
  53. package/src/core/app-factory.ts +0 -381
  54. package/src/core/builtin-agents.ts +0 -9
  55. package/src/core/command-system.ts +0 -550
  56. package/src/core/config-system.ts +0 -550
  57. package/src/core/connection-pool.ts +0 -390
  58. package/src/core/di-container.ts +0 -155
  59. package/src/core/headless-display.ts +0 -96
  60. package/src/core/interfaces/index.ts +0 -22
  61. package/src/core/interfaces/repository.interface.ts +0 -91
  62. package/src/core/interfaces/service.interface.ts +0 -133
  63. package/src/core/interfaces.ts +0 -96
  64. package/src/core/result.ts +0 -351
  65. package/src/core/service-config.ts +0 -252
  66. package/src/core/session-service.ts +0 -121
  67. package/src/core/storage-factory.ts +0 -115
  68. package/src/core/stream-handler.ts +0 -288
  69. package/src/core/type-utils.ts +0 -427
  70. package/src/core/unified-storage.ts +0 -456
  71. package/src/core/validation/limit.ts +0 -46
  72. package/src/core/validation/query.ts +0 -20
  73. package/src/db/auto-migrate.ts +0 -322
  74. package/src/db/base-database-client.ts +0 -144
  75. package/src/db/cache-db.ts +0 -218
  76. package/src/db/cache-schema.ts +0 -75
  77. package/src/db/database.ts +0 -70
  78. package/src/db/index.ts +0 -252
  79. package/src/db/memory-db.ts +0 -153
  80. package/src/db/memory-schema.ts +0 -29
  81. package/src/db/schema.ts +0 -289
  82. package/src/db/session-repository.ts +0 -733
  83. package/src/domains/index.ts +0 -6
  84. package/src/domains/utilities/index.ts +0 -6
  85. package/src/domains/utilities/time/index.ts +0 -5
  86. package/src/domains/utilities/time/tools.ts +0 -291
  87. package/src/services/agent-service.ts +0 -273
  88. package/src/services/evaluation-service.ts +0 -271
  89. package/src/services/functional/evaluation-logic.ts +0 -296
  90. package/src/services/functional/file-processor.ts +0 -273
  91. package/src/services/functional/index.ts +0 -12
  92. package/src/services/memory.service.ts +0 -476
  93. package/src/types/api/batch.ts +0 -108
  94. package/src/types/api/errors.ts +0 -118
  95. package/src/types/api/index.ts +0 -55
  96. package/src/types/api/requests.ts +0 -76
  97. package/src/types/api/responses.ts +0 -180
  98. package/src/types/api/websockets.ts +0 -85
  99. package/src/types/benchmark.ts +0 -49
  100. package/src/types/database.types.ts +0 -510
  101. package/src/types/memory-types.ts +0 -63
  102. package/src/utils/advanced-tokenizer.ts +0 -191
  103. package/src/utils/ai-model-fetcher.ts +0 -19
  104. package/src/utils/async-file-operations.ts +0 -516
  105. package/src/utils/audio-player.ts +0 -345
  106. package/src/utils/codebase-helpers.ts +0 -211
  107. package/src/utils/console-ui.ts +0 -79
  108. package/src/utils/database-errors.ts +0 -140
  109. package/src/utils/debug-logger.ts +0 -49
  110. package/src/utils/file-scanner.ts +0 -259
  111. package/src/utils/help.ts +0 -20
  112. package/src/utils/immutable-cache.ts +0 -106
  113. package/src/utils/jsonc.ts +0 -158
  114. package/src/utils/memory-tui.ts +0 -414
  115. package/src/utils/models-dev.ts +0 -91
  116. package/src/utils/parallel-operations.ts +0 -487
  117. package/src/utils/process-manager.ts +0 -155
  118. package/src/utils/prompts.ts +0 -120
  119. package/src/utils/search-tool-builder.ts +0 -214
  120. package/src/utils/session-manager.ts +0 -168
  121. package/src/utils/session-title.ts +0 -87
  122. package/src/utils/simplified-errors.ts +0 -410
  123. package/src/utils/template-engine.ts +0 -94
  124. package/src/utils/test-audio.ts +0 -71
  125. package/src/utils/todo-context.ts +0 -46
  126. package/src/utils/token-counter.ts +0 -288
  127. /package/src/utils/{cli-output.ts → display/cli-output.ts} +0 -0
  128. /package/src/utils/{logger.ts → display/logger.ts} +0 -0
  129. /package/src/utils/{notifications.ts → display/notifications.ts} +0 -0
  130. /package/src/utils/{secret-utils.ts → security/secret-utils.ts} +0 -0
  131. /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
- };