vantuz 3.3.5 → 3.3.6

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/config.js CHANGED
@@ -384,7 +384,8 @@ class Configurator {
384
384
  choice: String(index + 1),
385
385
  label: `${icon} ${label}`,
386
386
  description: description,
387
- envKey: providerInfo.envKey // Store the actual env key
387
+ envKey: providerInfo.envKey, // Store the actual env key
388
+ key: key // Store the provider key (e.g., 'gemini', 'groq')
388
389
  };
389
390
  });
390
391
 
@@ -432,13 +433,15 @@ class Configurator {
432
433
 
433
434
  if (key && key.trim()) {
434
435
  this.envVars[selectedOption.envKey] = key.trim();
436
+ this.envVars.AI_PROVIDER = selectedOption.key; // Save the provider key (e.g., 'groq')
437
+
435
438
  // Clear other AI keys if one is selected
436
439
  providerOptions.forEach(option => {
437
440
  if (option.envKey !== selectedOption.envKey && this.envVars[option.envKey]) {
438
441
  delete this.envVars[option.envKey];
439
442
  }
440
443
  });
441
- console.log(this.successMessage('API anahtarı kaydedildi'));
444
+ console.log(this.successMessage('API anahtarı ve sağlayıcı seçimi kaydedildi'));
442
445
  } else {
443
446
  if (this.envVars[selectedOption.envKey]) {
444
447
  delete this.envVars[selectedOption.envKey];
@@ -595,13 +598,33 @@ class Configurator {
595
598
  console.log('');
596
599
 
597
600
  if (!info.configFound || !info.hasToken || !info.connected) {
598
- console.log(this.warningMessage('Gateway tam olarak yapılandırılmamış veya çalışmıyor gibi görünüyor.'));
599
- console.log(c('brightWhite', 'Lütfen Gateway\'i başlatmak ve tam olarak yapılandırmak için `start.bat` dosyasını çalıştırın.\n'));
600
- console.log(c('dim', ' `start.bat` komutu gerekli dosyaları oluşturacak ve Gateway\'i başlatacaktır.'));
601
- console.log(c('dim', ' Daha sonra durumu tekrar kontrol etmek için: ') + c('brightCyan', 'vantuz gateway status'));
601
+ console.log(this.warningMessage('Gateway tam olarak yapılandırılmamış veya çalışmıyor.'));
602
+
603
+ const startChoice = await this.prompt('Sistemi otomatik başlatmak ister misiniz? (E/h)', 'E');
604
+ if (startChoice.toLowerCase() !== 'h') {
605
+ console.log(c('dim', 'Sistem başlatılıyor (Gateway + Server)...'));
606
+ const result = await gateway.startFullStack();
607
+
608
+ if (result.success) {
609
+ console.log(this.successMessage('Başlatma komutları gönderildi.'));
610
+ console.log(c('dim', 'Servislerin açılması 10-15 saniye sürebilir.'));
611
+ await sleep(5000); // Wait a bit before re-checking
612
+
613
+ // Re-check status
614
+ const newInfo = (await gateway.health()).success;
615
+ if (newInfo) console.log(this.successMessage('Gateway bağlantısı sağlandı!'));
616
+ else console.log(c('yellow', 'Gateway henüz hazır değil, arka planda açılıyor...'));
617
+ } else {
618
+ console.log(this.errorMessage('Başlatma sırasında hata oluştu.'));
619
+ if (result.gateway?.error) console.log(c('red', `Gateway Hatası: ${result.gateway.error}`));
620
+ if (result.server?.error) console.log(c('red', `Server Hatası: ${result.server.error}`));
621
+ }
622
+ } else {
623
+ console.log(c('dim', 'Manuel başlatmak için `start.bat` kullanabilirsiniz.'));
624
+ }
602
625
  } else {
603
- console.log(this.successMessage('Gateway başarılı bir şekilde yapılandırılmış ve çalışıyor görünüyor.'));
604
- console.log(c('brightWhite', 'Durumunu kontrol etmek için dilediğiniz zaman `vantuz gateway status` komutunu kullanabilirsiniz.\n'));
626
+ console.log(this.successMessage('Gateway başarılı bir şekilde yapılandırılmış ve çalışıyor.'));
627
+ console.log(c('dim', 'Durumu kontrol etmek için: vantuz gateway status'));
605
628
  }
606
629
  await this.prompt(c('dim', '▶ Devam etmek için Enter\'a basın...'));
607
630
  }
package/core/engine.js CHANGED
@@ -16,11 +16,11 @@ import platformHub from '../plugins/vantuz/platforms/index.js';
16
16
  // AI Provider & Gateway
17
17
  import { getChannelManager } from './channels.js';
18
18
  import { chat as aiChat, log } from './ai-provider.js';
19
- import { getGateway } from './gateway.js';
20
- import { getEIAMonitor } from './eia-monitor.js'; // New import
21
- import AutomationManager from './automation.js';
22
- import OpenClawBridge from './openclaw-bridge.js';
23
- import { executeTool } from './agent.js';
19
+ import { getGateway } from './gateway.js';
20
+ import { getEIAMonitor } from './eia-monitor.js'; // New import
21
+ import AutomationManager from './automation.js';
22
+ import OpenClawBridge from './openclaw-bridge.js';
23
+ import { executeTool } from './agent.js';
24
24
 
25
25
  // Tools
26
26
  import { repricerTool } from '../plugins/vantuz/tools/repricer.js';
@@ -40,32 +40,25 @@ const PLATFORM_CONFIG_MAP = {
40
40
  envPrefix: 'HEPSIBURADA',
41
41
  keys: ['merchantId', 'username', 'password']
42
42
  },
43
- n11: {
44
- envPrefix: 'N11',
45
- keys: ['apiKey', 'apiSecret']
46
- },
43
+ n11: {
44
+ envPrefix: 'N11',
45
+ keys: ['apiKey', 'apiSecret']
46
+ },
47
47
  amazon: {
48
48
  envPrefix: 'AMAZON',
49
- nested: {
50
- eu: {
51
- keys: ['sellerId', 'clientId', 'refreshToken']
52
- },
53
- us: {
54
- keys: ['sellerId', 'clientId', 'refreshToken']
55
- }
56
- }
49
+ keys: ['sellerId', 'clientId', 'clientSecret', 'refreshToken', 'region']
57
50
  },
58
51
  ciceksepeti: {
59
52
  envPrefix: 'CICEKSEPETI',
60
- keys: ['apiKey', 'apiSecret']
53
+ keys: ['apiKey', 'supplierId']
61
54
  },
62
55
  pttavm: {
63
56
  envPrefix: 'PTTAVM',
64
- keys: ['apiKey', 'apiSecret']
57
+ keys: ['apiKey', 'token', 'shopId']
65
58
  },
66
59
  pazarama: {
67
60
  envPrefix: 'PAZARAMA',
68
- keys: ['apiKey', 'apiSecret']
61
+ keys: ['clientId', 'clientSecret']
69
62
  }
70
63
  };
71
64
 
@@ -82,7 +75,7 @@ const CONFIG_JSON = path.join(VANTUZ_HOME, 'config.json');
82
75
  // ═══════════════════════════════════════════════════════════════════════════
83
76
 
84
77
  export class VantuzEngine {
85
- constructor() {
78
+ constructor() {
86
79
  this.initialized = false;
87
80
  this.config = {};
88
81
  this.env = {};
@@ -93,9 +86,9 @@ export class VantuzEngine {
93
86
  products: [],
94
87
  connectedPlatforms: []
95
88
  };
96
- this.eiaMonitor = null; // New property
97
- this.automation = null;
98
- this.bridge = null;
89
+ this.eiaMonitor = null; // New property
90
+ this.automation = null;
91
+ this.bridge = null;
99
92
 
100
93
  // Tool Registry
101
94
  this.tools = {
@@ -112,29 +105,29 @@ export class VantuzEngine {
112
105
  /**
113
106
  * Engine'i başlat
114
107
  */
115
- async initialize() {
116
- log('INFO', 'Vantuz Engine v3.2 başlatılıyor...');
117
-
118
- // Config ve env yükle
119
- this._loadConfig();
120
- this._loadEnv();
121
-
122
- // Vantuz Gateway bağlantısı
123
- try {
124
- this.gateway = await getGateway();
125
- if (this.gateway.isConnected()) {
126
- log('INFO', 'Vantuz Gateway bağlı', this.gateway.getInfo());
127
- } else if (this._shouldAutoStartGateway()) {
128
- const started = await this.gateway.ensureRunning();
129
- if (started.success) {
130
- log('INFO', 'Vantuz Gateway otomatik başlatıldı', this.gateway.getInfo());
131
- } else {
132
- log('WARN', 'Gateway otomatik başlatılamadı', { error: started.error });
133
- }
134
- }
135
- } catch (e) {
136
- log('WARN', 'Gateway bağlantısı başarısız, direkt mod', { error: e.message });
137
- }
108
+ async initialize() {
109
+ log('INFO', 'Vantuz Engine v3.2 başlatılıyor...');
110
+
111
+ // Config ve env yükle
112
+ this._loadConfig();
113
+ this._loadEnv();
114
+
115
+ // Vantuz Gateway bağlantısı
116
+ try {
117
+ this.gateway = await getGateway();
118
+ if (this.gateway.isConnected()) {
119
+ log('INFO', 'Vantuz Gateway bağlı', this.gateway.getInfo());
120
+ } else if (this._shouldAutoStartGateway()) {
121
+ const started = await this.gateway.ensureRunning();
122
+ if (started.success) {
123
+ log('INFO', 'Vantuz Gateway otomatik başlatıldı', this.gateway.getInfo());
124
+ } else {
125
+ log('WARN', 'Gateway otomatik başlatılamadı', { error: started.error });
126
+ }
127
+ }
128
+ } catch (e) {
129
+ log('WARN', 'Gateway bağlantısı başarısız, direkt mod', { error: e.message });
130
+ }
138
131
 
139
132
  // Channel Manager'ı başlat
140
133
  this.channels = await getChannelManager();
@@ -146,70 +139,70 @@ export class VantuzEngine {
146
139
  await this._buildContext();
147
140
 
148
141
  // Initialize and start EIA Monitor
149
- this.eiaMonitor = getEIAMonitor(this.config, this.env);
150
- await this.eiaMonitor.initMonitoringTasks(); // New line
151
-
152
- // Automation manager
153
- this.automation = new AutomationManager(this);
154
- this.automation.init();
155
-
156
- // Gateway WS bridge (inbound)
157
- if (this._shouldStartBridge()) {
158
- try {
159
- this.bridge = new OpenClawBridge(this, this.gateway);
160
- this.bridge.start();
161
- } catch (e) {
162
- log('WARN', 'Gateway bridge başlatılamadı', { error: e.message });
163
- }
164
- }
165
-
166
- this.initialized = true;
142
+ this.eiaMonitor = getEIAMonitor(this.config, this.env);
143
+ await this.eiaMonitor.initMonitoringTasks(); // New line
144
+
145
+ // Automation manager
146
+ this.automation = new AutomationManager(this);
147
+ this.automation.init();
148
+
149
+ // Gateway WS bridge (inbound)
150
+ if (this._shouldStartBridge()) {
151
+ try {
152
+ this.bridge = new OpenClawBridge(this, this.gateway);
153
+ this.bridge.start();
154
+ } catch (e) {
155
+ log('WARN', 'Gateway bridge başlatılamadı', { error: e.message });
156
+ }
157
+ }
158
+
159
+ this.initialized = true;
167
160
  log('INFO', 'Vantuz Engine hazır', {
168
161
  platforms: this.context.connectedPlatforms.length,
169
162
  gateway: this.gateway?.isConnected() || false
170
163
  });
171
164
 
172
- return this;
173
- }
174
-
175
- /**
176
- * Gelişmiş mesaj işleme (otomasyon + onay)
177
- */
178
- async handleMessage(message, meta = { channel: 'local', from: 'local' }) {
179
- if (!this.initialized) await this.initialize();
180
- if (this.automation) {
181
- const result = await this.automation.handleMessage(message, meta);
182
- if (result?.handled) {
183
- return result.response;
184
- }
185
- }
186
- return await this.chat(message);
187
- }
188
-
189
- /**
190
- * Gateway otomatik başlatılsın mı?
191
- */
192
- _shouldAutoStartGateway() {
193
- const envValue = this.env.VANTUZ_GATEWAY_AUTOSTART;
194
- if (envValue !== undefined) {
195
- return !['0', 'false', 'no'].includes(String(envValue).toLowerCase());
196
- }
197
- if (this.config && this.config.gatewayAutoStart !== undefined) {
198
- return this.config.gatewayAutoStart !== false;
199
- }
200
- return true;
201
- }
202
-
203
- _shouldStartBridge() {
204
- const envValue = this.env.VANTUZ_OPENCLAW_BRIDGE;
205
- if (envValue !== undefined) {
206
- return !['0', 'false', 'no'].includes(String(envValue).toLowerCase());
207
- }
208
- if (this.config && this.config.openclawBridge !== undefined) {
209
- return this.config.openclawBridge !== false;
210
- }
211
- return true;
212
- }
165
+ return this;
166
+ }
167
+
168
+ /**
169
+ * Gelişmiş mesaj işleme (otomasyon + onay)
170
+ */
171
+ async handleMessage(message, meta = { channel: 'local', from: 'local' }) {
172
+ if (!this.initialized) await this.initialize();
173
+ if (this.automation) {
174
+ const result = await this.automation.handleMessage(message, meta);
175
+ if (result?.handled) {
176
+ return result.response;
177
+ }
178
+ }
179
+ return await this.chat(message);
180
+ }
181
+
182
+ /**
183
+ * Gateway otomatik başlatılsın mı?
184
+ */
185
+ _shouldAutoStartGateway() {
186
+ const envValue = this.env.VANTUZ_GATEWAY_AUTOSTART;
187
+ if (envValue !== undefined) {
188
+ return !['0', 'false', 'no'].includes(String(envValue).toLowerCase());
189
+ }
190
+ if (this.config && this.config.gatewayAutoStart !== undefined) {
191
+ return this.config.gatewayAutoStart !== false;
192
+ }
193
+ return true;
194
+ }
195
+
196
+ _shouldStartBridge() {
197
+ const envValue = this.env.VANTUZ_OPENCLAW_BRIDGE;
198
+ if (envValue !== undefined) {
199
+ return !['0', 'false', 'no'].includes(String(envValue).toLowerCase());
200
+ }
201
+ if (this.config && this.config.openclawBridge !== undefined) {
202
+ return this.config.openclawBridge !== false;
203
+ }
204
+ return true;
205
+ }
213
206
 
214
207
  /**
215
208
  * Config dosyasını yükle
@@ -252,60 +245,23 @@ export class VantuzEngine {
252
245
  for (const platformName in PLATFORM_CONFIG_MAP) {
253
246
  const platformMap = PLATFORM_CONFIG_MAP[platformName];
254
247
 
255
- if (platformName === 'amazon') { // Handle Amazon's specific nested structure first
256
- const amazonConfig = {};
257
- let hasAmazonEnv = false;
258
-
259
- // Handle EU configuration
260
- const euConfig = {};
261
- let hasEuEnv = false;
262
- for (const key of PLATFORM_CONFIG_MAP.amazon.nested.eu.keys) {
263
- const envKey = `AMAZON_EU_${key.toUpperCase()}`; // Assuming EU specific env keys
264
- if (this.env[envKey]) {
265
- euConfig[key] = this.env[envKey];
266
- hasEuEnv = true;
248
+ if (platformMap.envPrefix && platformMap.keys) { // Handle all platforms with direct keys
249
+ const config = {};
250
+ let hasRequiredEnv = false;
251
+ for (const key of platformMap.keys) {
252
+ const upper = key.toUpperCase();
253
+ const snake = key.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toUpperCase();
254
+ const envKey = `${platformMap.envPrefix}_${upper}`;
255
+ const altEnvKey = `${platformMap.envPrefix}_${snake}`;
256
+ const value = this.env[envKey] || this.env[altEnvKey];
257
+ if (value) {
258
+ config[key] = value;
259
+ hasRequiredEnv = true;
267
260
  }
268
261
  }
269
- if (hasEuEnv) {
270
- amazonConfig.eu = euConfig;
271
- hasAmazonEnv = true;
272
- }
273
-
274
- // Handle US configuration (add similar logic here if needed)
275
- const usConfig = {};
276
- let hasUsEnv = false;
277
- for (const key of PLATFORM_CONFIG_MAP.amazon.nested.us.keys) {
278
- const envKey = `AMAZON_US_${key.toUpperCase()}`; // Assuming US specific env keys
279
- if (this.env[envKey]) {
280
- usConfig[key] = this.env[envKey];
281
- hasUsEnv = true;
282
- }
283
- }
284
- if (hasUsEnv) {
285
- amazonConfig.us = usConfig;
286
- hasAmazonEnv = true;
287
- }
288
-
289
- if (hasAmazonEnv) {
290
- platformConfig[platformName] = amazonConfig;
262
+ if (hasRequiredEnv) {
263
+ platformConfig[platformName] = config;
291
264
  }
292
- } else if (platformMap.envPrefix && platformMap.keys) { // Handle other platforms with direct keys
293
- const config = {};
294
- let hasRequiredEnv = false;
295
- for (const key of platformMap.keys) {
296
- const upper = key.toUpperCase();
297
- const snake = key.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toUpperCase();
298
- const envKey = `${platformMap.envPrefix}_${upper}`;
299
- const altEnvKey = `${platformMap.envPrefix}_${snake}`;
300
- const value = this.env[envKey] || this.env[altEnvKey];
301
- if (value) {
302
- config[key] = value;
303
- hasRequiredEnv = true;
304
- }
305
- }
306
- if (hasRequiredEnv) {
307
- platformConfig[platformName] = config;
308
- }
309
265
  }
310
266
  }
311
267
 
@@ -324,50 +280,50 @@ export class VantuzEngine {
324
280
  async _buildContext() {
325
281
  this.context.connectedPlatforms = platformHub.getConnected();
326
282
 
327
- for (const platform of this.context.connectedPlatforms) {
328
- try {
329
- const api = platformHub.resolve(platform);
330
- if (api && typeof api.getProducts === 'function') {
331
- const result = await api.getProducts({ page: 0, size: 10 });
332
- if (result?.success) {
333
- const data = result.data;
334
- let products = [];
335
- if (Array.isArray(data?.content)) products = data.content;
336
- else if (Array.isArray(data)) products = data;
337
- else if (Array.isArray(data?.productList?.product)) products = data.productList.product;
338
- if (products.length > 0) {
339
- this.context.products.push(...products.map(p => ({
340
- ...p,
341
- _platform: platform
342
- })));
343
- }
344
- }
345
- }
346
- } catch (e) {
347
- log('ERROR', `${platform} veri çekme hatası`, { error: e.message });
348
- }
349
- }
283
+ for (const platform of this.context.connectedPlatforms) {
284
+ try {
285
+ const api = platformHub.resolve(platform);
286
+ if (api && typeof api.getProducts === 'function') {
287
+ const result = await api.getProducts({ page: 0, size: 10 });
288
+ if (result?.success) {
289
+ const data = result.data;
290
+ let products = [];
291
+ if (Array.isArray(data?.content)) products = data.content;
292
+ else if (Array.isArray(data)) products = data;
293
+ else if (Array.isArray(data?.productList?.product)) products = data.productList.product;
294
+ if (products.length > 0) {
295
+ this.context.products.push(...products.map(p => ({
296
+ ...p,
297
+ _platform: platform
298
+ })));
299
+ }
300
+ }
301
+ }
302
+ } catch (e) {
303
+ log('ERROR', `${platform} veri çekme hatası`, { error: e.message });
304
+ }
305
+ }
350
306
  }
351
307
 
352
308
  /**
353
309
  * AI ile sohbet - Tool destekli
354
310
  */
355
- async chat(message) {
356
- if (!this.initialized) await this.initialize();
357
-
358
- // 1. Basit komut kontrolü (Tool çağırma)
359
- const toolResult = await this._tryExecuteToolFromMessage(message);
360
- if (toolResult) return toolResult;
361
-
362
- // 1.5 Gelişmiş ajan (araç çağrıları)
363
- const agentResult = await this._tryAgent(message);
364
- if (agentResult) return agentResult;
365
-
366
- // 2. Gateway üzerinden AI (Eğer varsa)
367
- if (this.gateway?.isConnected()) {
368
- try {
369
- const gatewayResult = await this.gateway.chat(message, {
370
- systemPrompt: this._buildContextInfo()
311
+ async chat(message) {
312
+ if (!this.initialized) await this.initialize();
313
+
314
+ // 1. Basit komut kontrolü (Tool çağırma)
315
+ const toolResult = await this._tryExecuteToolFromMessage(message);
316
+ if (toolResult) return toolResult;
317
+
318
+ // 1.5 Gelişmiş ajan (araç çağrıları)
319
+ const agentResult = await this._tryAgent(message);
320
+ if (agentResult) return agentResult;
321
+
322
+ // 2. Gateway üzerinden AI (Eğer varsa)
323
+ if (this.gateway?.isConnected()) {
324
+ try {
325
+ const gatewayResult = await this.gateway.chat(message, {
326
+ systemPrompt: this._buildContextInfo()
371
327
  });
372
328
  if (gatewayResult.success) return gatewayResult.response;
373
329
  } catch (e) { }
@@ -376,98 +332,99 @@ export class VantuzEngine {
376
332
  // 3. Direkt API (Fallback)
377
333
  const enrichedConfig = {
378
334
  ...this.config,
335
+ aiProvider: this.env.AI_PROVIDER || this.config.aiProvider || 'gemini',
379
336
  systemContext: this._buildContextInfo()
380
337
  };
381
338
 
382
- return await aiChat(message, enrichedConfig, this.env);
383
- }
384
-
385
- async _tryAgent(message) {
386
- const mode = this.config?.agentMode || this.env.VANTUZ_AGENT_MODE;
387
- if (!mode || mode === 'off') return null;
388
-
389
- const systemPrompt = [
390
- 'Sen Vantuz gelişmiş ajanısın.',
391
- 'Gerekirse aşağıdaki araçlardan birini çağır:',
392
- 'exec, readFile, listDir, httpGet, apiQuery',
393
- 'Sadece JSON döndür.',
394
- 'Şema: { "tool": "exec|readFile|listDir|httpGet|apiQuery", "args": { ... } }',
395
- 'apiQuery args: { "platform": "n11|trendyol|hepsiburada|amazon|ciceksepeti|pazarama|pttavm", "action": "orders|products|stock|categories", "params": { ... } }',
396
- 'Eğer araç gerekmezse: { "final": "cevap" }',
397
- 'Dosya yollarını ve komutları kısa tut.'
398
- ].join('\n');
399
-
400
- const plan = await aiChat(message, {
401
- aiProvider: this.config.aiProvider || 'gemini',
402
- systemContext: systemPrompt
403
- }, this.env);
404
-
405
- const jsonMatch = plan.match(/\{[\s\S]*\}/);
406
- if (!jsonMatch) return null;
407
- let obj;
408
- try { obj = JSON.parse(jsonMatch[0]); } catch { return null; }
409
- if (obj.final) return obj.final;
410
- if (!obj.tool) return null;
411
-
412
- let toolResult;
413
- if (obj.tool === 'apiQuery') {
414
- toolResult = await this._runApiQuery(obj.args || {});
415
- } else {
416
- toolResult = await executeTool(obj.tool, obj.args || {}, this.config);
417
- }
418
- const followup = await aiChat(
419
- `Kullanıcı mesajı: ${message}\nAraç çıktısı:\n${toolResult.output}\nCevap ver.`,
420
- { aiProvider: this.config.aiProvider || 'gemini' },
421
- this.env
422
- );
423
- return followup;
424
- }
425
-
426
- async _runApiQuery(args = {}) {
427
- const platform = (args.platform || '').toLowerCase();
428
- const action = (args.action || '').toLowerCase();
429
- const params = args.params || {};
430
- const api = platformHub.resolve(platform);
431
- if (!api) return { success: false, output: 'Platform bulunamadı.' };
432
-
433
- try {
434
- if (action === 'orders' && api.getOrders) {
435
- const result = await api.getOrders(params);
436
- return { success: true, output: JSON.stringify(result?.data || result || {}, null, 2) };
437
- }
438
- if (action === 'products' && api.getProducts) {
439
- const result = await api.getProducts(params);
440
- return { success: true, output: JSON.stringify(result?.data || result || {}, null, 2) };
441
- }
442
- if (action === 'stock' && api.getProducts) {
443
- const result = await api.getProducts(params);
444
- return { success: true, output: JSON.stringify(result?.data || result || {}, null, 2) };
445
- }
446
- if (action === 'categories' && api.getTopCategories) {
447
- const result = await api.getTopCategories(params);
448
- return { success: true, output: JSON.stringify(result?.data || result || {}, null, 2) };
449
- }
450
- return { success: false, output: 'Bu platform için istenen action desteklenmiyor.' };
451
- } catch (e) {
452
- return { success: false, output: e.message };
453
- }
454
- }
339
+ return await aiChat(message, enrichedConfig, this.env);
340
+ }
341
+
342
+ async _tryAgent(message) {
343
+ const mode = this.config?.agentMode || this.env.VANTUZ_AGENT_MODE;
344
+ if (!mode || mode === 'off') return null;
345
+
346
+ const systemPrompt = [
347
+ 'Sen Vantuz gelişmiş ajanısın.',
348
+ 'Gerekirse aşağıdaki araçlardan birini çağır:',
349
+ 'exec, readFile, listDir, httpGet, apiQuery',
350
+ 'Sadece JSON döndür.',
351
+ 'Şema: { "tool": "exec|readFile|listDir|httpGet|apiQuery", "args": { ... } }',
352
+ 'apiQuery args: { "platform": "n11|trendyol|hepsiburada|amazon|ciceksepeti|pazarama|pttavm", "action": "orders|products|stock|categories", "params": { ... } }',
353
+ 'Eğer araç gerekmezse: { "final": "cevap" }',
354
+ 'Dosya yollarını ve komutları kısa tut.'
355
+ ].join('\n');
356
+
357
+ const plan = await aiChat(message, {
358
+ aiProvider: this.config.aiProvider || 'gemini',
359
+ systemContext: systemPrompt
360
+ }, this.env);
361
+
362
+ const jsonMatch = plan.match(/\{[\s\S]*\}/);
363
+ if (!jsonMatch) return null;
364
+ let obj;
365
+ try { obj = JSON.parse(jsonMatch[0]); } catch { return null; }
366
+ if (obj.final) return obj.final;
367
+ if (!obj.tool) return null;
368
+
369
+ let toolResult;
370
+ if (obj.tool === 'apiQuery') {
371
+ toolResult = await this._runApiQuery(obj.args || {});
372
+ } else {
373
+ toolResult = await executeTool(obj.tool, obj.args || {}, this.config);
374
+ }
375
+ const followup = await aiChat(
376
+ `Kullanıcı mesajı: ${message}\nAraç çıktısı:\n${toolResult.output}\nCevap ver.`,
377
+ { aiProvider: this.config.aiProvider || 'gemini' },
378
+ this.env
379
+ );
380
+ return followup;
381
+ }
382
+
383
+ async _runApiQuery(args = {}) {
384
+ const platform = (args.platform || '').toLowerCase();
385
+ const action = (args.action || '').toLowerCase();
386
+ const params = args.params || {};
387
+ const api = platformHub.resolve(platform);
388
+ if (!api) return { success: false, output: 'Platform bulunamadı.' };
389
+
390
+ try {
391
+ if (action === 'orders' && api.getOrders) {
392
+ const result = await api.getOrders(params);
393
+ return { success: true, output: JSON.stringify(result?.data || result || {}, null, 2) };
394
+ }
395
+ if (action === 'products' && api.getProducts) {
396
+ const result = await api.getProducts(params);
397
+ return { success: true, output: JSON.stringify(result?.data || result || {}, null, 2) };
398
+ }
399
+ if (action === 'stock' && api.getProducts) {
400
+ const result = await api.getProducts(params);
401
+ return { success: true, output: JSON.stringify(result?.data || result || {}, null, 2) };
402
+ }
403
+ if (action === 'categories' && api.getTopCategories) {
404
+ const result = await api.getTopCategories(params);
405
+ return { success: true, output: JSON.stringify(result?.data || result || {}, null, 2) };
406
+ }
407
+ return { success: false, output: 'Bu platform için istenen action desteklenmiyor.' };
408
+ } catch (e) {
409
+ return { success: false, output: e.message };
410
+ }
411
+ }
455
412
 
456
413
  /**
457
414
  * Mesajdan Tool tespiti (Basit NLP)
458
415
  */
459
- async _tryExecuteToolFromMessage(message) {
460
- const lower = message.toLowerCase().trim();
461
- const normalized = lower
462
- .replace(/[çÇ]/g, 'c')
463
- .replace(/[ğĞ]/g, 'g')
464
- .replace(/[ıİ]/g, 'i')
465
- .replace(/[öÖ]/g, 'o')
466
- .replace(/[şŞ]/g, 's')
467
- .replace(/[üÜ]/g, 'u');
468
-
469
- // Check for explicit commands
470
- if (lower.startsWith('/')) {
416
+ async _tryExecuteToolFromMessage(message) {
417
+ const lower = message.toLowerCase().trim();
418
+ const normalized = lower
419
+ .replace(/[çÇ]/g, 'c')
420
+ .replace(/[ğĞ]/g, 'g')
421
+ .replace(/[ıİ]/g, 'i')
422
+ .replace(/[öÖ]/g, 'o')
423
+ .replace(/[şŞ]/g, 's')
424
+ .replace(/[üÜ]/g, 'u');
425
+
426
+ // Check for explicit commands
427
+ if (lower.startsWith('/')) {
471
428
  const parts = lower.substring(1).split(' ');
472
429
  const command = parts[0];
473
430
  const args = parts.slice(1);
@@ -485,63 +442,63 @@ export class VantuzEngine {
485
442
  case 'help':
486
443
  return "Kullanabileceğin komutlar: /rakip, /stok-durumu";
487
444
  default:
488
- return `Bilinmeyen komut: /${command}. Yardım için /help yazabilirsin.`;
489
- }
490
- }
491
-
492
- // Natural language shortcuts (no hallucination)
493
- if (
494
- lower.includes('hangi pazaryerleri bağlı') ||
495
- lower.includes('hangi pazaryeri bağlı') ||
496
- lower.includes('hangi platformlar bağlı') ||
497
- normalized.includes('hangi pazaryerleri bagli') ||
498
- normalized.includes('hangi platformlar bagli')
499
- ) {
500
- const connected = this.context.connectedPlatforms;
501
- if (connected.length === 0) return 'Şu an bağlı pazaryeri yok.';
502
- return `Bağlı pazaryerleri: ${connected.map(p => p.toUpperCase()).join(', ')}`;
503
- }
504
-
505
- const orderKeywords = [
506
- 'sipariş',
507
- 'siparis'
508
- ];
509
- const hasOrderKeyword = orderKeywords.some(k => lower.includes(k) || normalized.includes(k));
510
-
511
- if (hasOrderKeyword) {
512
- const orders = await this.getOrders({ size: 50, allStatuses: true });
513
- if (!orders || orders.length === 0) {
514
- return 'Sipariş verisine ulaşılamadı. Lütfen platform API bağlantılarını kontrol edin.';
515
- }
516
- const summary = this._summarizeOrdersByStatus(orders);
517
- return `Şu an bağlı platformlardan gelen toplam ${orders.length} sipariş var.${summary ? ` Durum kırılımı: ${summary}` : ''}`;
518
- }
519
-
520
- if (lower.includes('onaylanan')) {
521
- const orders = await this.getOrders({ size: 100, status: 'Picking' });
522
- return `Şu an onaylanan (Picking) ${orders.length} sipariş var.`;
523
- }
524
-
525
- if (lower.includes('kargoya verilmemiş') || lower.includes('henüz kargoya') || lower.includes('kargoya verilmedi') || normalized.includes('kargoya verilmemis')) {
526
- const orders = await this.getOrders({ size: 100, status: 'Created' });
527
- return `Şu an kargoya verilmemiş (Created) ${orders.length} sipariş var.`;
528
- }
529
-
530
- return null;
531
- }
532
-
533
- _summarizeOrdersByStatus(orders = []) {
534
- if (!Array.isArray(orders) || orders.length === 0) return '';
535
- const counts = {};
536
- orders.forEach(o => {
537
- const s = (o.status || o.shipmentPackageStatus || o.orderStatus || 'UNKNOWN').toString();
538
- counts[s] = (counts[s] || 0) + 1;
539
- });
540
- const entries = Object.entries(counts)
541
- .sort((a, b) => b[1] - a[1])
542
- .map(([s, n]) => `${s}:${n}`);
543
- return entries.join(', ');
544
- }
445
+ return `Bilinmeyen komut: /${command}. Yardım için /help yazabilirsin.`;
446
+ }
447
+ }
448
+
449
+ // Natural language shortcuts (no hallucination)
450
+ if (
451
+ lower.includes('hangi pazaryerleri bağlı') ||
452
+ lower.includes('hangi pazaryeri bağlı') ||
453
+ lower.includes('hangi platformlar bağlı') ||
454
+ normalized.includes('hangi pazaryerleri bagli') ||
455
+ normalized.includes('hangi platformlar bagli')
456
+ ) {
457
+ const connected = this.context.connectedPlatforms;
458
+ if (connected.length === 0) return 'Şu an bağlı pazaryeri yok.';
459
+ return `Bağlı pazaryerleri: ${connected.map(p => p.toUpperCase()).join(', ')}`;
460
+ }
461
+
462
+ const orderKeywords = [
463
+ 'sipariş',
464
+ 'siparis'
465
+ ];
466
+ const hasOrderKeyword = orderKeywords.some(k => lower.includes(k) || normalized.includes(k));
467
+
468
+ if (hasOrderKeyword) {
469
+ const orders = await this.getOrders({ size: 50, allStatuses: true });
470
+ if (!orders || orders.length === 0) {
471
+ return 'Sipariş verisine ulaşılamadı. Lütfen platform API bağlantılarını kontrol edin.';
472
+ }
473
+ const summary = this._summarizeOrdersByStatus(orders);
474
+ return `Şu an bağlı platformlardan gelen toplam ${orders.length} sipariş var.${summary ? ` Durum kırılımı: ${summary}` : ''}`;
475
+ }
476
+
477
+ if (lower.includes('onaylanan')) {
478
+ const orders = await this.getOrders({ size: 100, status: 'Picking' });
479
+ return `Şu an onaylanan (Picking) ${orders.length} sipariş var.`;
480
+ }
481
+
482
+ if (lower.includes('kargoya verilmemiş') || lower.includes('henüz kargoya') || lower.includes('kargoya verilmedi') || normalized.includes('kargoya verilmemis')) {
483
+ const orders = await this.getOrders({ size: 100, status: 'Created' });
484
+ return `Şu an kargoya verilmemiş (Created) ${orders.length} sipariş var.`;
485
+ }
486
+
487
+ return null;
488
+ }
489
+
490
+ _summarizeOrdersByStatus(orders = []) {
491
+ if (!Array.isArray(orders) || orders.length === 0) return '';
492
+ const counts = {};
493
+ orders.forEach(o => {
494
+ const s = (o.status || o.shipmentPackageStatus || o.orderStatus || 'UNKNOWN').toString();
495
+ counts[s] = (counts[s] || 0) + 1;
496
+ });
497
+ const entries = Object.entries(counts)
498
+ .sort((a, b) => b[1] - a[1])
499
+ .map(([s, n]) => `${s}:${n}`);
500
+ return entries.join(', ');
501
+ }
545
502
 
546
503
  /**
547
504
  * Context bilgisi oluştur (AI system prompt için)
@@ -609,7 +566,7 @@ export class VantuzEngine {
609
566
  return {
610
567
  engine: this.initialized ? 'active' : 'inactive',
611
568
  version: '3.2',
612
- aiProvider: this.config.aiProvider || 'gemini',
569
+ aiProvider: this.env.AI_PROVIDER || this.config.aiProvider || 'gemini',
613
570
  gateway: gatewayInfo,
614
571
  platforms: status,
615
572
  channels: channelStatus,
package/core/gateway.js CHANGED
@@ -9,11 +9,11 @@
9
9
  * - Sistem durumu sorgulama
10
10
  */
11
11
 
12
- import axios from 'axios';
13
- import fs from 'fs';
14
- import path from 'path';
15
- import os from 'os';
16
- import { log } from './ai-provider.js';
12
+ import axios from 'axios';
13
+ import fs from 'fs';
14
+ import path from 'path';
15
+ import os from 'os';
16
+ import { log } from './ai-provider.js';
17
17
 
18
18
  // ═══════════════════════════════════════════════════════════════════════════
19
19
  // CONFIG - Gateway ayarları
@@ -42,15 +42,15 @@ function getGatewayToken(config) {
42
42
  // GATEWAY CLIENT
43
43
  // ═══════════════════════════════════════════════════════════════════════════
44
44
 
45
- export class VantuzGateway {
45
+ export class VantuzGateway {
46
46
  constructor() {
47
47
  this.config = loadGatewayConfig();
48
48
  const port = this.config?.gateway?.port || 18789;
49
49
  this.baseUrl = `http://localhost:${port}`;
50
50
  this.token = getGatewayToken(this.config);
51
51
  this.connected = false;
52
- this.version = null;
53
- }
52
+ this.version = null;
53
+ }
54
54
 
55
55
  /**
56
56
  * HTTP Headers (token auth)
@@ -101,66 +101,137 @@ export class VantuzGateway {
101
101
  /**
102
102
  * Gateway sağlık kontrolü
103
103
  */
104
- async health() {
105
- const result = await this._request('GET', '/health');
106
- this.connected = result.success;
107
- if (result.success) {
108
- this.version = result.data?.version || 'unknown';
109
- }
110
- return result;
111
- }
112
-
113
- /**
114
- * Gateway sürecini başlat (lokal gateway.cmd)
115
- */
116
- async start() {
117
- const gatewayCmd = path.join(process.cwd(), '.openclaw', 'gateway.cmd');
118
- if (!fs.existsSync(gatewayCmd)) {
119
- return { success: false, error: 'Gateway başlatma dosyası bulunamadı: gateway.cmd' };
120
- }
121
-
122
- try {
123
- const { spawn } = await import('child_process');
124
- const child = spawn(gatewayCmd, [], {
125
- detached: true,
126
- stdio: 'ignore',
127
- shell: true
128
- });
129
- child.unref();
130
- return { success: true };
131
- } catch (e) {
132
- return { success: false, error: e.message };
133
- }
134
- }
135
-
136
- /**
137
- * Gateway çalışmıyorsa başlat ve sağlık kontrolü yap
138
- */
139
- async ensureRunning(options = {}) {
140
- const {
141
- retries = 5,
142
- intervalMs = 1000
143
- } = options;
144
-
145
- if (this.isConnected()) {
146
- return { success: true, already: true };
147
- }
148
-
149
- const started = await this.start();
150
- if (!started.success) {
151
- return started;
152
- }
153
-
154
- for (let i = 0; i < retries; i++) {
155
- await new Promise(r => setTimeout(r, intervalMs));
156
- const health = await this.health();
157
- if (health.success) {
158
- return { success: true, started: true };
159
- }
160
- }
161
-
162
- return { success: false, error: 'Gateway başlatıldı ancak sağlık kontrolü geçmedi' };
163
- }
104
+ async health() {
105
+ const result = await this._request('GET', '/health');
106
+ this.connected = result.success;
107
+ if (result.success) {
108
+ this.version = result.data?.version || 'unknown';
109
+ }
110
+ return result;
111
+ }
112
+
113
+ /**
114
+ * Gateway sürecini başlat
115
+ */
116
+ async start() {
117
+ const cwd = process.cwd();
118
+ const gatewayCmd = path.join(cwd, '.openclaw', 'gateway.cmd');
119
+ const isWin = process.platform === 'win32';
120
+
121
+ try {
122
+ const { spawn } = await import('child_process');
123
+ let child;
124
+
125
+ if (isWin && fs.existsSync(gatewayCmd)) {
126
+ // Windows: Use generated CMD (has config env vars)
127
+ child = spawn(gatewayCmd, [], {
128
+ detached: true,
129
+ stdio: 'ignore', // Keep it in background
130
+ shell: true,
131
+ cwd // Ensure CWD is correct for finding node_modules
132
+ });
133
+ } else {
134
+ // Linux/Mac or missing CMD: Use npx directly
135
+ // We try to load token from config if possible to pass as ENV
136
+ const env = { ...process.env };
137
+ if (this.config?.gateway?.auth?.token) {
138
+ env.OPENCLAW_GATEWAY_TOKEN = this.config.gateway.auth.token;
139
+ }
140
+
141
+ child = spawn('npx', ['openclaw', 'gateway', '--port', '18789', '--allow-unconfigured'], {
142
+ detached: true,
143
+ stdio: 'ignore',
144
+ shell: true,
145
+ cwd,
146
+ env
147
+ });
148
+ }
149
+
150
+ if (child) {
151
+ child.unref(); // Detach process so it outlives parent
152
+ return { success: true };
153
+ }
154
+ return { success: false, error: 'Child process could not be spawned' };
155
+
156
+ } catch (e) {
157
+ return { success: false, error: e.message };
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Vantuz API Server (server/app.js) başlat
163
+ */
164
+ async startServer() {
165
+ const serverPath = path.join(process.cwd(), 'server', 'app.js');
166
+ if (!fs.existsSync(serverPath)) {
167
+ return { success: false, error: 'Server dosyası bulunamadı: server/app.js' };
168
+ }
169
+
170
+ try {
171
+ const { spawn } = await import('child_process');
172
+ const child = spawn('node', [serverPath], {
173
+ detached: true,
174
+ stdio: 'ignore',
175
+ shell: true,
176
+ cwd: process.cwd(),
177
+ env: { ...process.env, PORT: '3001' } // Ensure default port
178
+ });
179
+
180
+ child.unref();
181
+ return { success: true };
182
+ } catch (e) {
183
+ return { success: false, error: e.message };
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Tüm sistemi başlat (Gateway + Server)
189
+ */
190
+ async startFullStack() {
191
+ // 1. Start Gateway
192
+ const gwResult = await this.start();
193
+
194
+ // 2. Wait for Gateway to initialize (approx 3s)
195
+ await new Promise(resolve => setTimeout(resolve, 3000));
196
+
197
+ // 3. Start Server
198
+ const serverResult = await this.startServer();
199
+
200
+ return {
201
+ success: gwResult.success && serverResult.success,
202
+ gateway: gwResult,
203
+ server: serverResult
204
+ };
205
+ }
206
+
207
+ /**
208
+ * Gateway çalışmıyorsa başlat ve sağlık kontrolü yap
209
+ */
210
+ async ensureRunning(options = {}) {
211
+ const {
212
+ retries = 5,
213
+ intervalMs = 1000
214
+ } = options;
215
+
216
+ if (this.isConnected()) {
217
+ return { success: true, already: true };
218
+ }
219
+
220
+ const started = await this.start();
221
+ if (!started.success) {
222
+ return started;
223
+ }
224
+
225
+ for (let i = 0; i < retries; i++) {
226
+ await new Promise(r => setTimeout(r, intervalMs));
227
+ const health = await this.health();
228
+ if (health.success) {
229
+ return { success: true, started: true };
230
+ }
231
+ }
232
+
233
+ return { success: false, error: 'Gateway başlatıldı ancak sağlık kontrolü geçmedi' };
234
+ }
164
235
 
165
236
  /**
166
237
  * Detaylı sistem durumu
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vantuz",
3
- "version": "3.3.5",
3
+ "version": "3.3.6",
4
4
  "description": "Yapay Zeka Destekli E-Ticaret Yönetim Platformu - 7 Pazaryeri + WhatsApp/Telegram",
5
5
  "type": "module",
6
6
  "main": "cli.js",
@@ -4,7 +4,10 @@ export default {
4
4
  description: 'Global E-ticaret Platformu',
5
5
  requiredFields: [
6
6
  { key: 'sellerId', label: 'Seller ID', env: 'AMAZON_SELLER_ID' },
7
- { key: 'authToken', label: 'Auth Token', env: 'AMAZON_AUTH_TOKEN' }
7
+ { key: 'clientId', label: 'Client ID (LWA)', env: 'AMAZON_CLIENT_ID' },
8
+ { key: 'clientSecret', label: 'Client Secret (LWA)', env: 'AMAZON_CLIENT_SECRET' },
9
+ { key: 'refreshToken', label: 'Refresh Token', env: 'AMAZON_REFRESH_TOKEN' },
10
+ { key: 'region', label: 'Bölge (eu/na/tr)', env: 'AMAZON_REGION', default: 'eu' }
8
11
  ],
9
12
  async getOrders(creds) {
10
13
  // Stub
@@ -3,7 +3,8 @@ export default {
3
3
  icon: '🌸', // Flower icon for ÇiçekSepeti
4
4
  description: 'Entegre Çevrimiçi Çiçek ve Hediye Platformu',
5
5
  requiredFields: [
6
- { key: 'apiKey', label: 'API Key', env: 'CICEKSEPETI_API_KEY' }
6
+ { key: 'apiKey', label: 'API Key', env: 'CICEKSEPETI_API_KEY' },
7
+ { key: 'supplierId', label: 'Supplier ID', env: 'CICEKSEPETI_SUPPLIER_ID' }
7
8
  ],
8
9
  async getOrders(creds) {
9
10
  // Stub
package/platforms/n11.js CHANGED
@@ -3,8 +3,8 @@ export default {
3
3
  icon: '🔵', // Blue circle icon for N11
4
4
  description: 'Alternatif E-ticaret Platformu',
5
5
  requiredFields: [
6
- { key: 'apiKey', label: 'API Key', env: 'N11_API_KEY' },
7
- { key: 'apiSecret', label: 'API Secret', env: 'N11_API_SECRET' }
6
+ { key: 'apiKey', label: 'App Key', env: 'N11_API_KEY' },
7
+ { key: 'apiSecret', label: 'App Secret', env: 'N11_API_SECRET' }
8
8
  ],
9
9
  async getOrders(creds) {
10
10
  // Stub
@@ -3,7 +3,8 @@ export default {
3
3
  icon: '🛒', // Shopping cart icon for Pazarama
4
4
  description: 'Yeni Nesil Mobil Alışveriş Platformu',
5
5
  requiredFields: [
6
- { key: 'apiKey', label: 'API Key', env: 'PAZARAMA_API_KEY' }
6
+ { key: 'clientId', label: 'Client ID', env: 'PAZARAMA_CLIENT_ID' },
7
+ { key: 'clientSecret', label: 'Client Secret', env: 'PAZARAMA_CLIENT_SECRET' }
7
8
  ],
8
9
  async getOrders(creds) {
9
10
  // Stub
@@ -0,0 +1,14 @@
1
+ export default {
2
+ name: 'PttAVM',
3
+ icon: '📮', // Postbox icon for PttAVM
4
+ description: 'Türkiye\'nin Güvenilir E-ticaret Platformu',
5
+ requiredFields: [
6
+ { key: 'apiKey', label: 'API Key', env: 'PTTAVM_API_KEY' },
7
+ { key: 'token', label: 'Token', env: 'PTTAVM_TOKEN' },
8
+ { key: 'shopId', label: 'Shop ID', env: 'PTTAVM_SHOP_ID' }
9
+ ],
10
+ async getOrders(creds) {
11
+ // Stub
12
+ return [];
13
+ }
14
+ };