@sylphx/flow 1.0.1 → 1.0.3
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/CHANGELOG.md +12 -0
- package/package.json +10 -9
- package/src/commands/codebase-command.ts +168 -0
- package/src/commands/flow-command.ts +1137 -0
- package/src/commands/flow-orchestrator.ts +296 -0
- package/src/commands/hook-command.ts +444 -0
- package/src/commands/init-command.ts +92 -0
- package/src/commands/init-core.ts +322 -0
- package/src/commands/knowledge-command.ts +161 -0
- package/src/commands/run-command.ts +120 -0
- package/src/components/benchmark-monitor.tsx +331 -0
- package/src/components/reindex-progress.tsx +261 -0
- package/src/composables/functional/index.ts +14 -0
- package/src/composables/functional/useEnvironment.ts +171 -0
- package/src/composables/functional/useFileSystem.ts +139 -0
- package/src/composables/index.ts +5 -0
- package/src/composables/useEnv.ts +13 -0
- package/src/composables/useRuntimeConfig.ts +27 -0
- package/src/composables/useTargetConfig.ts +45 -0
- package/src/config/ai-config.ts +376 -0
- package/src/config/constants.ts +35 -0
- package/src/config/index.ts +27 -0
- package/src/config/rules.ts +43 -0
- package/src/config/servers.ts +371 -0
- package/src/config/targets.ts +126 -0
- package/src/core/agent-loader.ts +141 -0
- package/src/core/agent-manager.ts +174 -0
- package/src/core/ai-sdk.ts +603 -0
- package/src/core/app-factory.ts +381 -0
- package/src/core/builtin-agents.ts +9 -0
- package/src/core/command-system.ts +550 -0
- package/src/core/config-system.ts +550 -0
- package/src/core/connection-pool.ts +390 -0
- package/src/core/di-container.ts +155 -0
- package/src/core/error-handling.ts +519 -0
- package/src/core/formatting/bytes.test.ts +115 -0
- package/src/core/formatting/bytes.ts +64 -0
- package/src/core/functional/async.ts +313 -0
- package/src/core/functional/either.ts +109 -0
- package/src/core/functional/error-handler.ts +135 -0
- package/src/core/functional/error-types.ts +311 -0
- package/src/core/functional/index.ts +19 -0
- package/src/core/functional/option.ts +142 -0
- package/src/core/functional/pipe.ts +189 -0
- package/src/core/functional/result.ts +204 -0
- package/src/core/functional/validation.ts +138 -0
- package/src/core/headless-display.ts +96 -0
- package/src/core/index.ts +6 -0
- package/src/core/installers/file-installer.ts +303 -0
- package/src/core/installers/mcp-installer.ts +213 -0
- package/src/core/interfaces/index.ts +22 -0
- package/src/core/interfaces/repository.interface.ts +91 -0
- package/src/core/interfaces/service.interface.ts +133 -0
- package/src/core/interfaces.ts +129 -0
- package/src/core/loop-controller.ts +200 -0
- package/src/core/result.ts +351 -0
- package/src/core/rule-loader.ts +147 -0
- package/src/core/rule-manager.ts +240 -0
- package/src/core/service-config.ts +252 -0
- package/src/core/session-service.ts +121 -0
- package/src/core/state-detector.ts +389 -0
- package/src/core/storage-factory.ts +115 -0
- package/src/core/stream-handler.ts +288 -0
- package/src/core/target-manager.ts +161 -0
- package/src/core/type-utils.ts +427 -0
- package/src/core/unified-storage.ts +456 -0
- package/src/core/upgrade-manager.ts +300 -0
- package/src/core/validation/limit.test.ts +155 -0
- package/src/core/validation/limit.ts +46 -0
- package/src/core/validation/query.test.ts +44 -0
- package/src/core/validation/query.ts +20 -0
- package/src/db/auto-migrate.ts +322 -0
- package/src/db/base-database-client.ts +144 -0
- package/src/db/cache-db.ts +218 -0
- package/src/db/cache-schema.ts +75 -0
- package/src/db/database.ts +70 -0
- package/src/db/index.ts +252 -0
- package/src/db/memory-db.ts +153 -0
- package/src/db/memory-schema.ts +29 -0
- package/src/db/schema.ts +289 -0
- package/src/db/session-repository.ts +733 -0
- package/src/domains/codebase/index.ts +5 -0
- package/src/domains/codebase/tools.ts +139 -0
- package/src/domains/index.ts +8 -0
- package/src/domains/knowledge/index.ts +10 -0
- package/src/domains/knowledge/resources.ts +537 -0
- package/src/domains/knowledge/tools.ts +174 -0
- package/src/domains/utilities/index.ts +6 -0
- package/src/domains/utilities/time/index.ts +5 -0
- package/src/domains/utilities/time/tools.ts +291 -0
- package/src/index.ts +211 -0
- package/src/services/agent-service.ts +273 -0
- package/src/services/claude-config-service.ts +252 -0
- package/src/services/config-service.ts +258 -0
- package/src/services/evaluation-service.ts +271 -0
- package/src/services/functional/evaluation-logic.ts +296 -0
- package/src/services/functional/file-processor.ts +273 -0
- package/src/services/functional/index.ts +12 -0
- package/src/services/index.ts +13 -0
- package/src/services/mcp-service.ts +432 -0
- package/src/services/memory.service.ts +476 -0
- package/src/services/search/base-indexer.ts +156 -0
- package/src/services/search/codebase-indexer-types.ts +38 -0
- package/src/services/search/codebase-indexer.ts +647 -0
- package/src/services/search/embeddings-provider.ts +455 -0
- package/src/services/search/embeddings.ts +316 -0
- package/src/services/search/functional-indexer.ts +323 -0
- package/src/services/search/index.ts +27 -0
- package/src/services/search/indexer.ts +380 -0
- package/src/services/search/knowledge-indexer.ts +422 -0
- package/src/services/search/semantic-search.ts +244 -0
- package/src/services/search/tfidf.ts +559 -0
- package/src/services/search/unified-search-service.ts +888 -0
- package/src/services/smart-config-service.ts +385 -0
- package/src/services/storage/cache-storage.ts +487 -0
- package/src/services/storage/drizzle-storage.ts +581 -0
- package/src/services/storage/index.ts +15 -0
- package/src/services/storage/lancedb-vector-storage.ts +494 -0
- package/src/services/storage/memory-storage.ts +268 -0
- package/src/services/storage/separated-storage.ts +467 -0
- package/src/services/storage/vector-storage.ts +13 -0
- package/src/shared/agents/index.ts +63 -0
- package/src/shared/files/index.ts +99 -0
- package/src/shared/index.ts +32 -0
- package/src/shared/logging/index.ts +24 -0
- package/src/shared/processing/index.ts +153 -0
- package/src/shared/types/index.ts +25 -0
- package/src/targets/claude-code.ts +574 -0
- package/src/targets/functional/claude-code-logic.ts +185 -0
- package/src/targets/functional/index.ts +6 -0
- package/src/targets/opencode.ts +529 -0
- package/src/types/agent.types.ts +32 -0
- package/src/types/api/batch.ts +108 -0
- package/src/types/api/errors.ts +118 -0
- package/src/types/api/index.ts +55 -0
- package/src/types/api/requests.ts +76 -0
- package/src/types/api/responses.ts +180 -0
- package/src/types/api/websockets.ts +85 -0
- package/src/types/api.types.ts +9 -0
- package/src/types/benchmark.ts +49 -0
- package/src/types/cli.types.ts +87 -0
- package/src/types/common.types.ts +35 -0
- package/src/types/database.types.ts +510 -0
- package/src/types/mcp-config.types.ts +448 -0
- package/src/types/mcp.types.ts +69 -0
- package/src/types/memory-types.ts +63 -0
- package/src/types/provider.types.ts +28 -0
- package/src/types/rule.types.ts +24 -0
- package/src/types/session.types.ts +214 -0
- package/src/types/target-config.types.ts +295 -0
- package/src/types/target.types.ts +140 -0
- package/src/types/todo.types.ts +25 -0
- package/src/types.ts +40 -0
- package/src/utils/advanced-tokenizer.ts +191 -0
- package/src/utils/agent-enhancer.ts +114 -0
- package/src/utils/ai-model-fetcher.ts +19 -0
- package/src/utils/async-file-operations.ts +516 -0
- package/src/utils/audio-player.ts +345 -0
- package/src/utils/cli-output.ts +266 -0
- package/src/utils/codebase-helpers.ts +211 -0
- package/src/utils/console-ui.ts +79 -0
- package/src/utils/database-errors.ts +140 -0
- package/src/utils/debug-logger.ts +49 -0
- package/src/utils/error-handler.ts +53 -0
- package/src/utils/file-operations.ts +310 -0
- package/src/utils/file-scanner.ts +259 -0
- package/src/utils/functional/array.ts +355 -0
- package/src/utils/functional/index.ts +15 -0
- package/src/utils/functional/object.ts +279 -0
- package/src/utils/functional/string.ts +281 -0
- package/src/utils/functional.ts +543 -0
- package/src/utils/help.ts +20 -0
- package/src/utils/immutable-cache.ts +106 -0
- package/src/utils/index.ts +78 -0
- package/src/utils/jsonc.ts +158 -0
- package/src/utils/logger.ts +396 -0
- package/src/utils/mcp-config.ts +249 -0
- package/src/utils/memory-tui.ts +414 -0
- package/src/utils/models-dev.ts +91 -0
- package/src/utils/notifications.ts +169 -0
- package/src/utils/object-utils.ts +51 -0
- package/src/utils/parallel-operations.ts +487 -0
- package/src/utils/paths.ts +143 -0
- package/src/utils/process-manager.ts +155 -0
- package/src/utils/prompts.ts +120 -0
- package/src/utils/search-tool-builder.ts +214 -0
- package/src/utils/secret-utils.ts +179 -0
- package/src/utils/security.ts +537 -0
- package/src/utils/session-manager.ts +168 -0
- package/src/utils/session-title.ts +87 -0
- package/src/utils/settings.ts +182 -0
- package/src/utils/simplified-errors.ts +410 -0
- package/src/utils/sync-utils.ts +159 -0
- package/src/utils/target-config.ts +570 -0
- package/src/utils/target-utils.ts +394 -0
- package/src/utils/template-engine.ts +94 -0
- package/src/utils/test-audio.ts +71 -0
- package/src/utils/todo-context.ts +46 -0
- package/src/utils/token-counter.ts +288 -0
- package/dist/index.d.ts +0 -10
- package/dist/index.js +0 -59554
- package/dist/lancedb.linux-x64-gnu-b7f0jgsz.node +0 -0
- package/dist/lancedb.linux-x64-musl-tgcv22rx.node +0 -0
- package/dist/shared/chunk-25dwp0dp.js +0 -89
- package/dist/shared/chunk-3pjb6063.js +0 -208
- package/dist/shared/chunk-4d6ydpw7.js +0 -2854
- package/dist/shared/chunk-4wjcadjk.js +0 -225
- package/dist/shared/chunk-5j4w74t6.js +0 -30
- package/dist/shared/chunk-5j8m3dh3.js +0 -58
- package/dist/shared/chunk-5thh3qem.js +0 -91
- package/dist/shared/chunk-6g9xy73m.js +0 -252
- package/dist/shared/chunk-7eq34c42.js +0 -23
- package/dist/shared/chunk-c2gwgx3r.js +0 -115
- package/dist/shared/chunk-cjd3mk4c.js +0 -1320
- package/dist/shared/chunk-g5cv6703.js +0 -368
- package/dist/shared/chunk-hpkhykhq.js +0 -574
- package/dist/shared/chunk-m2322pdk.js +0 -122
- package/dist/shared/chunk-nd5fdvaq.js +0 -26
- package/dist/shared/chunk-pgd3m6zf.js +0 -108
- package/dist/shared/chunk-qk8n91hw.js +0 -494
- package/dist/shared/chunk-rkkn8szp.js +0 -16855
- package/dist/shared/chunk-t16rfxh0.js +0 -61
- package/dist/shared/chunk-t4fbfa5v.js +0 -19
- package/dist/shared/chunk-t77h86w6.js +0 -276
- package/dist/shared/chunk-v0ez4aef.js +0 -71
- package/dist/shared/chunk-v29j2r3s.js +0 -32051
- package/dist/shared/chunk-vfbc6ew5.js +0 -765
- package/dist/shared/chunk-vmeqwm1c.js +0 -204
- package/dist/shared/chunk-x66eh37x.js +0 -137
|
@@ -0,0 +1,345 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Output Utilities
|
|
3
|
+
* Provides structured output for CLI commands with proper logging separation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { logger } from './logger.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* CLI output levels
|
|
10
|
+
*/
|
|
11
|
+
export type CLIOutputLevel = 'info' | 'success' | 'warning' | 'error';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* CLI output interface
|
|
15
|
+
*/
|
|
16
|
+
export interface ICLIOutput {
|
|
17
|
+
/**
|
|
18
|
+
* Print user-facing message
|
|
19
|
+
*/
|
|
20
|
+
print(message: string, level?: CLIOutputLevel): void;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Print success message
|
|
24
|
+
*/
|
|
25
|
+
success(message: string): void;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Print warning message
|
|
29
|
+
*/
|
|
30
|
+
warning(message: string): void;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Print error message
|
|
34
|
+
*/
|
|
35
|
+
error(message: string): void;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Print info message
|
|
39
|
+
*/
|
|
40
|
+
info(message: string): void;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Print formatted data
|
|
44
|
+
*/
|
|
45
|
+
table(data: Record<string, unknown>[]): void;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Print formatted list
|
|
49
|
+
*/
|
|
50
|
+
list(items: string[], options?: { numbered?: boolean; bullet?: string }): void;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* CLI output implementation
|
|
55
|
+
*/
|
|
56
|
+
export class CLIOutput implements ICLIOutput {
|
|
57
|
+
private colors = {
|
|
58
|
+
reset: '\x1b[0m',
|
|
59
|
+
bright: '\x1b[1m',
|
|
60
|
+
dim: '\x1b[2m',
|
|
61
|
+
red: '\x1b[31m',
|
|
62
|
+
green: '\x1b[32m',
|
|
63
|
+
yellow: '\x1b[33m',
|
|
64
|
+
blue: '\x1b[34m',
|
|
65
|
+
magenta: '\x1b[35m',
|
|
66
|
+
cyan: '\x1b[36m',
|
|
67
|
+
white: '\x1b[37m',
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
private icons = {
|
|
71
|
+
info: 'ℹ️',
|
|
72
|
+
success: '✅',
|
|
73
|
+
warning: '⚠️',
|
|
74
|
+
error: '❌',
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
print(message: string, level: CLIOutputLevel = 'info'): void {
|
|
78
|
+
// Log internally for debugging
|
|
79
|
+
logger.debug('CLI output', { message, level });
|
|
80
|
+
|
|
81
|
+
// Output to user
|
|
82
|
+
switch (level) {
|
|
83
|
+
case 'success':
|
|
84
|
+
this.success(message);
|
|
85
|
+
break;
|
|
86
|
+
case 'warning':
|
|
87
|
+
this.warning(message);
|
|
88
|
+
break;
|
|
89
|
+
case 'error':
|
|
90
|
+
this.error(message);
|
|
91
|
+
break;
|
|
92
|
+
default:
|
|
93
|
+
this.info(message);
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
success(message: string): void {
|
|
99
|
+
console.log(`${this.icons.success} ${this.colors.green}${message}${this.colors.reset}`);
|
|
100
|
+
logger.info('CLI success output', { message });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
warning(message: string): void {
|
|
104
|
+
console.log(`${this.icons.warning} ${this.colors.yellow}${message}${this.colors.reset}`);
|
|
105
|
+
logger.warn('CLI warning output', { message });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
error(message: string): void {
|
|
109
|
+
console.error(`${this.icons.error} ${this.colors.red}${message}${this.colors.reset}`);
|
|
110
|
+
logger.error('CLI error output', { message });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
info(message: string): void {
|
|
114
|
+
console.log(`${this.icons.info} ${message}`);
|
|
115
|
+
logger.info('CLI info output', { message });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
table(data: Record<string, unknown>[]): void {
|
|
119
|
+
if (data.length === 0) {
|
|
120
|
+
this.info('No data to display');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Simple table formatting
|
|
125
|
+
const headers = Object.keys(data[0]);
|
|
126
|
+
const columnWidths = headers.map((header) =>
|
|
127
|
+
Math.max(header.length, ...data.map((row) => String(row[header] || '').length))
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
// Print header
|
|
131
|
+
const headerRow = headers.map((header, i) => header.padEnd(columnWidths[i])).join(' | ');
|
|
132
|
+
console.log(this.colors.bright + headerRow + this.colors.reset);
|
|
133
|
+
console.log('-'.repeat(headerRow.length));
|
|
134
|
+
|
|
135
|
+
// Print rows
|
|
136
|
+
data.forEach((row) => {
|
|
137
|
+
const rowStr = headers
|
|
138
|
+
.map((header, i) => String(row[header] || '').padEnd(columnWidths[i]))
|
|
139
|
+
.join(' | ');
|
|
140
|
+
console.log(rowStr);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
logger.debug('CLI table output', {
|
|
144
|
+
headers,
|
|
145
|
+
rowCount: data.length,
|
|
146
|
+
columnWidths,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
list(items: string[], options: { numbered?: boolean; bullet?: string } = {}): void {
|
|
151
|
+
const { numbered = false, bullet = '•' } = options;
|
|
152
|
+
|
|
153
|
+
if (items.length === 0) {
|
|
154
|
+
this.info('No items to display');
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
items.forEach((item, index) => {
|
|
159
|
+
const prefix = numbered ? `${index + 1}.` : bullet;
|
|
160
|
+
console.log(`${prefix} ${item}`);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
logger.debug('CLI list output', {
|
|
164
|
+
itemCount: items.length,
|
|
165
|
+
numbered,
|
|
166
|
+
bullet,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Print formatted memory entry
|
|
172
|
+
*/
|
|
173
|
+
memoryEntry(
|
|
174
|
+
entry: {
|
|
175
|
+
namespace: string;
|
|
176
|
+
key: string;
|
|
177
|
+
value: unknown;
|
|
178
|
+
updated_at: string;
|
|
179
|
+
},
|
|
180
|
+
index?: number
|
|
181
|
+
): void {
|
|
182
|
+
const prefix = index !== undefined ? `${index + 1}.` : '•';
|
|
183
|
+
const safeValue = entry.value || '';
|
|
184
|
+
const value =
|
|
185
|
+
typeof safeValue === 'string'
|
|
186
|
+
? safeValue.substring(0, 50) + (safeValue.length > 50 ? '...' : '')
|
|
187
|
+
: `${JSON.stringify(safeValue).substring(0, 50)}...`;
|
|
188
|
+
|
|
189
|
+
console.log(`${prefix} ${entry.namespace}:${entry.key}`);
|
|
190
|
+
console.log(` Value: ${value}`);
|
|
191
|
+
console.log(` Updated: ${entry.updated_at}`);
|
|
192
|
+
console.log('');
|
|
193
|
+
|
|
194
|
+
logger.debug('CLI memory entry output', {
|
|
195
|
+
namespace: entry.namespace,
|
|
196
|
+
key: entry.key,
|
|
197
|
+
valueLength: String(entry.value || '').length,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Print search results summary
|
|
203
|
+
*/
|
|
204
|
+
searchSummary(query: string, results: number, namespace?: string): void {
|
|
205
|
+
console.log(`${this.colors.cyan}🔍 Search results for pattern: ${query}${this.colors.reset}`);
|
|
206
|
+
|
|
207
|
+
if (namespace) {
|
|
208
|
+
console.log(`${this.colors.dim}Namespace: ${namespace}${this.colors.reset}`);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
console.log(`${this.colors.bright}Found: ${results} results${this.colors.reset}\n`);
|
|
212
|
+
|
|
213
|
+
logger.info('CLI search summary', { query, results, namespace });
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Print list summary
|
|
218
|
+
*/
|
|
219
|
+
listSummary(namespace: string, count: number, total?: number): void {
|
|
220
|
+
if (namespace && namespace !== 'all') {
|
|
221
|
+
console.log(
|
|
222
|
+
`${this.colors.cyan}📋 Memory entries in namespace: ${namespace}${this.colors.reset}`
|
|
223
|
+
);
|
|
224
|
+
console.log(`${this.colors.bright}Total: ${count} entries${this.colors.reset}\n`);
|
|
225
|
+
} else if (total) {
|
|
226
|
+
console.log(
|
|
227
|
+
`${this.colors.cyan}📋 All memory entries (showing first ${count})${this.colors.reset}`
|
|
228
|
+
);
|
|
229
|
+
console.log(`${this.colors.bright}Total: ${total} entries${this.colors.reset}\n`);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
logger.info('CLI list summary', { namespace, count, total });
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Print empty state message
|
|
237
|
+
*/
|
|
238
|
+
emptyState(type: 'entries' | 'results' | 'data', context?: string): void {
|
|
239
|
+
const messages = {
|
|
240
|
+
entries: 'No entries found',
|
|
241
|
+
results: 'No matching entries found',
|
|
242
|
+
data: 'No data to display',
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
let message = messages[type];
|
|
246
|
+
if (context) {
|
|
247
|
+
message += ` in ${context}`;
|
|
248
|
+
}
|
|
249
|
+
message += '.';
|
|
250
|
+
|
|
251
|
+
this.info(message);
|
|
252
|
+
logger.debug('CLI empty state', { type, context, message });
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Global CLI output instance
|
|
257
|
+
export const cli = new CLIOutput();
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Convenience functions
|
|
261
|
+
*/
|
|
262
|
+
export const print = (message: string, level?: CLIOutputLevel) => cli.print(message, level);
|
|
263
|
+
export const success = (message: string) => cli.success(message);
|
|
264
|
+
export const warning = (message: string) => cli.warning(message);
|
|
265
|
+
export const error = (message: string) => cli.error(message);
|
|
266
|
+
export const info = (message: string) => cli.info(message);
|