vantuz 3.4.1 → 3.5.0

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 (70) hide show
  1. package/LICENSE +45 -45
  2. package/admin-keygen.js +51 -0
  3. package/cli.js +685 -585
  4. package/config.js +733 -733
  5. package/core/agent-loop.js +190 -190
  6. package/core/ai-provider.js +298 -261
  7. package/core/automation.js +523 -523
  8. package/core/brand-analyst.js +101 -0
  9. package/core/channels.js +167 -167
  10. package/core/dashboard.js +230 -230
  11. package/core/database.js +135 -36
  12. package/core/eia-monitor.js +3 -1
  13. package/core/engine.js +648 -636
  14. package/core/gateway.js +447 -447
  15. package/core/learning.js +214 -214
  16. package/core/license.js +113 -0
  17. package/core/marketplace-adapter.js +168 -168
  18. package/core/memory.js +190 -190
  19. package/core/migrations/001-initial-schema.sql +1 -1
  20. package/core/queue.js +120 -120
  21. package/core/self-healer.js +314 -314
  22. package/core/unified-product.js +214 -214
  23. package/core/vision-service.js +113 -113
  24. package/index.js +217 -174
  25. package/modules/crm/sentiment-crm.js +231 -231
  26. package/modules/healer/listing-healer.js +201 -201
  27. package/modules/oracle/predictor.js +214 -214
  28. package/modules/researcher/agent.js +169 -169
  29. package/modules/team/agents/base.js +92 -92
  30. package/modules/team/agents/dev.js +33 -33
  31. package/modules/team/agents/josh.js +40 -40
  32. package/modules/team/agents/marketing.js +33 -33
  33. package/modules/team/agents/milo.js +36 -36
  34. package/modules/team/index.js +78 -78
  35. package/modules/team/shared-memory.js +87 -87
  36. package/modules/war-room/competitor-tracker.js +250 -250
  37. package/modules/war-room/pricing-engine.js +308 -308
  38. package/nodes/warehouse.js +238 -238
  39. package/onboard.js +1 -1
  40. package/package.json +7 -6
  41. package/platforms/pttavm.js +14 -14
  42. package/plugins/vantuz/index.js +528 -528
  43. package/plugins/vantuz/memory/hippocampus.js +465 -464
  44. package/plugins/vantuz/package.json +20 -20
  45. package/plugins/vantuz/platforms/_template.js +118 -118
  46. package/plugins/vantuz/platforms/amazon.js +236 -236
  47. package/plugins/vantuz/platforms/ciceksepeti.js +166 -166
  48. package/plugins/vantuz/platforms/hepsiburada.js +180 -180
  49. package/plugins/vantuz/platforms/index.js +165 -165
  50. package/plugins/vantuz/platforms/n11.js +229 -229
  51. package/plugins/vantuz/platforms/pazarama.js +154 -154
  52. package/plugins/vantuz/platforms/pttavm.js +127 -127
  53. package/plugins/vantuz/platforms/trendyol.js +326 -326
  54. package/plugins/vantuz/services/alerts.js +253 -253
  55. package/plugins/vantuz/services/license.js +34 -34
  56. package/plugins/vantuz/services/scheduler.js +232 -232
  57. package/plugins/vantuz/tools/analytics.js +152 -152
  58. package/plugins/vantuz/tools/crossborder.js +187 -187
  59. package/plugins/vantuz/tools/nl-parser.js +211 -211
  60. package/plugins/vantuz/tools/product.js +110 -110
  61. package/plugins/vantuz/tools/quick-report.js +175 -175
  62. package/plugins/vantuz/tools/repricer.js +314 -314
  63. package/plugins/vantuz/tools/sentiment.js +115 -115
  64. package/plugins/vantuz/tools/vision.js +257 -257
  65. package/private.pem +28 -0
  66. package/public.pem +9 -0
  67. package/server/app.js +260 -260
  68. package/server/public/index.html +514 -514
  69. package/start.bat +33 -33
  70. package/vantuz.sqlite +0 -0
package/config.js CHANGED
@@ -1,733 +1,733 @@
1
-
2
-
3
- /**
4
- * VANTUZ - Profesyonel Kurulum Sihirbazı
5
- * v3.2.7 - Gateway Entegrasyonlu
6
- */
7
-
8
- import fs from 'fs';
9
- import path from 'path';
10
- import os from 'os';
11
- import readline from 'readline';
12
- import { fileURLToPath, pathToFileURL } from 'url';
13
- import { PROVIDER_CONFIG } from './core/ai-provider.js'; // Import PROVIDER_CONFIG
14
-
15
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
16
- const VANTUZ_HOME = path.join(os.homedir(), '.vantuz');
17
- const CONFIG_PATH = path.join(VANTUZ_HOME, '.env');
18
-
19
- // Enhanced Colors with background support
20
- const colors = {
21
- reset: '\x1b[0m',
22
- bold: '\x1b[1m',
23
- dim: '\x1b[2m',
24
- italic: '\x1b[3m',
25
- underscore: '\x1b[4m',
26
-
27
- // Foreground colors
28
- black: '\x1b[30m',
29
- red: '\x1b[31m',
30
- green: '\x1b[32m',
31
- yellow: '\x1b[33m',
32
- blue: '\x1b[34m',
33
- magenta: '\x1b[35m',
34
- cyan: '\x1b[36m',
35
- white: '\x1b[37m',
36
-
37
- // Bright foreground colors
38
- brightBlack: '\x1b[90m',
39
- brightRed: '\x1b[91m',
40
- brightGreen: '\x1b[92m',
41
- brightYellow: '\x1b[93m',
42
- brightBlue: '\x1b[94m',
43
- brightMagenta: '\x1b[95m',
44
- brightCyan: '\x1b[96m',
45
- brightWhite: '\x1b[97m',
46
-
47
- // Background colors
48
- bgBlack: '\x1b[40m',
49
- bgRed: '\x1b[41m',
50
- bgGreen: '\x1b[42m',
51
- bgYellow: '\x1b[43m',
52
- bgBlue: '\x1b[44m',
53
- bgMagenta: '\x1b[45m',
54
- bgCyan: '\x1b[46m',
55
- bgWhite: '\x1b[47m'
56
- };
57
-
58
- const c = (color, text) => `${colors[color]}${text}${colors.reset}`;
59
- const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
60
-
61
- // Enhanced box drawing characters
62
- const box = {
63
- topLeft: '╔',
64
- topRight: '╗',
65
- bottomLeft: '╚',
66
- bottomRight: '╝',
67
- horizontal: '═',
68
- vertical: '║',
69
- leftT: '╠',
70
- rightT: '╣',
71
- topT: '╦',
72
- bottomT: '╩',
73
- cross: '╬'
74
- };
75
-
76
- const LOGO = `
77
- ${colors.cyan}${colors.bold}
78
- ╦ ╦╔═╗╔╗╔╔╦╗╦ ╦╔═╗ ╔═╗╦
79
- ╚╗╔╝╠═╣║║║ ║ ║ ║╔═╝ ╠═╣║
80
- ╚╝ ╩ ╩╝╚╝ ╩ ╚═╝╚═╝ ╩ ╩╩
81
- ${colors.reset}
82
- ${colors.brightCyan} Enterprise E-Ticaret Yönetimi${colors.reset}
83
- `;
84
-
85
- const createBox = (title, content, width = 65) => {
86
- const lines = content.split('\n');
87
- let result = '';
88
-
89
- // Top border with title
90
- result += c('brightCyan', box.topLeft + box.horizontal.repeat(3));
91
- result += c('bold', ` ${title} `);
92
- result += c('brightCyan', box.horizontal.repeat(width - title.length - 5) + box.topRight) + '\n';
93
-
94
- // Content
95
- lines.forEach(line => {
96
- const padding = ' '.repeat(Math.max(0, width - line.length - 2));
97
- result += c('brightCyan', box.vertical) + ' ' + line + padding + ' ' + c('brightCyan', box.vertical) + '\n';
98
- });
99
-
100
- // Bottom border
101
- result += c('brightCyan', box.bottomLeft + box.horizontal.repeat(width) + box.bottomRight) + '\n';
102
-
103
- return result;
104
- };
105
-
106
- const WELCOME_BOX = createBox('HOŞ GELDİNİZ', `
107
- Bu sihirbaz kurulumu tamamlamanıza yardımcı olacak:
108
-
109
- ${c('brightGreen', '✓')} AI Servis Seçimi
110
- ${c('brightGreen', '✓')} Pazaryeri Bağlantıları
111
- ${c('brightGreen', '✓')} İletişim Kanalları
112
- ${c('brightGreen', '✓')} Gateway Yapılandırması
113
- `);
114
-
115
- class Configurator {
116
- constructor() {
117
- this.envVars = Configurator.loadEnvFile();
118
- this.step = 0;
119
- this.rl = readline.createInterface({
120
- input: process.stdin,
121
- output: process.stdout,
122
- crlfDelay: Infinity
123
- });
124
- this.platforms = []; // Initialize platforms array
125
- }
126
-
127
- async _loadPlatformMetadata() {
128
- const platformFiles = await fs.promises.readdir(path.join(__dirname, 'platforms'));
129
- const dynamicPlatforms = [];
130
-
131
- for (const file of platformFiles) {
132
- if (file.endsWith('.js') && !file.startsWith('_')) { // Exclude helper files
133
- const platformPath = path.join(__dirname, 'platforms', file);
134
- try {
135
- // Dynamic import for ES Modules
136
- const platformModule = await import(pathToFileURL(platformPath).href);
137
- // Check if module.exports is present (CommonJS) or default export (ESM)
138
- const platform = platformModule.default || platformModule;
139
-
140
- if (platform.name && platform.requiredFields) {
141
- dynamicPlatforms.push({
142
- id: file.replace('.js', ''),
143
- name: platform.name,
144
- icon: platform.icon || '🛒', // Default icon if not specified
145
- description: platform.description || '',
146
- requiredFields: platform.requiredFields
147
- });
148
- }
149
- } catch (error) {
150
- console.warn(this.warningMessage(`Platform dosyasını yüklerken hata oluştu: ${file} - ${error.message}`));
151
- }
152
- }
153
- }
154
- // Sort platforms alphabetically by name
155
- this.platforms = dynamicPlatforms.sort((a, b) => a.name.localeCompare(b.name));
156
- }
157
-
158
- static loadEnvFile() {
159
- const env = {};
160
- try {
161
- if (fs.existsSync(CONFIG_PATH)) {
162
- const content = fs.readFileSync(CONFIG_PATH, 'utf-8');
163
- content.split('\n').forEach(line => {
164
- const match = line.match(/^([^=]+)=(.*)$/);
165
- if (match) env[match[1].trim()] = match[2].trim();
166
- });
167
- }
168
- } catch (e) {
169
- console.error(c('red', `✗ Config yükleme hatası: ${e.message}`));
170
- }
171
- return env;
172
- }
173
-
174
- async step_EIAConfig() {
175
- this.printHeader('E-TİCARET YÖNETİM AJANSI (EIA) YAPILANDIRMASI', '📊');
176
-
177
- console.log(c('brightWhite', 'EIA\'nın e-ticaret operasyonlarınızı optimize etmesi için kritik bilgiler sağlayın.\n'));
178
- console.log(this.infoMessage('Bu bilgiler, EIA\'nın pazar analizi ve stratejik kararlarında kullanılacaktır.'));
179
-
180
- await sleep(200);
181
-
182
- const currentCompetitorUrls = this.envVars.EIA_COMPETITOR_URLS || '';
183
- console.log(this.createInputBox('Rakip Ürün URL\'leri', 'Virgülle ayırarak birden fazla rakip ürün veya kategori URL\'si girebilirsiniz. (Örn: https://rakip.com/urun1, https://rakip.com/kategori)'));
184
- const competitorUrls = await this.prompt('', currentCompetitorUrls);
185
-
186
- // Basic validation for URLs
187
- const urls = competitorUrls.split(',').map(url => url.trim()).filter(url => url !== '');
188
- const invalidUrls = urls.filter(url => url && (!url.startsWith('http://') && !url.startsWith('https://')));
189
-
190
- if (competitorUrls && invalidUrls.length === 0) {
191
- this.envVars.EIA_COMPETITOR_URLS = competitorUrls.trim();
192
- console.log(this.successMessage('Rakip URL\'leri kaydedildi/güncellendi. EIA, bu kaynakları izleyecektir.'));
193
- } else if (competitorUrls && invalidUrls.length > 0) {
194
- console.log(this.errorMessage(`Geçersiz URL(ler) tespit edildi: ${invalidUrls.join(', ')}. Lütfen geçerli URL'ler girin.`));
195
- // Do not save invalid URLs, keep previous if any
196
- if (currentCompetitorUrls) { // If there were previous valid URLs, keep them.
197
- this.envVars.EIA_COMPETITOR_URLS = currentCompetitorUrls;
198
- } else { // If there were no previous valid URLs, clear it.
199
- delete this.envVars.EIA_COMPETITOR_URLS;
200
- }
201
- await sleep(2000); // Give user time to read error
202
- }
203
- else { // If competitorUrls is empty
204
- if (this.envVars.EIA_COMPETITOR_URLS) {
205
- delete this.envVars.EIA_COMPETITOR_URLS;
206
- console.log(this.infoMessage('Rakip URL\'leri temizlendi. EIA, rakip analizi yapmayacaktır.'));
207
- } else {
208
- console.log(this.infoMessage('Rakip URL\'leri girilmedi. EIA, rakip analizi yapmayacaktır.'));
209
- }
210
- }
211
-
212
- const currentProfitMargin = this.envVars.EIA_TARGET_PROFIT_MARGIN ? String(this.envVars.EIA_TARGET_PROFIT_MARGIN) : '15';
213
- console.log(this.createInputBox('Hedef Kar Marjı (%)', 'Ürünleriniz için ulaşmak istediğiniz ortalama kar marjı hedefi. (Örnek: 15)'));
214
- const profitMargin = await this.prompt('', currentProfitMargin);
215
-
216
- if (profitMargin && !isNaN(parseFloat(profitMargin)) && parseFloat(profitMargin) >= 0) {
217
- this.envVars.EIA_TARGET_PROFIT_MARGIN = parseFloat(profitMargin);
218
- console.log(this.successMessage('Hedef Kar Marjı kaydedildi/güncellendi. EIA, fiyatlandırma önerilerinde bu marjı dikkate alacaktır.'));
219
- } else {
220
- if (this.envVars.EIA_TARGET_PROFIT_MARGIN) {
221
- delete this.envVars.EIA_TARGET_PROFIT_MARGIN;
222
- console.log(this.infoMessage('Hedef Kar Marjı temizlendi. EIA, varsayılan bir kar marjı kullanabilir.'));
223
- } else {
224
- this.envVars.EIA_TARGET_PROFIT_MARGIN = 15; // Default if invalid and no previous value
225
- console.log(this.infoMessage('Geçersiz kar marjı girildi, varsayılan %15 kullanılacaktır.'));
226
- }
227
- }
228
- await sleep(1000);
229
- }
230
-
231
- clear() {
232
- console.clear();
233
- }
234
-
235
- async showLogo() {
236
- this.clear();
237
- console.log(LOGO);
238
- await sleep(500);
239
- }
240
-
241
- async runFullOnboarding() {
242
- try {
243
- await this.showLogo();
244
- await this.showWelcome();
245
- console.log(c('brightGreen', '⚡ Geliştirici Modu: Lisans kontrolü atlandı.\n'));
246
- await this._loadPlatformMetadata(); // Load platform data
247
- await this.step1_AIProvider();
248
- await this.step2_Platforms();
249
- await this.step3_Channels();
250
- await this.step4_Gateway();
251
- await this.step_EIAConfig();
252
- await this.step_RiskAcceptance(); // Add risk acceptance step
253
- await this.step5_Save();
254
- await this.showSuccess();
255
- } catch (error) {
256
- console.error('\n' + this.errorMessage(`Beklenmeyen Hata: ${error.message}`));
257
- } finally {
258
- this.close();
259
- }
260
- }
261
-
262
- async run() {
263
- try {
264
- await this.showLogo();
265
- await this._loadPlatformMetadata(); // Load platform data
266
-
267
- while (true) {
268
- this.printHeader('VANTUZ YAPILANDIRMA MENÜSÜ', '⚙️');
269
-
270
- console.log(c('brightWhite', 'Lütfen yapılandırmak istediğiniz alanı seçin:\n'));
271
-
272
- console.log(this.menuItem('1', '🤖 Yapay Zeka Servisi', 'AI Provider'));
273
- console.log(this.menuItem('2', '🛒 Pazaryeri Entegrasyonları', 'Platforms'));
274
- console.log(this.menuItem('3', '💬 İletişim Kanalları', 'Channels'));
275
- console.log(this.menuItem('4', '🌐 Vantuz Gateway', 'Gateway Configuration'));
276
- console.log(this.menuItem('5', '📊 E-Ticaret Yönetim Ajansı', 'EIA'));
277
- console.log('');
278
- console.log(this.menuItem('A', '🚀 Tümünü Yapılandır', 'Full Onboarding', 'dim'));
279
- console.log(this.menuItem('S', '💾 Kaydet ve Çık', 'Save & Exit', 'dim'));
280
- console.log(this.menuItem('İ', '❌ İptal Et', 'Cancel without saving', 'dim'));
281
- console.log('');
282
-
283
- const choice = await this.prompt(c('brightYellow', '❯ Seçiminiz (1-5, A, S, İ)'));
284
-
285
- switch (choice.toLowerCase()) {
286
- case '1': await this.step1_AIProvider(); break;
287
- case '2': await this.step2_Platforms(); break;
288
- case '3': await this.step3_Channels(); break;
289
- case '4': await this.step4_Gateway(); break;
290
- case '5': await this.step_EIAConfig(); break;
291
- case 'a': await this.runFullOnboarding(); return;
292
- case 's':
293
- await this.step5_Save();
294
- await this.showSuccess();
295
- return;
296
- case 'i':
297
- case 'İ':
298
- console.log(this.warningMessage('Yapılandırma iptal edildi. Değişiklikler kaydedilmedi.'));
299
- return;
300
- default:
301
- console.log(this.errorMessage('Geçersiz seçim. Lütfen tekrar deneyin.'));
302
- await sleep(1000);
303
- }
304
- }
305
- } catch (error) {
306
- console.error('\n' + this.errorMessage(`Beklenmeyen Hata: ${error.message}`));
307
- } finally {
308
- this.close();
309
- }
310
- }
311
-
312
- close() {
313
- if (this.rl) {
314
- this.rl.close();
315
- this.rl = null;
316
- }
317
- }
318
-
319
- printHeader(title, icon = '') {
320
- this.clear();
321
- console.log(LOGO);
322
- console.log('');
323
- const fullTitle = icon ? `${icon} ${title}` : title;
324
- console.log(c('bold', c('brightWhite', fullTitle)));
325
- console.log(c('brightCyan', '─'.repeat(65)));
326
- console.log('');
327
- }
328
-
329
- async showWelcome() {
330
- console.log(WELCOME_BOX);
331
- await this.prompt(c('dim', '▶ Devam etmek için Enter\'a basın...'));
332
- }
333
-
334
- menuItem(key, title, subtitle = '', style = 'normal') {
335
- const keyStyle = style === 'dim' ? 'dim' : 'brightYellow';
336
- const titleStyle = style === 'dim' ? 'dim' : 'brightWhite';
337
- const subtitleStyle = 'dim';
338
-
339
- let line = ` ${c(keyStyle, c('bold', key))}. ${c(titleStyle, title)}`;
340
- if (subtitle) {
341
- line += ` ${c(subtitleStyle, `(${subtitle})`)}`;
342
- }
343
- return line;
344
- }
345
-
346
- createInputBox(label, hint = '') {
347
- let output = '\n' + c('brightCyan', '┌─ ') + c('bold', label);
348
- if (hint) {
349
- output += ' ' + c('dim', `(${hint})`);
350
- }
351
- output += '\n' + c('brightCyan', '│ ');
352
- return output;
353
- }
354
-
355
- successMessage(text) {
356
- return '\n' + c('brightGreen', '✓ ') + c('green', text) + '\n';
357
- }
358
-
359
- errorMessage(text) {
360
- return c('brightRed', '✗ ') + c('red', text);
361
- }
362
-
363
- warningMessage(text) {
364
- return '\n' + c('brightYellow', '⚠ ') + c('yellow', text) + '\n';
365
- }
366
-
367
- infoMessage(text) {
368
- return '\n' + c('brightBlue', 'ℹ ') + c('blue', text) + '\n';
369
- }
370
-
371
- // ADIM 1: AI PROVIDER
372
- async step1_AIProvider() {
373
- this.printHeader('YAPAY ZEKA SERVİSİ', '🤖');
374
-
375
- console.log(c('brightWhite', 'Kullanılacak AI modelini seçin:\n'));
376
-
377
- // Dynamically generate menu items from PROVIDER_CONFIG
378
- const providerKeys = Object.keys(PROVIDER_CONFIG);
379
- const providerOptions = providerKeys.map((key, index) => {
380
- const providerInfo = PROVIDER_CONFIG[key];
381
- const label = providerInfo.config_label || key.charAt(0).toUpperCase() + key.slice(1);
382
- const description = providerInfo.config_description || '';
383
- const icon = providerInfo.config_icon || '';
384
- return {
385
- choice: String(index + 1),
386
- label: `${icon} ${label}`,
387
- description: description,
388
- envKey: providerInfo.envKey, // Store the actual env key
389
- key: key // Store the provider key (e.g., 'gemini', 'groq')
390
- };
391
- });
392
-
393
- providerOptions.forEach(option => {
394
- console.log(this.menuItem(option.choice, option.label, option.description));
395
- });
396
- console.log(this.menuItem('S', 'Atla', 'Daha sonra ayarla', 'dim'));
397
- console.log('');
398
-
399
- await sleep(200);
400
-
401
- let currentAIChoice = '';
402
- for (const option of providerOptions) {
403
- if (this.envVars[option.envKey]) {
404
- currentAIChoice = option.choice;
405
- break;
406
- }
407
- }
408
- if (!currentAIChoice && this.envVars.GEMINI_API_KEY) { // Fallback to Gemini if no other is set but Gemini is.
409
- currentAIChoice = providerOptions.find(opt => opt.envKey === 'GEMINI_API_KEY')?.choice || '';
410
- }
411
- if (!currentAIChoice) currentAIChoice = '1'; // Default to first option if nothing is set
412
-
413
- const choice = await this.prompt(c('brightYellow', '❯ Seçiminiz (1-' + providerOptions.length + ' veya S)'), currentAIChoice);
414
-
415
- if (choice.toLowerCase() === 's') {
416
- console.log(this.warningMessage('AI yapılandırması geçildi'));
417
- await sleep(1000);
418
- return;
419
- }
420
-
421
- const selectedOption = providerOptions.find(option => option.choice === choice);
422
-
423
- if (!selectedOption) {
424
- console.log(this.errorMessage('Geçersiz seçim. Lütfen tekrar deneyin.'));
425
- await sleep(1000);
426
- return;
427
- }
428
-
429
- console.log(this.successMessage(`${selectedOption.label.trim()} seçildi`));
430
-
431
- const currentKey = this.envVars[selectedOption.envKey] || '';
432
- console.log(this.createInputBox(`${selectedOption.label.trim()} API Key`, 'Mevcut değeri değiştirmek için yeni değer girin'));
433
- const key = await this.prompt('', currentKey);
434
-
435
- if (key && key.trim()) {
436
- this.envVars[selectedOption.envKey] = key.trim();
437
- this.envVars.AI_PROVIDER = selectedOption.key; // Save the provider key (e.g., 'groq')
438
-
439
- // Clear other AI keys if one is selected
440
- providerOptions.forEach(option => {
441
- if (option.envKey !== selectedOption.envKey && this.envVars[option.envKey]) {
442
- delete this.envVars[option.envKey];
443
- }
444
- });
445
- console.log(this.successMessage('API anahtarı ve sağlayıcı seçimi kaydedildi'));
446
- } else {
447
- if (this.envVars[selectedOption.envKey]) {
448
- delete this.envVars[selectedOption.envKey];
449
- console.log(this.infoMessage('API anahtarı temizlendi'));
450
- } else {
451
- console.log(this.infoMessage('API anahtarı girilmedi, daha sonra ekleyebilirsiniz'));
452
- }
453
- }
454
- await sleep(1000);
455
- }
456
-
457
- // ADIM 2: PAZARYERLERİ
458
- async step2_Platforms() {
459
- this.printHeader('PAZARYERİ ENTEGRASYONLARI', '🛒');
460
-
461
- console.log(c('brightWhite', 'Hangi pazaryerini yapılandırmak istersiniz?\n'));
462
-
463
- // Dynamically generate menu items from this.platforms
464
- this.platforms.forEach((platform, index) => {
465
- console.log(this.menuItem(String(index + 1), `${platform.icon} ${platform.name}`, platform.description));
466
- });
467
- console.log(this.menuItem('S', 'Atla', 'Tümünü geç', 'dim'));
468
- console.log('');
469
-
470
- await sleep(200);
471
- const choice = await this.prompt(c('brightYellow', '❯ Seçiminiz (1-' + this.platforms.length + ' veya S)'));
472
-
473
- if (choice.toLowerCase() === 's') {
474
- console.log(this.warningMessage('Pazaryeri yapılandırması geçildi'));
475
- return;
476
- }
477
-
478
- const selectedPlatform = this.platforms[parseInt(choice) - 1];
479
-
480
- if (!selectedPlatform) {
481
- console.log(this.errorMessage('Geçersiz seçim. Lütfen tekrar deneyin.'));
482
- await sleep(1000);
483
- return;
484
- }
485
-
486
- console.log(this.successMessage(`${selectedPlatform.icon} ${selectedPlatform.name} seçildi`));
487
- console.log(c('dim', 'Mevcut değerleri değiştirmek için yeni değer girin veya boş bırakın\n'));
488
-
489
- let allFieldsProvided = true;
490
- for (const field of selectedPlatform.requiredFields) {
491
- const currentVal = this.envVars[field.env] || '';
492
- console.log(this.createInputBox(field.label));
493
- const value = await this.prompt('', currentVal);
494
-
495
- if (value && value.trim()) {
496
- this.envVars[field.env] = value.trim();
497
- } else {
498
- // If a required field is left empty, consider it not fully configured
499
- allFieldsProvided = false;
500
- delete this.envVars[field.env]; // Clear it if left empty
501
- }
502
- }
503
-
504
- if (allFieldsProvided) {
505
- console.log(this.successMessage(`${selectedPlatform.name} bilgileri alındı/güncellendi`));
506
- // Clear keys for other platforms to ensure only one platform's config is active if not multiple
507
- // This logic might need refinement if multiple platforms can be configured simultaneously.
508
- // For now, assuming mutually exclusive configuration.
509
- this.platforms.forEach(platform => {
510
- if (platform.id !== selectedPlatform.id) {
511
- platform.requiredFields.forEach(field => {
512
- if (this.envVars[field.env]) {
513
- delete this.envVars[field.env];
514
- }
515
- });
516
- }
517
- });
518
- } else {
519
- console.log(this.infoMessage(`${selectedPlatform.name} bilgileri eksik, kaydedilmedi/temizlenmedi`));
520
- }
521
- await sleep(1000);
522
- }
523
-
524
- // ADIM 3: KANALLAR
525
- async step3_Channels() {
526
- this.printHeader('İLETİŞİM KANALLARI', '💬');
527
-
528
- console.log(c('brightWhite', 'Hangi iletişim kanalını yapılandırmak istersiniz?\n'));
529
-
530
- console.log(this.menuItem('1', 'Telegram Bot', 'Anlık bildirimler ve sohbet için'));
531
- console.log(this.menuItem('2', 'WhatsApp', 'Gateway üzerinden yönetilir'));
532
- console.log(this.menuItem('S', 'Atla', 'Daha sonra ayarla', 'dim'));
533
- console.log('');
534
-
535
- await sleep(200);
536
- const choice = await this.prompt(c('brightYellow', '❯ Seçiminiz (1-2 veya S)'));
537
-
538
- if (choice.toLowerCase() === 's') {
539
- console.log(this.warningMessage('İletişim kanalları yapılandırması geçildi'));
540
- await sleep(1000);
541
- return;
542
- }
543
-
544
- if (choice === '1') { // Configure Telegram
545
- console.log('\n' + c('bold', 'Telegram Bot Yapılandırması'));
546
- console.log(c('dim', 'Mevcut değeri değiştirmek için yeni değer girin veya boş bırakın\n'));
547
-
548
- const currentTelegramToken = this.envVars.TELEGRAM_BOT_TOKEN || '';
549
- console.log(this.createInputBox('Telegram Bot Token', 'BotFather\'dan alınan token'));
550
- const token = await this.prompt('', currentTelegramToken);
551
-
552
- if (token && token.trim()) {
553
- this.envVars.TELEGRAM_BOT_TOKEN = token.trim();
554
- console.log(this.successMessage('Telegram token alındı/güncellendi'));
555
- } else {
556
- delete this.envVars.TELEGRAM_BOT_TOKEN;
557
- console.log(this.infoMessage('Telegram token temizlendi'));
558
- }
559
- await sleep(1000);
560
- } else if (choice === '2') { // Information about WhatsApp
561
- this.printHeader('WhatsApp Kurulum Bilgisi', '💬');
562
- console.log(this.infoMessage('WhatsApp entegrasyonu Vantuz Gateway üzerinden sağlanır.'));
563
- console.log(c('brightWhite', 'Gateway\'inizi yapılandırdıktan ve başlattıktan sonra, Gateway arayüzünden WhatsApp kanalını etkinleştirebilirsiniz.\n'));
564
- console.log(c('dim', ' Gateway durumunu kontrol etmek için: ') + c('brightCyan', 'vantuz gateway status'));
565
- console.log(c('dim', ' Gateway\'i başlatmak için: ') + c('brightCyan', 'start.bat') + '\n');
566
- await this.prompt(c('dim', '▶ Devam etmek için Enter\'a basın...'));
567
- } else {
568
- console.log(this.errorMessage('Geçersiz seçim. Lütfen tekrar deneyin.'));
569
- await sleep(1000);
570
- return;
571
- }
572
- }
573
-
574
- // ADIM 4: VANTUZ GATEWAY
575
- async step4_Gateway() {
576
- this.printHeader('VANTUZ GATEWAY', '🌐');
577
-
578
- console.log(c('brightWhite', 'Vantuz Gateway, AI ve kanal yönetimini güçlendirir.\n'));
579
-
580
- const setupChoice = await this.prompt('Gateway durumunu kontrol etmek ve yapılandırmak ister misiniz? (e/H)', 'e');
581
-
582
- if (setupChoice.toLowerCase() === 'h') {
583
- console.log(this.warningMessage('Gateway yapılandırması geçildi'));
584
- await sleep(1000);
585
- return;
586
- }
587
-
588
- // Dynamically import getGateway to avoid circular dependency if not already imported
589
- const { getGateway } = await import('./core/gateway.js');
590
- const gateway = await getGateway();
591
- const info = gateway.getInfo();
592
-
593
- console.log(c('brightYellow', '\n── Gateway Mevcut Durumu ──'));
594
- console.log(` URL: ${c('cyan', info.url)}`);
595
- console.log(` Durum: ${info.connected ? c('brightGreen', '● Bağlı') : c('brightRed', '○ Bağlı Değil')}`);
596
- console.log(` Token: ${info.hasToken ? c('brightGreen', '✔ Yapılandırılmış') : c('brightRed', '✘ Eksik/Geçersiz')}`);
597
- console.log(` Config: ${info.configFound ? c('brightGreen', '✔ Bulundu (gateway config)') : c('brightRed', '✘ Bulunamadı (gateway config)')}`);
598
- if (info.version) console.log(` Sürüm: ${c('dim', info.version)}`);
599
- console.log('');
600
-
601
- if (!info.configFound || !info.hasToken || !info.connected) {
602
- console.log(this.warningMessage('Gateway tam olarak yapılandırılmamış veya çalışmıyor.'));
603
-
604
- const startChoice = await this.prompt('Sistemi otomatik başlatmak ister misiniz? (E/h)', 'E');
605
- if (startChoice.toLowerCase() !== 'h') {
606
- console.log(c('dim', 'Sistem başlatılıyor (Gateway + Server)...'));
607
- const result = await gateway.startFullStack();
608
-
609
- if (result.success) {
610
- console.log(this.successMessage('Başlatma komutları gönderildi.'));
611
- console.log(c('dim', 'Servislerin açılması 10-15 saniye sürebilir.'));
612
- await sleep(5000); // Wait a bit before re-checking
613
-
614
- // Re-check status
615
- const newInfo = (await gateway.health()).success;
616
- if (newInfo) console.log(this.successMessage('Gateway bağlantısı sağlandı!'));
617
- else console.log(c('yellow', 'Gateway henüz hazır değil, arka planda açılıyor...'));
618
- } else {
619
- console.log(this.errorMessage('Başlatma sırasında hata oluştu.'));
620
- if (result.gateway?.error) console.log(c('red', `Gateway Hatası: ${result.gateway.error}`));
621
- if (result.server?.error) console.log(c('red', `Server Hatası: ${result.server.error}`));
622
- }
623
- } else {
624
- console.log(c('dim', 'Manuel başlatmak için `start.bat` kullanabilirsiniz.'));
625
- }
626
- } else {
627
- console.log(this.successMessage('Gateway başarılı bir şekilde yapılandırılmış ve çalışıyor.'));
628
- console.log(c('dim', 'Durumu kontrol etmek için: vantuz gateway status'));
629
- }
630
- await this.prompt(c('dim', '▶ Devam etmek için Enter\'a basın...'));
631
- }
632
-
633
- // KAYDET
634
- async step_RiskAcceptance() {
635
- if (this.envVars.RISK_ACCEPTED === 'true') return;
636
-
637
- this.printHeader('RİSK KABULÜ', '⚠️');
638
- console.log(c('brightWhite', 'Vantuz AI, sizin adınıza fiyat ve stok güncellemeleri yapabilir.\n'));
639
- console.log(c('yellow', 'Bazı işlemler geri alınamaz olabilir. Otonom kararlar için riskleri kabul ediyor musunuz?'));
640
- console.log(c('dim', '(Kabul ederseniz, yazma işlemlerinde sürekli onay sormayacaktır.)\n'));
641
-
642
- console.log(this.menuItem('E', 'Evet, kabul ediyorum', 'Otonom mod'));
643
- console.log(this.menuItem('H', 'Hayır, her işlemde sor', 'Güvenli mod'));
644
- console.log('');
645
-
646
- const choice = await this.prompt(c('brightYellow', '❯ Seçiminiz (E/H)'));
647
- if (choice.toLowerCase() === 'e') {
648
- this.envVars.RISK_ACCEPTED = 'true';
649
- console.log(this.successMessage('Risk kabul edildi. Otonom mod aktif.'));
650
- } else {
651
- this.envVars.RISK_ACCEPTED = 'false';
652
- console.log(this.infoMessage('Güvenli mod aktif. Kritik işlemlerde onay istenecektir.'));
653
- }
654
- await sleep(1000);
655
- }
656
-
657
- async step5_Save() {
658
- this.printHeader('AYARLAR KAYDEDİLİYOR', '💾');
659
-
660
- console.log(c('brightWhite', 'Yapılandırma dosyası oluşturuluyor...\n'));
661
-
662
- if (!fs.existsSync(VANTUZ_HOME)) {
663
- fs.mkdirSync(VANTUZ_HOME, { recursive: true });
664
- }
665
-
666
- let envContent = '# Vantuz AI Yapılandırması\n';
667
- envContent += `# Oluşturulma Tarihi: ${new Date().toISOString()}\n\n`;
668
-
669
- for (const [key, value] of Object.entries(this.envVars)) {
670
- if (value) {
671
- envContent += `${key}=${value}\n`;
672
- }
673
- }
674
-
675
- fs.writeFileSync(CONFIG_PATH, envContent);
676
- console.log(this.successMessage(`Dosya kaydedildi: ${CONFIG_PATH}`));
677
- await sleep(500);
678
-
679
- ['logs', 'data', 'cache'].forEach(dir => {
680
- const p = path.join(VANTUZ_HOME, dir);
681
- if (!fs.existsSync(p)) fs.mkdirSync(p, { recursive: true });
682
- });
683
- console.log(this.successMessage('Veri klasörleri oluşturuldu'));
684
- await sleep(1000);
685
- }
686
-
687
- async showSuccess() {
688
- this.clear();
689
- console.log('\n');
690
-
691
- const successBox = `
692
- ${colors.brightGreen}${box.topLeft}${box.horizontal.repeat(63)}${box.topRight}
693
- ${box.vertical}${' '.repeat(17)}KURULUM BAŞARIYLA TAMAMLANDI${' '.repeat(17)}${box.vertical}
694
- ${box.bottomLeft}${box.horizontal.repeat(63)}${box.bottomRight}${colors.reset}
695
- `;
696
-
697
- console.log(successBox);
698
- console.log(c('brightWhite', '\nVantuz AI kullanıma hazırdır! 🎉\n'));
699
-
700
- console.log(c('bold', 'Başlamak için şu komutları kullanabilirsiniz:\n'));
701
- console.log(c('brightCyan', ' vantuz tui') + c('dim', ' - Sohbet arayüzünü başlatır'));
702
- console.log(c('brightCyan', ' vantuz status') + c('dim', ' - Sistem durumunu gösterir'));
703
- console.log(c('brightCyan', ' vantuz gateway') + c('dim', ' - Gateway durumunu gösterir'));
704
- console.log(c('brightCyan', ' vantuz doctor') + c('dim', ' - Sistem sağlık kontrolü'));
705
- console.log('\n');
706
-
707
- await this.prompt(c('dim', '▶ Çıkmak için Enter\'a basın...'));
708
- }
709
-
710
- async promptWithRetry(question, defaultValue = '', allowEmpty = false) {
711
- while (true) {
712
- const answer = await this.prompt(question, defaultValue);
713
- if (answer) return answer;
714
- if (allowEmpty) return '';
715
-
716
- console.log(this.warningMessage('Boş giriş algılandı. Lütfen değeri girin (veya iptal için "iptal" yazın)'));
717
- const check = await this.prompt('Tekrar denensin mi? (E/h): ');
718
- if (check.toLowerCase() === 'h' || check.toLowerCase() === 'iptal') return '';
719
- await sleep(200);
720
- }
721
- }
722
-
723
- prompt(question, defaultValue = '') {
724
- const displayQuestion = defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;
725
- return new Promise((resolve) => {
726
- this.rl.question(displayQuestion, (answer) => {
727
- resolve(answer.trim() || defaultValue);
728
- });
729
- });
730
- }
731
- }
732
-
733
- export { Configurator };
1
+
2
+
3
+ /**
4
+ * VANTUZ - Profesyonel Kurulum Sihirbazı
5
+ * v3.2.7 - Gateway Entegrasyonlu
6
+ */
7
+
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import os from 'os';
11
+ import readline from 'readline';
12
+ import { fileURLToPath, pathToFileURL } from 'url';
13
+ import { PROVIDER_CONFIG } from './core/ai-provider.js'; // Import PROVIDER_CONFIG
14
+
15
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
16
+ const VANTUZ_HOME = path.join(os.homedir(), '.vantuz');
17
+ const CONFIG_PATH = path.join(VANTUZ_HOME, '.env');
18
+
19
+ // Enhanced Colors with background support
20
+ const colors = {
21
+ reset: '\x1b[0m',
22
+ bold: '\x1b[1m',
23
+ dim: '\x1b[2m',
24
+ italic: '\x1b[3m',
25
+ underscore: '\x1b[4m',
26
+
27
+ // Foreground colors
28
+ black: '\x1b[30m',
29
+ red: '\x1b[31m',
30
+ green: '\x1b[32m',
31
+ yellow: '\x1b[33m',
32
+ blue: '\x1b[34m',
33
+ magenta: '\x1b[35m',
34
+ cyan: '\x1b[36m',
35
+ white: '\x1b[37m',
36
+
37
+ // Bright foreground colors
38
+ brightBlack: '\x1b[90m',
39
+ brightRed: '\x1b[91m',
40
+ brightGreen: '\x1b[92m',
41
+ brightYellow: '\x1b[93m',
42
+ brightBlue: '\x1b[94m',
43
+ brightMagenta: '\x1b[95m',
44
+ brightCyan: '\x1b[96m',
45
+ brightWhite: '\x1b[97m',
46
+
47
+ // Background colors
48
+ bgBlack: '\x1b[40m',
49
+ bgRed: '\x1b[41m',
50
+ bgGreen: '\x1b[42m',
51
+ bgYellow: '\x1b[43m',
52
+ bgBlue: '\x1b[44m',
53
+ bgMagenta: '\x1b[45m',
54
+ bgCyan: '\x1b[46m',
55
+ bgWhite: '\x1b[47m'
56
+ };
57
+
58
+ const c = (color, text) => `${colors[color]}${text}${colors.reset}`;
59
+ const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
60
+
61
+ // Enhanced box drawing characters
62
+ const box = {
63
+ topLeft: '╔',
64
+ topRight: '╗',
65
+ bottomLeft: '╚',
66
+ bottomRight: '╝',
67
+ horizontal: '═',
68
+ vertical: '║',
69
+ leftT: '╠',
70
+ rightT: '╣',
71
+ topT: '╦',
72
+ bottomT: '╩',
73
+ cross: '╬'
74
+ };
75
+
76
+ const LOGO = `
77
+ ${colors.cyan}${colors.bold}
78
+ ╦ ╦╔═╗╔╗╔╔╦╗╦ ╦╔═╗ ╔═╗╦
79
+ ╚╗╔╝╠═╣║║║ ║ ║ ║╔═╝ ╠═╣║
80
+ ╚╝ ╩ ╩╝╚╝ ╩ ╚═╝╚═╝ ╩ ╩╩
81
+ ${colors.reset}
82
+ ${colors.brightCyan} Enterprise E-Ticaret Yönetimi${colors.reset}
83
+ `;
84
+
85
+ const createBox = (title, content, width = 65) => {
86
+ const lines = content.split('\n');
87
+ let result = '';
88
+
89
+ // Top border with title
90
+ result += c('brightCyan', box.topLeft + box.horizontal.repeat(3));
91
+ result += c('bold', ` ${title} `);
92
+ result += c('brightCyan', box.horizontal.repeat(width - title.length - 5) + box.topRight) + '\n';
93
+
94
+ // Content
95
+ lines.forEach(line => {
96
+ const padding = ' '.repeat(Math.max(0, width - line.length - 2));
97
+ result += c('brightCyan', box.vertical) + ' ' + line + padding + ' ' + c('brightCyan', box.vertical) + '\n';
98
+ });
99
+
100
+ // Bottom border
101
+ result += c('brightCyan', box.bottomLeft + box.horizontal.repeat(width) + box.bottomRight) + '\n';
102
+
103
+ return result;
104
+ };
105
+
106
+ const WELCOME_BOX = createBox('HOŞ GELDİNİZ', `
107
+ Bu sihirbaz kurulumu tamamlamanıza yardımcı olacak:
108
+
109
+ ${c('brightGreen', '✓')} AI Servis Seçimi
110
+ ${c('brightGreen', '✓')} Pazaryeri Bağlantıları
111
+ ${c('brightGreen', '✓')} İletişim Kanalları
112
+ ${c('brightGreen', '✓')} Gateway Yapılandırması
113
+ `);
114
+
115
+ class Configurator {
116
+ constructor() {
117
+ this.envVars = Configurator.loadEnvFile();
118
+ this.step = 0;
119
+ this.rl = readline.createInterface({
120
+ input: process.stdin,
121
+ output: process.stdout,
122
+ crlfDelay: Infinity
123
+ });
124
+ this.platforms = []; // Initialize platforms array
125
+ }
126
+
127
+ async _loadPlatformMetadata() {
128
+ const platformFiles = await fs.promises.readdir(path.join(__dirname, 'platforms'));
129
+ const dynamicPlatforms = [];
130
+
131
+ for (const file of platformFiles) {
132
+ if (file.endsWith('.js') && !file.startsWith('_')) { // Exclude helper files
133
+ const platformPath = path.join(__dirname, 'platforms', file);
134
+ try {
135
+ // Dynamic import for ES Modules
136
+ const platformModule = await import(pathToFileURL(platformPath).href);
137
+ // Check if module.exports is present (CommonJS) or default export (ESM)
138
+ const platform = platformModule.default || platformModule;
139
+
140
+ if (platform.name && platform.requiredFields) {
141
+ dynamicPlatforms.push({
142
+ id: file.replace('.js', ''),
143
+ name: platform.name,
144
+ icon: platform.icon || '🛒', // Default icon if not specified
145
+ description: platform.description || '',
146
+ requiredFields: platform.requiredFields
147
+ });
148
+ }
149
+ } catch (error) {
150
+ console.warn(this.warningMessage(`Platform dosyasını yüklerken hata oluştu: ${file} - ${error.message}`));
151
+ }
152
+ }
153
+ }
154
+ // Sort platforms alphabetically by name
155
+ this.platforms = dynamicPlatforms.sort((a, b) => a.name.localeCompare(b.name));
156
+ }
157
+
158
+ static loadEnvFile() {
159
+ const env = {};
160
+ try {
161
+ if (fs.existsSync(CONFIG_PATH)) {
162
+ const content = fs.readFileSync(CONFIG_PATH, 'utf-8');
163
+ content.split('\n').forEach(line => {
164
+ const match = line.match(/^([^=]+)=(.*)$/);
165
+ if (match) env[match[1].trim()] = match[2].trim();
166
+ });
167
+ }
168
+ } catch (e) {
169
+ console.error(c('red', `✗ Config yükleme hatası: ${e.message}`));
170
+ }
171
+ return env;
172
+ }
173
+
174
+ async step_EIAConfig() {
175
+ this.printHeader('E-TİCARET YÖNETİM AJANSI (EIA) YAPILANDIRMASI', '📊');
176
+
177
+ console.log(c('brightWhite', 'EIA\'nın e-ticaret operasyonlarınızı optimize etmesi için kritik bilgiler sağlayın.\n'));
178
+ console.log(this.infoMessage('Bu bilgiler, EIA\'nın pazar analizi ve stratejik kararlarında kullanılacaktır.'));
179
+
180
+ await sleep(200);
181
+
182
+ const currentCompetitorUrls = this.envVars.EIA_COMPETITOR_URLS || '';
183
+ console.log(this.createInputBox('Rakip Ürün URL\'leri', 'Virgülle ayırarak birden fazla rakip ürün veya kategori URL\'si girebilirsiniz. (Örn: https://rakip.com/urun1, https://rakip.com/kategori)'));
184
+ const competitorUrls = await this.prompt('', currentCompetitorUrls);
185
+
186
+ // Basic validation for URLs
187
+ const urls = competitorUrls.split(',').map(url => url.trim()).filter(url => url !== '');
188
+ const invalidUrls = urls.filter(url => url && (!url.startsWith('http://') && !url.startsWith('https://')));
189
+
190
+ if (competitorUrls && invalidUrls.length === 0) {
191
+ this.envVars.EIA_COMPETITOR_URLS = competitorUrls.trim();
192
+ console.log(this.successMessage('Rakip URL\'leri kaydedildi/güncellendi. EIA, bu kaynakları izleyecektir.'));
193
+ } else if (competitorUrls && invalidUrls.length > 0) {
194
+ console.log(this.errorMessage(`Geçersiz URL(ler) tespit edildi: ${invalidUrls.join(', ')}. Lütfen geçerli URL'ler girin.`));
195
+ // Do not save invalid URLs, keep previous if any
196
+ if (currentCompetitorUrls) { // If there were previous valid URLs, keep them.
197
+ this.envVars.EIA_COMPETITOR_URLS = currentCompetitorUrls;
198
+ } else { // If there were no previous valid URLs, clear it.
199
+ delete this.envVars.EIA_COMPETITOR_URLS;
200
+ }
201
+ await sleep(2000); // Give user time to read error
202
+ }
203
+ else { // If competitorUrls is empty
204
+ if (this.envVars.EIA_COMPETITOR_URLS) {
205
+ delete this.envVars.EIA_COMPETITOR_URLS;
206
+ console.log(this.infoMessage('Rakip URL\'leri temizlendi. EIA, rakip analizi yapmayacaktır.'));
207
+ } else {
208
+ console.log(this.infoMessage('Rakip URL\'leri girilmedi. EIA, rakip analizi yapmayacaktır.'));
209
+ }
210
+ }
211
+
212
+ const currentProfitMargin = this.envVars.EIA_TARGET_PROFIT_MARGIN ? String(this.envVars.EIA_TARGET_PROFIT_MARGIN) : '15';
213
+ console.log(this.createInputBox('Hedef Kar Marjı (%)', 'Ürünleriniz için ulaşmak istediğiniz ortalama kar marjı hedefi. (Örnek: 15)'));
214
+ const profitMargin = await this.prompt('', currentProfitMargin);
215
+
216
+ if (profitMargin && !isNaN(parseFloat(profitMargin)) && parseFloat(profitMargin) >= 0) {
217
+ this.envVars.EIA_TARGET_PROFIT_MARGIN = parseFloat(profitMargin);
218
+ console.log(this.successMessage('Hedef Kar Marjı kaydedildi/güncellendi. EIA, fiyatlandırma önerilerinde bu marjı dikkate alacaktır.'));
219
+ } else {
220
+ if (this.envVars.EIA_TARGET_PROFIT_MARGIN) {
221
+ delete this.envVars.EIA_TARGET_PROFIT_MARGIN;
222
+ console.log(this.infoMessage('Hedef Kar Marjı temizlendi. EIA, varsayılan bir kar marjı kullanabilir.'));
223
+ } else {
224
+ this.envVars.EIA_TARGET_PROFIT_MARGIN = 15; // Default if invalid and no previous value
225
+ console.log(this.infoMessage('Geçersiz kar marjı girildi, varsayılan %15 kullanılacaktır.'));
226
+ }
227
+ }
228
+ await sleep(1000);
229
+ }
230
+
231
+ clear() {
232
+ console.clear();
233
+ }
234
+
235
+ async showLogo() {
236
+ this.clear();
237
+ console.log(LOGO);
238
+ await sleep(500);
239
+ }
240
+
241
+ async runFullOnboarding() {
242
+ try {
243
+ await this.showLogo();
244
+ await this.showWelcome();
245
+ console.log(c('brightGreen', '⚡ Geliştirici Modu: Lisans kontrolü atlandı.\n'));
246
+ await this._loadPlatformMetadata(); // Load platform data
247
+ await this.step1_AIProvider();
248
+ await this.step2_Platforms();
249
+ await this.step3_Channels();
250
+ await this.step4_Gateway();
251
+ await this.step_EIAConfig();
252
+ await this.step_RiskAcceptance(); // Add risk acceptance step
253
+ await this.step5_Save();
254
+ await this.showSuccess();
255
+ } catch (error) {
256
+ console.error('\n' + this.errorMessage(`Beklenmeyen Hata: ${error.message}`));
257
+ } finally {
258
+ this.close();
259
+ }
260
+ }
261
+
262
+ async run() {
263
+ try {
264
+ await this.showLogo();
265
+ await this._loadPlatformMetadata(); // Load platform data
266
+
267
+ while (true) {
268
+ this.printHeader('VANTUZ YAPILANDIRMA MENÜSÜ', '⚙️');
269
+
270
+ console.log(c('brightWhite', 'Lütfen yapılandırmak istediğiniz alanı seçin:\n'));
271
+
272
+ console.log(this.menuItem('1', '🤖 Yapay Zeka Servisi', 'AI Provider'));
273
+ console.log(this.menuItem('2', '🛒 Pazaryeri Entegrasyonları', 'Platforms'));
274
+ console.log(this.menuItem('3', '💬 İletişim Kanalları', 'Channels'));
275
+ console.log(this.menuItem('4', '🌐 Vantuz Gateway', 'Gateway Configuration'));
276
+ console.log(this.menuItem('5', '📊 E-Ticaret Yönetim Ajansı', 'EIA'));
277
+ console.log('');
278
+ console.log(this.menuItem('A', '🚀 Tümünü Yapılandır', 'Full Onboarding', 'dim'));
279
+ console.log(this.menuItem('S', '💾 Kaydet ve Çık', 'Save & Exit', 'dim'));
280
+ console.log(this.menuItem('İ', '❌ İptal Et', 'Cancel without saving', 'dim'));
281
+ console.log('');
282
+
283
+ const choice = await this.prompt(c('brightYellow', '❯ Seçiminiz (1-5, A, S, İ)'));
284
+
285
+ switch (choice.toLowerCase()) {
286
+ case '1': await this.step1_AIProvider(); break;
287
+ case '2': await this.step2_Platforms(); break;
288
+ case '3': await this.step3_Channels(); break;
289
+ case '4': await this.step4_Gateway(); break;
290
+ case '5': await this.step_EIAConfig(); break;
291
+ case 'a': await this.runFullOnboarding(); return;
292
+ case 's':
293
+ await this.step5_Save();
294
+ await this.showSuccess();
295
+ return;
296
+ case 'i':
297
+ case 'İ':
298
+ console.log(this.warningMessage('Yapılandırma iptal edildi. Değişiklikler kaydedilmedi.'));
299
+ return;
300
+ default:
301
+ console.log(this.errorMessage('Geçersiz seçim. Lütfen tekrar deneyin.'));
302
+ await sleep(1000);
303
+ }
304
+ }
305
+ } catch (error) {
306
+ console.error('\n' + this.errorMessage(`Beklenmeyen Hata: ${error.message}`));
307
+ } finally {
308
+ this.close();
309
+ }
310
+ }
311
+
312
+ close() {
313
+ if (this.rl) {
314
+ this.rl.close();
315
+ this.rl = null;
316
+ }
317
+ }
318
+
319
+ printHeader(title, icon = '') {
320
+ this.clear();
321
+ console.log(LOGO);
322
+ console.log('');
323
+ const fullTitle = icon ? `${icon} ${title}` : title;
324
+ console.log(c('bold', c('brightWhite', fullTitle)));
325
+ console.log(c('brightCyan', '─'.repeat(65)));
326
+ console.log('');
327
+ }
328
+
329
+ async showWelcome() {
330
+ console.log(WELCOME_BOX);
331
+ await this.prompt(c('dim', '▶ Devam etmek için Enter\'a basın...'));
332
+ }
333
+
334
+ menuItem(key, title, subtitle = '', style = 'normal') {
335
+ const keyStyle = style === 'dim' ? 'dim' : 'brightYellow';
336
+ const titleStyle = style === 'dim' ? 'dim' : 'brightWhite';
337
+ const subtitleStyle = 'dim';
338
+
339
+ let line = ` ${c(keyStyle, c('bold', key))}. ${c(titleStyle, title)}`;
340
+ if (subtitle) {
341
+ line += ` ${c(subtitleStyle, `(${subtitle})`)}`;
342
+ }
343
+ return line;
344
+ }
345
+
346
+ createInputBox(label, hint = '') {
347
+ let output = '\n' + c('brightCyan', '┌─ ') + c('bold', label);
348
+ if (hint) {
349
+ output += ' ' + c('dim', `(${hint})`);
350
+ }
351
+ output += '\n' + c('brightCyan', '│ ');
352
+ return output;
353
+ }
354
+
355
+ successMessage(text) {
356
+ return '\n' + c('brightGreen', '✓ ') + c('green', text) + '\n';
357
+ }
358
+
359
+ errorMessage(text) {
360
+ return c('brightRed', '✗ ') + c('red', text);
361
+ }
362
+
363
+ warningMessage(text) {
364
+ return '\n' + c('brightYellow', '⚠ ') + c('yellow', text) + '\n';
365
+ }
366
+
367
+ infoMessage(text) {
368
+ return '\n' + c('brightBlue', 'ℹ ') + c('blue', text) + '\n';
369
+ }
370
+
371
+ // ADIM 1: AI PROVIDER
372
+ async step1_AIProvider() {
373
+ this.printHeader('YAPAY ZEKA SERVİSİ', '🤖');
374
+
375
+ console.log(c('brightWhite', 'Kullanılacak AI modelini seçin:\n'));
376
+
377
+ // Dynamically generate menu items from PROVIDER_CONFIG
378
+ const providerKeys = Object.keys(PROVIDER_CONFIG);
379
+ const providerOptions = providerKeys.map((key, index) => {
380
+ const providerInfo = PROVIDER_CONFIG[key];
381
+ const label = providerInfo.config_label || key.charAt(0).toUpperCase() + key.slice(1);
382
+ const description = providerInfo.config_description || '';
383
+ const icon = providerInfo.config_icon || '';
384
+ return {
385
+ choice: String(index + 1),
386
+ label: `${icon} ${label}`,
387
+ description: description,
388
+ envKey: providerInfo.envKey, // Store the actual env key
389
+ key: key // Store the provider key (e.g., 'gemini', 'groq')
390
+ };
391
+ });
392
+
393
+ providerOptions.forEach(option => {
394
+ console.log(this.menuItem(option.choice, option.label, option.description));
395
+ });
396
+ console.log(this.menuItem('S', 'Atla', 'Daha sonra ayarla', 'dim'));
397
+ console.log('');
398
+
399
+ await sleep(200);
400
+
401
+ let currentAIChoice = '';
402
+ for (const option of providerOptions) {
403
+ if (this.envVars[option.envKey]) {
404
+ currentAIChoice = option.choice;
405
+ break;
406
+ }
407
+ }
408
+ if (!currentAIChoice && this.envVars.GEMINI_API_KEY) { // Fallback to Gemini if no other is set but Gemini is.
409
+ currentAIChoice = providerOptions.find(opt => opt.envKey === 'GEMINI_API_KEY')?.choice || '';
410
+ }
411
+ if (!currentAIChoice) currentAIChoice = '1'; // Default to first option if nothing is set
412
+
413
+ const choice = await this.prompt(c('brightYellow', '❯ Seçiminiz (1-' + providerOptions.length + ' veya S)'), currentAIChoice);
414
+
415
+ if (choice.toLowerCase() === 's') {
416
+ console.log(this.warningMessage('AI yapılandırması geçildi'));
417
+ await sleep(1000);
418
+ return;
419
+ }
420
+
421
+ const selectedOption = providerOptions.find(option => option.choice === choice);
422
+
423
+ if (!selectedOption) {
424
+ console.log(this.errorMessage('Geçersiz seçim. Lütfen tekrar deneyin.'));
425
+ await sleep(1000);
426
+ return;
427
+ }
428
+
429
+ console.log(this.successMessage(`${selectedOption.label.trim()} seçildi`));
430
+
431
+ const currentKey = this.envVars[selectedOption.envKey] || '';
432
+ console.log(this.createInputBox(`${selectedOption.label.trim()} API Key`, 'Mevcut değeri değiştirmek için yeni değer girin'));
433
+ const key = await this.prompt('', currentKey);
434
+
435
+ if (key && key.trim()) {
436
+ this.envVars[selectedOption.envKey] = key.trim();
437
+ this.envVars.AI_PROVIDER = selectedOption.key; // Save the provider key (e.g., 'groq')
438
+
439
+ // Clear other AI keys if one is selected
440
+ providerOptions.forEach(option => {
441
+ if (option.envKey !== selectedOption.envKey && this.envVars[option.envKey]) {
442
+ delete this.envVars[option.envKey];
443
+ }
444
+ });
445
+ console.log(this.successMessage('API anahtarı ve sağlayıcı seçimi kaydedildi'));
446
+ } else {
447
+ if (this.envVars[selectedOption.envKey]) {
448
+ delete this.envVars[selectedOption.envKey];
449
+ console.log(this.infoMessage('API anahtarı temizlendi'));
450
+ } else {
451
+ console.log(this.infoMessage('API anahtarı girilmedi, daha sonra ekleyebilirsiniz'));
452
+ }
453
+ }
454
+ await sleep(1000);
455
+ }
456
+
457
+ // ADIM 2: PAZARYERLERİ
458
+ async step2_Platforms() {
459
+ this.printHeader('PAZARYERİ ENTEGRASYONLARI', '🛒');
460
+
461
+ console.log(c('brightWhite', 'Hangi pazaryerini yapılandırmak istersiniz?\n'));
462
+
463
+ // Dynamically generate menu items from this.platforms
464
+ this.platforms.forEach((platform, index) => {
465
+ console.log(this.menuItem(String(index + 1), `${platform.icon} ${platform.name}`, platform.description));
466
+ });
467
+ console.log(this.menuItem('S', 'Atla', 'Tümünü geç', 'dim'));
468
+ console.log('');
469
+
470
+ await sleep(200);
471
+ const choice = await this.prompt(c('brightYellow', '❯ Seçiminiz (1-' + this.platforms.length + ' veya S)'));
472
+
473
+ if (choice.toLowerCase() === 's') {
474
+ console.log(this.warningMessage('Pazaryeri yapılandırması geçildi'));
475
+ return;
476
+ }
477
+
478
+ const selectedPlatform = this.platforms[parseInt(choice) - 1];
479
+
480
+ if (!selectedPlatform) {
481
+ console.log(this.errorMessage('Geçersiz seçim. Lütfen tekrar deneyin.'));
482
+ await sleep(1000);
483
+ return;
484
+ }
485
+
486
+ console.log(this.successMessage(`${selectedPlatform.icon} ${selectedPlatform.name} seçildi`));
487
+ console.log(c('dim', 'Mevcut değerleri değiştirmek için yeni değer girin veya boş bırakın\n'));
488
+
489
+ let allFieldsProvided = true;
490
+ for (const field of selectedPlatform.requiredFields) {
491
+ const currentVal = this.envVars[field.env] || '';
492
+ console.log(this.createInputBox(field.label));
493
+ const value = await this.prompt('', currentVal);
494
+
495
+ if (value && value.trim()) {
496
+ this.envVars[field.env] = value.trim();
497
+ } else {
498
+ // If a required field is left empty, consider it not fully configured
499
+ allFieldsProvided = false;
500
+ delete this.envVars[field.env]; // Clear it if left empty
501
+ }
502
+ }
503
+
504
+ if (allFieldsProvided) {
505
+ console.log(this.successMessage(`${selectedPlatform.name} bilgileri alındı/güncellendi`));
506
+ // Clear keys for other platforms to ensure only one platform's config is active if not multiple
507
+ // This logic might need refinement if multiple platforms can be configured simultaneously.
508
+ // For now, assuming mutually exclusive configuration.
509
+ this.platforms.forEach(platform => {
510
+ if (platform.id !== selectedPlatform.id) {
511
+ platform.requiredFields.forEach(field => {
512
+ if (this.envVars[field.env]) {
513
+ delete this.envVars[field.env];
514
+ }
515
+ });
516
+ }
517
+ });
518
+ } else {
519
+ console.log(this.infoMessage(`${selectedPlatform.name} bilgileri eksik, kaydedilmedi/temizlenmedi`));
520
+ }
521
+ await sleep(1000);
522
+ }
523
+
524
+ // ADIM 3: KANALLAR
525
+ async step3_Channels() {
526
+ this.printHeader('İLETİŞİM KANALLARI', '💬');
527
+
528
+ console.log(c('brightWhite', 'Hangi iletişim kanalını yapılandırmak istersiniz?\n'));
529
+
530
+ console.log(this.menuItem('1', 'Telegram Bot', 'Anlık bildirimler ve sohbet için'));
531
+ console.log(this.menuItem('2', 'WhatsApp', 'Gateway üzerinden yönetilir'));
532
+ console.log(this.menuItem('S', 'Atla', 'Daha sonra ayarla', 'dim'));
533
+ console.log('');
534
+
535
+ await sleep(200);
536
+ const choice = await this.prompt(c('brightYellow', '❯ Seçiminiz (1-2 veya S)'));
537
+
538
+ if (choice.toLowerCase() === 's') {
539
+ console.log(this.warningMessage('İletişim kanalları yapılandırması geçildi'));
540
+ await sleep(1000);
541
+ return;
542
+ }
543
+
544
+ if (choice === '1') { // Configure Telegram
545
+ console.log('\n' + c('bold', 'Telegram Bot Yapılandırması'));
546
+ console.log(c('dim', 'Mevcut değeri değiştirmek için yeni değer girin veya boş bırakın\n'));
547
+
548
+ const currentTelegramToken = this.envVars.TELEGRAM_BOT_TOKEN || '';
549
+ console.log(this.createInputBox('Telegram Bot Token', 'BotFather\'dan alınan token'));
550
+ const token = await this.prompt('', currentTelegramToken);
551
+
552
+ if (token && token.trim()) {
553
+ this.envVars.TELEGRAM_BOT_TOKEN = token.trim();
554
+ console.log(this.successMessage('Telegram token alındı/güncellendi'));
555
+ } else {
556
+ delete this.envVars.TELEGRAM_BOT_TOKEN;
557
+ console.log(this.infoMessage('Telegram token temizlendi'));
558
+ }
559
+ await sleep(1000);
560
+ } else if (choice === '2') { // Information about WhatsApp
561
+ this.printHeader('WhatsApp Kurulum Bilgisi', '💬');
562
+ console.log(this.infoMessage('WhatsApp entegrasyonu Vantuz Gateway üzerinden sağlanır.'));
563
+ console.log(c('brightWhite', 'Gateway\'inizi yapılandırdıktan ve başlattıktan sonra, Gateway arayüzünden WhatsApp kanalını etkinleştirebilirsiniz.\n'));
564
+ console.log(c('dim', ' Gateway durumunu kontrol etmek için: ') + c('brightCyan', 'vantuz gateway status'));
565
+ console.log(c('dim', ' Gateway\'i başlatmak için: ') + c('brightCyan', 'start.bat') + '\n');
566
+ await this.prompt(c('dim', '▶ Devam etmek için Enter\'a basın...'));
567
+ } else {
568
+ console.log(this.errorMessage('Geçersiz seçim. Lütfen tekrar deneyin.'));
569
+ await sleep(1000);
570
+ return;
571
+ }
572
+ }
573
+
574
+ // ADIM 4: VANTUZ GATEWAY
575
+ async step4_Gateway() {
576
+ this.printHeader('VANTUZ GATEWAY', '🌐');
577
+
578
+ console.log(c('brightWhite', 'Vantuz Gateway, AI ve kanal yönetimini güçlendirir.\n'));
579
+
580
+ const setupChoice = await this.prompt('Gateway durumunu kontrol etmek ve yapılandırmak ister misiniz? (e/H)', 'e');
581
+
582
+ if (setupChoice.toLowerCase() === 'h') {
583
+ console.log(this.warningMessage('Gateway yapılandırması geçildi'));
584
+ await sleep(1000);
585
+ return;
586
+ }
587
+
588
+ // Dynamically import getGateway to avoid circular dependency if not already imported
589
+ const { getGateway } = await import('./core/gateway.js');
590
+ const gateway = await getGateway();
591
+ const info = gateway.getInfo();
592
+
593
+ console.log(c('brightYellow', '\n── Gateway Mevcut Durumu ──'));
594
+ console.log(` URL: ${c('cyan', info.url)}`);
595
+ console.log(` Durum: ${info.connected ? c('brightGreen', '● Bağlı') : c('brightRed', '○ Bağlı Değil')}`);
596
+ console.log(` Token: ${info.hasToken ? c('brightGreen', '✔ Yapılandırılmış') : c('brightRed', '✘ Eksik/Geçersiz')}`);
597
+ console.log(` Config: ${info.configFound ? c('brightGreen', '✔ Bulundu (gateway config)') : c('brightRed', '✘ Bulunamadı (gateway config)')}`);
598
+ if (info.version) console.log(` Sürüm: ${c('dim', info.version)}`);
599
+ console.log('');
600
+
601
+ if (!info.configFound || !info.hasToken || !info.connected) {
602
+ console.log(this.warningMessage('Gateway tam olarak yapılandırılmamış veya çalışmıyor.'));
603
+
604
+ const startChoice = await this.prompt('Sistemi otomatik başlatmak ister misiniz? (E/h)', 'E');
605
+ if (startChoice.toLowerCase() !== 'h') {
606
+ console.log(c('dim', 'Sistem başlatılıyor (Gateway + Server)...'));
607
+ const result = await gateway.startFullStack();
608
+
609
+ if (result.success) {
610
+ console.log(this.successMessage('Başlatma komutları gönderildi.'));
611
+ console.log(c('dim', 'Servislerin açılması 10-15 saniye sürebilir.'));
612
+ await sleep(5000); // Wait a bit before re-checking
613
+
614
+ // Re-check status
615
+ const newInfo = (await gateway.health()).success;
616
+ if (newInfo) console.log(this.successMessage('Gateway bağlantısı sağlandı!'));
617
+ else console.log(c('yellow', 'Gateway henüz hazır değil, arka planda açılıyor...'));
618
+ } else {
619
+ console.log(this.errorMessage('Başlatma sırasında hata oluştu.'));
620
+ if (result.gateway?.error) console.log(c('red', `Gateway Hatası: ${result.gateway.error}`));
621
+ if (result.server?.error) console.log(c('red', `Server Hatası: ${result.server.error}`));
622
+ }
623
+ } else {
624
+ console.log(c('dim', 'Manuel başlatmak için `start.bat` kullanabilirsiniz.'));
625
+ }
626
+ } else {
627
+ console.log(this.successMessage('Gateway başarılı bir şekilde yapılandırılmış ve çalışıyor.'));
628
+ console.log(c('dim', 'Durumu kontrol etmek için: vantuz gateway status'));
629
+ }
630
+ await this.prompt(c('dim', '▶ Devam etmek için Enter\'a basın...'));
631
+ }
632
+
633
+ // KAYDET
634
+ async step_RiskAcceptance() {
635
+ if (this.envVars.RISK_ACCEPTED === 'true') return;
636
+
637
+ this.printHeader('RİSK KABULÜ', '⚠️');
638
+ console.log(c('brightWhite', 'Vantuz AI, sizin adınıza fiyat ve stok güncellemeleri yapabilir.\n'));
639
+ console.log(c('yellow', 'Bazı işlemler geri alınamaz olabilir. Otonom kararlar için riskleri kabul ediyor musunuz?'));
640
+ console.log(c('dim', '(Kabul ederseniz, yazma işlemlerinde sürekli onay sormayacaktır.)\n'));
641
+
642
+ console.log(this.menuItem('E', 'Evet, kabul ediyorum', 'Otonom mod'));
643
+ console.log(this.menuItem('H', 'Hayır, her işlemde sor', 'Güvenli mod'));
644
+ console.log('');
645
+
646
+ const choice = await this.prompt(c('brightYellow', '❯ Seçiminiz (E/H)'));
647
+ if (choice.toLowerCase() === 'e') {
648
+ this.envVars.RISK_ACCEPTED = 'true';
649
+ console.log(this.successMessage('Risk kabul edildi. Otonom mod aktif.'));
650
+ } else {
651
+ this.envVars.RISK_ACCEPTED = 'false';
652
+ console.log(this.infoMessage('Güvenli mod aktif. Kritik işlemlerde onay istenecektir.'));
653
+ }
654
+ await sleep(1000);
655
+ }
656
+
657
+ async step5_Save() {
658
+ this.printHeader('AYARLAR KAYDEDİLİYOR', '💾');
659
+
660
+ console.log(c('brightWhite', 'Yapılandırma dosyası oluşturuluyor...\n'));
661
+
662
+ if (!fs.existsSync(VANTUZ_HOME)) {
663
+ fs.mkdirSync(VANTUZ_HOME, { recursive: true });
664
+ }
665
+
666
+ let envContent = '# Vantuz AI Yapılandırması\n';
667
+ envContent += `# Oluşturulma Tarihi: ${new Date().toISOString()}\n\n`;
668
+
669
+ for (const [key, value] of Object.entries(this.envVars)) {
670
+ if (value) {
671
+ envContent += `${key}=${value}\n`;
672
+ }
673
+ }
674
+
675
+ fs.writeFileSync(CONFIG_PATH, envContent);
676
+ console.log(this.successMessage(`Dosya kaydedildi: ${CONFIG_PATH}`));
677
+ await sleep(500);
678
+
679
+ ['logs', 'data', 'cache'].forEach(dir => {
680
+ const p = path.join(VANTUZ_HOME, dir);
681
+ if (!fs.existsSync(p)) fs.mkdirSync(p, { recursive: true });
682
+ });
683
+ console.log(this.successMessage('Veri klasörleri oluşturuldu'));
684
+ await sleep(1000);
685
+ }
686
+
687
+ async showSuccess() {
688
+ this.clear();
689
+ console.log('\n');
690
+
691
+ const successBox = `
692
+ ${colors.brightGreen}${box.topLeft}${box.horizontal.repeat(63)}${box.topRight}
693
+ ${box.vertical}${' '.repeat(17)}KURULUM BAŞARIYLA TAMAMLANDI${' '.repeat(17)}${box.vertical}
694
+ ${box.bottomLeft}${box.horizontal.repeat(63)}${box.bottomRight}${colors.reset}
695
+ `;
696
+
697
+ console.log(successBox);
698
+ console.log(c('brightWhite', '\nVantuz AI kullanıma hazırdır! 🎉\n'));
699
+
700
+ console.log(c('bold', 'Başlamak için şu komutları kullanabilirsiniz:\n'));
701
+ console.log(c('brightCyan', ' vantuz tui') + c('dim', ' - Sohbet arayüzünü başlatır'));
702
+ console.log(c('brightCyan', ' vantuz status') + c('dim', ' - Sistem durumunu gösterir'));
703
+ console.log(c('brightCyan', ' vantuz gateway') + c('dim', ' - Gateway durumunu gösterir'));
704
+ console.log(c('brightCyan', ' vantuz doctor') + c('dim', ' - Sistem sağlık kontrolü'));
705
+ console.log('\n');
706
+
707
+ await this.prompt(c('dim', '▶ Çıkmak için Enter\'a basın...'));
708
+ }
709
+
710
+ async promptWithRetry(question, defaultValue = '', allowEmpty = false) {
711
+ while (true) {
712
+ const answer = await this.prompt(question, defaultValue);
713
+ if (answer) return answer;
714
+ if (allowEmpty) return '';
715
+
716
+ console.log(this.warningMessage('Boş giriş algılandı. Lütfen değeri girin (veya iptal için "iptal" yazın)'));
717
+ const check = await this.prompt('Tekrar denensin mi? (E/h): ');
718
+ if (check.toLowerCase() === 'h' || check.toLowerCase() === 'iptal') return '';
719
+ await sleep(200);
720
+ }
721
+ }
722
+
723
+ prompt(question, defaultValue = '') {
724
+ const displayQuestion = defaultValue ? `${question} [${defaultValue}]: ` : `${question}: `;
725
+ return new Promise((resolve) => {
726
+ this.rl.question(displayQuestion, (answer) => {
727
+ resolve(answer.trim() || defaultValue);
728
+ });
729
+ });
730
+ }
731
+ }
732
+
733
+ export { Configurator };