waengine 2.0.0 → 2.2.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waengine",
3
- "version": "2.0.0",
3
+ "version": "2.2.5",
4
4
  "description": "🚀 WAEngine - The most powerful WhatsApp Bot Library with 860+ Working Features, Complete Baileys Integration & Production-Ready Stability",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/client.js CHANGED
@@ -262,9 +262,35 @@ export class WhatsAppClient {
262
262
  // ===== CONNECTION METHODS =====
263
263
 
264
264
  async connect() {
265
+ // ===== SESSION MENU - AUTOMATISCH FÜR JEDEN USER! =====
266
+ const { showSessionMenuIfNeeded } = await import('./console-logger.js');
267
+ const activeSessions = await showSessionMenuIfNeeded();
268
+
269
+ // Wenn Session Menu aktiv war, beende hier
270
+ // (User hat entweder Exit gewählt oder Sessions über Menu gestartet)
271
+ if (activeSessions !== null) {
272
+ console.log('✅ Session Menu wurde verwendet - connect() übersprungen');
273
+ return this;
274
+ }
275
+ // ===== ENDE SESSION MENU =====
276
+
277
+ // WICHTIG: Nach Session Menu IMMER neuen Socket erstellen
278
+ // (Session Menu hat eigenen Socket für Auth erstellt und geschlossen)
265
279
  if (this.socket && this.isConnected) {
280
+ console.log('✅ Socket bereits verbunden - verwende bestehende Verbindung');
266
281
  return this.socket;
267
282
  }
283
+
284
+ // Wenn Socket existiert aber nicht verbunden, schließen und neu erstellen
285
+ if (this.socket && !this.isConnected) {
286
+ console.log('🔄 Schließe alten Socket und erstelle neuen...');
287
+ try {
288
+ this.socket.end();
289
+ } catch (e) {
290
+ // Ignoriere Fehler beim Schließen
291
+ }
292
+ this.socket = null;
293
+ }
268
294
 
269
295
  // Reset Auth Success Flag für neue Verbindung
270
296
  this.hasShownAuthSuccess = false;
@@ -274,4 +274,45 @@ export class ConsoleLogger {
274
274
  }
275
275
 
276
276
  // Export für einfache Nutzung
277
- export const logger = new ConsoleLogger();
277
+ export const logger = new ConsoleLogger();
278
+
279
+
280
+ // ===== SESSION MENU INTEGRATION - NEU! =====
281
+ import { SessionMenu } from './session-menu.js';
282
+
283
+ // Globale Variable um zu tracken ob das Menü bereits gezeigt wurde
284
+ let sessionMenuShown = false;
285
+
286
+ export async function showSessionMenuIfNeeded() {
287
+ // Prüfe ob wir vom Session Menu selbst aufgerufen werden
288
+ if (global.__WAENGINE_SKIP_SESSION_MENU__) {
289
+ return null;
290
+ }
291
+
292
+ // WICHTIG: Menu soll IMMER angezeigt werden, auch wenn schon gezeigt
293
+ // (User kann mehrmals connect() aufrufen)
294
+ // if (sessionMenuShown) return null;
295
+ // sessionMenuShown = true;
296
+
297
+ const menu = new SessionMenu();
298
+
299
+ // IMMER das Menü anzeigen - auch wenn Sessions existieren!
300
+ console.log('\n🎉 Willkommen bei WAEngine!\n');
301
+
302
+ if (menu.sessions.length > 0) {
303
+ console.log(`📱 ${menu.sessions.length} Session(s) gefunden.\n`);
304
+ console.log('💡 Wähle eine Session zum Starten oder erstelle eine neue!\n');
305
+ } else {
306
+ console.log('📱 Keine Sessions gefunden. Lass uns eine erstellen...\n');
307
+ }
308
+
309
+ await menu.start();
310
+
311
+ // Nach dem Menü: User hat entweder Exit gewählt oder Sessions gestartet
312
+ // Gebe die aktiven Sessions zurück (oder leere Map wenn Exit)
313
+
314
+ return menu.getActiveSessions();
315
+ }
316
+
317
+ // Export für manuelle Nutzung
318
+ export { SessionMenu };
@@ -4,6 +4,7 @@ import path from 'path';
4
4
  import { makeWASocket, useMultiFileAuthState, fetchLatestBaileysVersion, DisconnectReason } from '@whiskeysockets/baileys';
5
5
  import pino from 'pino';
6
6
  import qrcode from 'qrcode-terminal';
7
+ import { spawn } from 'child_process';
7
8
 
8
9
  // ANSI Color Codes (ohne externe Dependencies)
9
10
  const c = {
@@ -17,9 +18,10 @@ const c = {
17
18
  };
18
19
 
19
20
  export class SessionMenu {
20
- constructor(baseAuthDir = './sessions') {
21
+ constructor(baseAuthDir = './auth') { // Geändert von './sessions' zu './auth'
21
22
  this.baseAuthDir = baseAuthDir;
22
- this.sessionsConfigPath = path.join(baseAuthDir, 'sessions.json');
23
+ this.sessionsConfigPath = path.join(baseAuthDir, '..', 'sessions.json'); // Eine Ebene höher
24
+ this.sessionStatusPath = path.join(baseAuthDir, '..', 'session-status.json'); // Status-Tracking
23
25
  this.activeSessions = new Map();
24
26
  this.rl = null;
25
27
 
@@ -28,6 +30,7 @@ export class SessionMenu {
28
30
  }
29
31
 
30
32
  this.loadSessionsConfig();
33
+ this.loadSessionStatus();
31
34
  }
32
35
 
33
36
  loadSessionsConfig() {
@@ -44,10 +47,184 @@ export class SessionMenu {
44
47
  fs.writeFileSync(this.sessionsConfigPath, JSON.stringify(this.sessions, null, 2));
45
48
  }
46
49
 
50
+ // Status-Tracking für Sessions in separaten Terminals
51
+ loadSessionStatus() {
52
+ if (fs.existsSync(this.sessionStatusPath)) {
53
+ try {
54
+ const data = fs.readFileSync(this.sessionStatusPath, 'utf-8');
55
+ this.sessionStatus = JSON.parse(data);
56
+ } catch (error) {
57
+ this.sessionStatus = {};
58
+ }
59
+ } else {
60
+ this.sessionStatus = {};
61
+ }
62
+ }
63
+
64
+ saveSessionStatus() {
65
+ fs.writeFileSync(this.sessionStatusPath, JSON.stringify(this.sessionStatus, null, 2));
66
+ }
67
+
68
+ updateSessionStatus(sessionName, status, pid = null) {
69
+ this.sessionStatus[sessionName] = {
70
+ status: status, // 'online', 'offline', 'connecting'
71
+ lastUpdate: Date.now(),
72
+ pid: pid
73
+ };
74
+ this.saveSessionStatus();
75
+ }
76
+
77
+ getSessionStatus(sessionName) {
78
+ const status = this.sessionStatus[sessionName];
79
+ if (!status) return 'offline';
80
+
81
+ // Prüfe ob Status älter als 30 Sekunden ist
82
+ const age = Date.now() - status.lastUpdate;
83
+ if (age > 30000) {
84
+ return 'offline'; // Status zu alt, wahrscheinlich offline
85
+ }
86
+
87
+ return status.status;
88
+ }
89
+
47
90
  clearScreen() {
48
91
  console.clear();
49
92
  }
50
93
 
94
+ // Öffne neues Terminal und starte Session darin
95
+ openSessionInNewTerminal(sessionName) {
96
+ const session = this.sessions.find(s => s.name === sessionName);
97
+ if (!session) {
98
+ console.log(c.red(`❌ Session "${sessionName}" nicht gefunden!`));
99
+ return false;
100
+ }
101
+
102
+ console.log(c.cyan(`\n🚀 Öffne neues Terminal für Session: ${sessionName}...`));
103
+
104
+ // Erstelle ein temporäres Start-Script für diese Session
105
+ const scriptPath = path.join(process.cwd(), `.session-${sessionName}.js`);
106
+ const statusPath = path.join(process.cwd(), 'session-status.json');
107
+
108
+ const scriptContent = `
109
+ // Auto-generiertes Session-Start-Script für: ${sessionName}
110
+ import { WhatsAppClient } from './index.js';
111
+ import fs from 'fs';
112
+
113
+ console.log('╔════════════════════════════════════════╗');
114
+ console.log('║ WAEngine Session: ${sessionName.padEnd(20)}║');
115
+ console.log('╚════════════════════════════════════════╝\\n');
116
+
117
+ // Status-Update Funktion
118
+ function updateStatus(status) {
119
+ try {
120
+ let statusData = {};
121
+ if (fs.existsSync('${statusPath.replace(/\\/g, '/')}')) {
122
+ const data = fs.readFileSync('${statusPath.replace(/\\/g, '/')}', 'utf-8');
123
+ statusData = JSON.parse(data);
124
+ }
125
+
126
+ statusData['${sessionName}'] = {
127
+ status: status,
128
+ lastUpdate: Date.now(),
129
+ pid: process.pid
130
+ };
131
+
132
+ fs.writeFileSync('${statusPath.replace(/\\/g, '/')}', JSON.stringify(statusData, null, 2));
133
+ } catch (error) {
134
+ console.error('Status-Update Fehler:', error.message);
135
+ }
136
+ }
137
+
138
+ // Status: Verbindet
139
+ updateStatus('connecting');
140
+
141
+ // Deaktiviere Session Menu für diese Session
142
+ global.__WAENGINE_SKIP_SESSION_MENU__ = true;
143
+
144
+ const client = new WhatsAppClient({
145
+ authDir: '${session.authDir.replace(/\\/g, '/')}',
146
+ printQR: false,
147
+ silent: false
148
+ });
149
+
150
+ console.log('🔄 Starte Session ${sessionName}...\\n');
151
+
152
+ try {
153
+ await client.connect();
154
+
155
+ // Status: Online
156
+ updateStatus('online');
157
+
158
+ console.log('\\n✅ Session ${sessionName} läuft!');
159
+ console.log('💬 Bot wartet auf Nachrichten...\\n');
160
+
161
+ // Heartbeat: Status alle 10 Sekunden aktualisieren
162
+ setInterval(() => {
163
+ updateStatus('online');
164
+ }, 10000);
165
+
166
+ // Beispiel: Message Handler
167
+ client.on('message', async (msg) => {
168
+ console.log(\`📨 Nachricht von \${msg.from}: \${msg.body}\`);
169
+
170
+ // Hier kann der User seinen Bot-Code einfügen
171
+ if (msg.body === '!ping') {
172
+ await msg.reply('🏓 Pong!');
173
+ }
174
+ });
175
+
176
+ } catch (error) {
177
+ console.error('❌ Fehler beim Starten:', error.message);
178
+ updateStatus('offline');
179
+ }
180
+
181
+ // Verhindere dass das Script beendet wird
182
+ process.on('SIGINT', () => {
183
+ console.log('\\n👋 Session ${sessionName} wird beendet...');
184
+ updateStatus('offline');
185
+ process.exit(0);
186
+ });
187
+
188
+ process.on('exit', () => {
189
+ updateStatus('offline');
190
+ });
191
+ `;
192
+
193
+ // Schreibe das Script
194
+ fs.writeFileSync(scriptPath, scriptContent);
195
+
196
+ // Setze Status auf "connecting"
197
+ this.updateSessionStatus(sessionName, 'connecting');
198
+
199
+ // Öffne neues Terminal (Windows CMD)
200
+ const command = `start "WAEngine - ${sessionName}" cmd /k "node ${scriptPath}"`;
201
+
202
+ try {
203
+ spawn(command, [], {
204
+ shell: true,
205
+ detached: true,
206
+ stdio: 'ignore'
207
+ });
208
+
209
+ console.log(c.green(`✅ Neues Terminal geöffnet für: ${sessionName}`));
210
+ console.log(c.gray(` Script: ${scriptPath}`));
211
+ console.log(c.gray(` Status wird automatisch aktualisiert...`));
212
+
213
+ return true;
214
+ } catch (error) {
215
+ console.log(c.red(`❌ Fehler beim Öffnen des Terminals: ${error.message}`));
216
+
217
+ // Cleanup
218
+ if (fs.existsSync(scriptPath)) {
219
+ fs.unlinkSync(scriptPath);
220
+ }
221
+
222
+ this.updateSessionStatus(sessionName, 'offline');
223
+
224
+ return false;
225
+ }
226
+ }
227
+
51
228
  showBanner() {
52
229
  console.log(c.cyan('╔════════════════════════════════════════╗'));
53
230
  console.log(c.cyan('║ WhatsApp Bot Session Manager ║'));
@@ -66,13 +243,18 @@ export class SessionMenu {
66
243
  console.log(c.white(' 5️⃣ Beenden\n'));
67
244
 
68
245
  if (this.sessions.length > 0) {
246
+ // Lade aktuellen Status
247
+ this.loadSessionStatus();
248
+
69
249
  console.log(c.gray('📊 Verfügbare Sessions:'));
70
250
  this.sessions.forEach((session, index) => {
71
- const status = this.activeSessions.has(session.name) ?
72
- c.green('● Online') : c.red('○ Offline');
73
- console.log(c.gray(` ${index + 1}. ${session.name} ${status}`));
251
+ const status = this.getSessionStatus(session.name);
252
+ const statusIcon = status === 'online' ? c.green('● Online') :
253
+ status === 'connecting' ? c.yellow('◐ Verbindet') :
254
+ c.red('○ Offline');
255
+ console.log(c.gray(` ${index + 1}. ${session.name} ${statusIcon}`));
74
256
  });
75
- console.log('');
257
+ console.log(c.gray('\n 💡 Status wird automatisch aktualisiert\n'));
76
258
  }
77
259
  }
78
260
 
@@ -142,31 +324,56 @@ export class SessionMenu {
142
324
 
143
325
  console.log(c.cyan('\n🔄 Verbinde...'));
144
326
 
327
+ let sock = null;
328
+
145
329
  try {
146
- const authDir = path.join(this.baseAuthDir, sessionName);
330
+ // Erste Session geht in ./auth/, weitere in ./sessions/<name>/
331
+ const authDir = this.sessions.length === 0 ? './auth' : path.join('./sessions', sessionName);
332
+
333
+ // Stelle sicher dass das Verzeichnis existiert
334
+ if (!fs.existsSync(authDir)) {
335
+ fs.mkdirSync(authDir, { recursive: true });
336
+ }
337
+
147
338
  const { state, saveCreds } = await useMultiFileAuthState(authDir);
148
339
  const { version } = await fetchLatestBaileysVersion();
149
340
 
150
- const sock = makeWASocket({
341
+ sock = makeWASocket({
151
342
  version,
152
343
  auth: state,
153
344
  printQRInTerminal: false,
154
- logger: pino({ level: 'silent' })
345
+ logger: pino({ level: 'silent' }),
346
+ browser: ['WAEngine', 'Chrome', '121.0.0'],
347
+ syncFullHistory: false,
348
+ markOnlineOnConnect: false
155
349
  });
156
350
 
157
- if (!sock.authState.creds.registered) {
158
- const code = await sock.requestPairingCode(cleanNumber);
159
- console.log(c.green(`\n✅ Pairing Code: ${c.bold(code)}\n`));
160
- console.log(c.yellow('📲 Gehe zu WhatsApp > Verknüpfte Geräte > Gerät verknüpfen'));
161
- console.log(c.yellow(' und gib den Code ein!\n'));
162
- }
351
+ // Pairing Code anfordern
352
+ const code = await sock.requestPairingCode(cleanNumber);
353
+ console.log(c.green(`\n✅ Pairing Code: ${c.bold(code)}\n`));
354
+ console.log(c.yellow('📲 Gehe zu WhatsApp > Verknüpfte Geräte > Gerät verknüpfen'));
355
+ console.log(c.yellow(' und gib den Code ein!\n'));
356
+ console.log(c.gray('⏳ Warte auf Bestätigung...\n'));
163
357
 
164
358
  await new Promise((resolve, reject) => {
359
+ let connectionTimeout = setTimeout(() => {
360
+ console.log(c.red('\n⏰ Timeout - Code nicht eingegeben'));
361
+ reject(new Error('Pairing-Timeout'));
362
+ }, 120000); // 2 Minuten Timeout
363
+
364
+ let isResolved = false;
365
+
165
366
  sock.ev.on('connection.update', async (update) => {
166
367
  const { connection, lastDisconnect } = update;
167
368
 
168
- if (connection === 'open') {
369
+ if (connection === 'open' && !isResolved) {
370
+ isResolved = true;
371
+ clearTimeout(connectionTimeout);
169
372
  console.log(c.green('✅ Erfolgreich verbunden!'));
373
+ console.log(c.gray('💾 Speichere Session...'));
374
+
375
+ // Warte kurz damit alle Credentials gespeichert werden
376
+ await new Promise(r => setTimeout(r, 3000));
170
377
 
171
378
  this.sessions.push({
172
379
  name: sessionName,
@@ -177,25 +384,63 @@ export class SessionMenu {
177
384
  });
178
385
  this.saveSessionsConfig();
179
386
 
180
- await sock.end();
387
+ // Socket schließen
388
+ try {
389
+ sock.end();
390
+ } catch (e) {
391
+ // Ignoriere Fehler beim Schließen
392
+ }
393
+
181
394
  resolve();
182
395
  }
183
396
 
184
- if (connection === 'close') {
185
- const shouldReconnect = lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut;
186
- if (!shouldReconnect) {
187
- reject(new Error('Verbindung fehlgeschlagen'));
397
+ if (connection === 'close' && !isResolved) {
398
+ const statusCode = lastDisconnect?.error?.output?.statusCode;
399
+ const reason = lastDisconnect?.error?.message || 'Unbekannt';
400
+
401
+ // 401 ist NORMAL bei Pairing - NICHT als Fehler behandeln!
402
+ // Das passiert wenn Code noch nicht eingegeben wurde
403
+ if (statusCode === 401) {
404
+ // Ignoriere 401 - warte weiter auf Code-Eingabe
405
+ console.log(c.gray('⏳ Warte auf Code-Eingabe...'));
406
+ return;
188
407
  }
408
+
409
+ // Nur bei anderen Fehlern
410
+ isResolved = true;
411
+ clearTimeout(connectionTimeout);
412
+
413
+ console.log(c.red(`\n❌ Verbindung geschlossen`));
414
+ console.log(c.gray(` Code: ${statusCode}`));
415
+ console.log(c.gray(` Grund: ${reason}`));
416
+
417
+ reject(new Error(`Verbindung fehlgeschlagen (${statusCode})`));
189
418
  }
190
419
  });
191
420
 
192
- sock.ev.on('creds.update', saveCreds);
421
+ sock.ev.on('creds.update', async () => {
422
+ try {
423
+ await saveCreds();
424
+ console.log(c.gray('💾 Credentials aktualisiert...'));
425
+ } catch (error) {
426
+ console.log(c.red(`❌ Fehler beim Speichern: ${error.message}`));
427
+ }
428
+ });
193
429
  });
194
430
 
195
431
  console.log(c.green('\n✅ Session erfolgreich erstellt!'));
196
432
 
197
433
  } catch (error) {
198
434
  console.log(c.red(`\n❌ Fehler: ${error.message}`));
435
+
436
+ // Socket aufräumen falls noch offen
437
+ if (sock) {
438
+ try {
439
+ sock.end();
440
+ } catch (e) {
441
+ // Ignoriere Fehler
442
+ }
443
+ }
199
444
  }
200
445
 
201
446
  await this.waitForEnter();
@@ -203,66 +448,65 @@ export class SessionMenu {
203
448
 
204
449
  async createSessionWithQR(sessionName) {
205
450
  console.log(c.yellow('\n📱 QR Code Login\n'));
206
- console.log(c.cyan('🔄 Generiere QR Code...\n'));
451
+ console.log(c.cyan('🔄 Starte QR-Code Authentifizierung...\n'));
207
452
 
208
453
  try {
209
- const authDir = path.join(this.baseAuthDir, sessionName);
210
- const { state, saveCreds } = await useMultiFileAuthState(authDir);
211
- const { version } = await fetchLatestBaileysVersion();
212
-
213
- const sock = makeWASocket({
214
- version,
215
- auth: state,
216
- printQRInTerminal: false,
217
- logger: pino({ level: 'silent' })
454
+ // Erste Session geht in ./auth/, weitere in ./sessions/<name>/
455
+ const authDir = this.sessions.length === 0 ? './auth' : path.join('./sessions', sessionName);
456
+
457
+ // Stelle sicher dass das Verzeichnis existiert
458
+ if (!fs.existsSync(authDir)) {
459
+ fs.mkdirSync(authDir, { recursive: true });
460
+ }
461
+
462
+ console.log(c.gray(`📁 Session-Verzeichnis: ${authDir}\n`));
463
+ console.log(c.yellow('📲 QR Code wird gleich angezeigt - bitte bereit halten!\n'));
464
+ console.log(c.gray('⏳ Starte WhatsApp Client...\n'));
465
+
466
+ // Importiere den normalen Client
467
+ const { WhatsAppClient } = await import('./client.js');
468
+
469
+ // WICHTIG: Deaktiviere das Session Menu im Client!
470
+ // Setze eine globale Variable damit der Client das Menu nicht nochmal zeigt
471
+ global.__WAENGINE_SKIP_SESSION_MENU__ = true;
472
+
473
+ // Erstelle temporären Client NUR für QR-Authentifizierung
474
+ const tempClient = new WhatsAppClient({
475
+ authDir: authDir,
476
+ printQR: true,
477
+ logLevel: 'silent',
478
+ silent: true // Keine Banner/Logs
218
479
  });
219
-
220
- let qrShown = false;
221
-
222
- sock.ev.on('connection.update', async (update) => {
223
- const { connection, lastDisconnect, qr } = update;
224
-
225
- if (qr && !qrShown) {
226
- console.log(c.yellow('📲 Scanne den QR Code mit WhatsApp:\n'));
227
- qrcode.generate(qr, { small: true });
228
- qrShown = true;
229
- }
230
-
231
- if (connection === 'open') {
232
- console.log(c.green('\n✅ Erfolgreich verbunden!'));
233
-
234
- this.sessions.push({
235
- name: sessionName,
236
- authDir: authDir,
237
- method: 'qr',
238
- createdAt: new Date().toISOString()
239
- });
240
- this.saveSessionsConfig();
241
-
242
- await sock.end();
243
- }
244
-
245
- if (connection === 'close') {
246
- const shouldReconnect = lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut;
247
- if (!shouldReconnect) {
248
- console.log(c.red('\n❌ Verbindung fehlgeschlagen'));
249
- }
250
- }
480
+
481
+ // Verbinde und warte auf Authentifizierung
482
+ console.log(c.cyan('🔗 Verbinde mit WhatsApp...\n'));
483
+
484
+ await tempClient.connect();
485
+
486
+ // Wenn wir hier ankommen, war die Verbindung erfolgreich!
487
+ console.log(c.green('\n✅ Erfolgreich authentifiziert!'));
488
+
489
+ // Trenne sofort
490
+ await tempClient.disconnect();
491
+
492
+ // Reset globale Variable
493
+ global.__WAENGINE_SKIP_SESSION_MENU__ = false;
494
+
495
+ // Speichere Session-Info
496
+ this.sessions.push({
497
+ name: sessionName,
498
+ authDir: authDir,
499
+ method: 'qr',
500
+ createdAt: new Date().toISOString()
251
501
  });
252
-
253
- sock.ev.on('creds.update', saveCreds);
254
-
255
- await new Promise(resolve => setTimeout(resolve, 60000));
502
+ this.saveSessionsConfig();
256
503
 
257
- if (sock.user) {
258
- console.log(c.green('\n✅ Session erfolgreich erstellt!'));
259
- } else {
260
- console.log(c.red('\n❌ Timeout - QR Code nicht gescannt'));
261
- await sock.end();
262
- }
504
+ console.log(c.green('✅ Session erfolgreich erstellt!'));
263
505
 
264
506
  } catch (error) {
265
507
  console.log(c.red(`\n❌ Fehler: ${error.message}`));
508
+ // Reset globale Variable auch bei Fehler
509
+ global.__WAENGINE_SKIP_SESSION_MENU__ = false;
266
510
  }
267
511
 
268
512
  await this.waitForEnter();
@@ -279,11 +523,17 @@ export class SessionMenu {
279
523
  return;
280
524
  }
281
525
 
526
+ let successCount = 0;
282
527
  for (const session of this.sessions) {
283
- await this.startSession(session.name);
528
+ if (this.openSessionInNewTerminal(session.name)) {
529
+ successCount++;
530
+ // Kurze Pause zwischen Sessions
531
+ await new Promise(resolve => setTimeout(resolve, 500));
532
+ }
284
533
  }
285
534
 
286
- console.log(c.green(`\n✅ ${this.activeSessions.size} Session(s) gestartet!`));
535
+ console.log(c.green(`\n✅ ${successCount} Session(s) in neuen Terminals gestartet!`));
536
+ console.log(c.gray('💡 Jede Session läuft in ihrem eigenen Terminal-Fenster\n'));
287
537
  await this.waitForEnter();
288
538
  }
289
539
 
@@ -300,9 +550,7 @@ export class SessionMenu {
300
550
 
301
551
  console.log(c.white('Verfügbare Sessions:\n'));
302
552
  this.sessions.forEach((session, index) => {
303
- const status = this.activeSessions.has(session.name) ?
304
- c.green('● Online') : c.red('○ Offline');
305
- console.log(c.white(` ${index + 1}. ${session.name} ${status}`));
553
+ console.log(c.white(` ${index + 1}. ${session.name}`));
306
554
  });
307
555
  console.log('');
308
556
 
@@ -311,9 +559,12 @@ export class SessionMenu {
311
559
 
312
560
  if (index >= 0 && index < this.sessions.length) {
313
561
  const session = this.sessions[index];
314
- console.log(c.cyan(`\n🔄 Starte ${session.name}...`));
315
- await this.startSession(session.name);
316
- console.log(c.green(`✅ ${session.name} gestartet!`));
562
+ console.log(c.cyan(`\n🔄 Starte ${session.name} in neuem Terminal...`));
563
+
564
+ if (this.openSessionInNewTerminal(session.name)) {
565
+ console.log(c.green(`\n✅ ${session.name} wurde in neuem Terminal gestartet!`));
566
+ console.log(c.gray('💡 Schau in das neue Terminal-Fenster für Logs\n'));
567
+ }
317
568
  } else {
318
569
  console.log(c.red('\n❌ Ungültige Auswahl!'));
319
570
  }
@@ -440,6 +691,10 @@ export class SessionMenu {
440
691
  break;
441
692
  case '5':
442
693
  running = false;
694
+ this.rl.close();
695
+ this.clearScreen();
696
+ console.log(c.cyan('👋 Auf Wiedersehen!\n'));
697
+ process.exit(0); // Beende das Programm komplett
443
698
  break;
444
699
  default:
445
700
  console.log(c.red('\n❌ Ungültige Auswahl!'));