vantuz 3.4.2 → 3.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/.env.example +21 -0
  2. package/.openclaw/completions/openclaw.bash +227 -0
  3. package/.openclaw/completions/openclaw.fish +1552 -0
  4. package/.openclaw/completions/openclaw.ps1 +1966 -0
  5. package/.openclaw/completions/openclaw.zsh +3571 -0
  6. package/.openclaw/gateway.cmd +10 -0
  7. package/.openclaw/identity/device.json +7 -0
  8. package/.openclaw/openclaw.json +40 -0
  9. package/.windsurf/workflows/vantuz-dev.md +31 -0
  10. package/DOCS_TR.md +80 -0
  11. package/LICENSE +45 -45
  12. package/README.md +52 -21
  13. package/cli.js +685 -585
  14. package/config.js +733 -733
  15. package/core/agent-loop.js +190 -190
  16. package/core/ai-provider.js +298 -261
  17. package/core/automation.js +523 -523
  18. package/core/brand-analyst.js +101 -0
  19. package/core/channels.js +167 -167
  20. package/core/dashboard.js +230 -230
  21. package/core/database.js +135 -37
  22. package/core/eia-monitor.js +3 -1
  23. package/core/engine.js +648 -636
  24. package/core/gateway.js +447 -447
  25. package/core/learning.js +214 -214
  26. package/core/license.js +113 -0
  27. package/core/marketplace-adapter.js +168 -168
  28. package/core/memory.js +190 -190
  29. package/core/migrations/001-initial-schema.sql +1 -1
  30. package/core/queue.js +120 -120
  31. package/core/self-healer.js +314 -314
  32. package/core/unified-product.js +214 -214
  33. package/core/vision-service.js +113 -113
  34. package/index.js +217 -174
  35. package/modules/crm/sentiment-crm.js +231 -231
  36. package/modules/healer/listing-healer.js +201 -201
  37. package/modules/oracle/predictor.js +214 -214
  38. package/modules/researcher/agent.js +169 -169
  39. package/modules/team/agents/base.js +92 -92
  40. package/modules/team/agents/dev.js +33 -33
  41. package/modules/team/agents/josh.js +40 -40
  42. package/modules/team/agents/marketing.js +33 -33
  43. package/modules/team/agents/milo.js +36 -36
  44. package/modules/team/index.js +78 -78
  45. package/modules/team/shared-memory.js +87 -87
  46. package/modules/war-room/competitor-tracker.js +250 -250
  47. package/modules/war-room/pricing-engine.js +308 -308
  48. package/n11docs.md +1680 -0
  49. package/nodes/warehouse.js +238 -238
  50. package/onboard.js +1 -1
  51. package/openclawdocs.md +3 -0
  52. package/package.json +7 -5
  53. package/platforms/pttavm.js +14 -14
  54. package/plugins/vantuz/index.js +528 -528
  55. package/plugins/vantuz/memory/hippocampus.js +465 -465
  56. package/plugins/vantuz/package.json +20 -20
  57. package/plugins/vantuz/platforms/_template.js +118 -118
  58. package/plugins/vantuz/platforms/amazon.js +236 -236
  59. package/plugins/vantuz/platforms/ciceksepeti.js +166 -166
  60. package/plugins/vantuz/platforms/hepsiburada.js +180 -180
  61. package/plugins/vantuz/platforms/index.js +165 -165
  62. package/plugins/vantuz/platforms/n11.js +229 -229
  63. package/plugins/vantuz/platforms/pazarama.js +154 -154
  64. package/plugins/vantuz/platforms/pttavm.js +127 -127
  65. package/plugins/vantuz/platforms/trendyol.js +326 -326
  66. package/plugins/vantuz/services/alerts.js +253 -253
  67. package/plugins/vantuz/services/license.js +34 -34
  68. package/plugins/vantuz/services/scheduler.js +232 -232
  69. package/plugins/vantuz/tools/analytics.js +152 -152
  70. package/plugins/vantuz/tools/crossborder.js +187 -187
  71. package/plugins/vantuz/tools/nl-parser.js +211 -211
  72. package/plugins/vantuz/tools/product.js +110 -110
  73. package/plugins/vantuz/tools/quick-report.js +175 -175
  74. package/plugins/vantuz/tools/repricer.js +314 -314
  75. package/plugins/vantuz/tools/sentiment.js +115 -115
  76. package/plugins/vantuz/tools/vision.js +257 -257
  77. package/public.pem +9 -0
  78. package/server/app.js +260 -260
  79. package/server/public/index.html +514 -514
  80. package/start.bat +33 -33
  81. package/vantuz.sqlite +0 -0
  82. package/workspace/AGENTS.md +73 -0
  83. package/workspace/BRAND.md +29 -0
  84. package/workspace/SOUL.md +72 -0
  85. package/workspace/team/DECISIONS.md +3 -0
  86. package/workspace/team/GOALS.md +3 -0
  87. package/workspace/team/PROJECT_STATUS.md +3 -0
  88. package/workspace/team/agents/dev/SOUL.md +12 -0
  89. package/workspace/team/agents/josh/SOUL.md +12 -0
  90. package/workspace/team/agents/marketing/SOUL.md +12 -0
  91. package/workspace/team/agents/milo/SOUL.md +12 -0
  92. package/vantuz-3.3.4.tgz +0 -0
package/core/engine.js CHANGED
@@ -1,636 +1,648 @@
1
- /**
2
- * 🐙 VANTUZ ENGINE v3.2
3
- * Merkezi motor - Tüm sistemleri yönetir
4
- *
5
- * Vantuz Gateway üzerinden güçlendirilmiş altyapı
6
- * Entegre Tool Sistemi
7
- */
8
-
9
- import fs from 'fs';
10
- import path from 'path';
11
- import os from 'os';
12
-
13
- // Platform Hub
14
- import platformHub from '../plugins/vantuz/platforms/index.js';
15
-
16
- // AI Provider & Gateway
17
- import { getChannelManager } from './channels.js';
18
- import { chat as aiChat, log } from './ai-provider.js';
19
- import { getGateway } from './gateway.js';
20
- import { getEIAMonitor } from './eia-monitor.js';
21
- import AutomationManager from './automation.js';
22
- import OpenClawBridge from './openclaw-bridge.js';
23
- import { executeTool } from './agent.js';
24
- import { getCriticalQueue } from './queue.js';
25
- import { getMemory } from './memory.js';
26
-
27
- // Tools
28
- import { repricerTool } from '../plugins/vantuz/tools/repricer.js';
29
- import { visionTool } from '../plugins/vantuz/tools/vision.js';
30
- import { sentimentTool } from '../plugins/vantuz/tools/sentiment.js';
31
- import { crossborderTool } from '../plugins/vantuz/tools/crossborder.js';
32
- import { productTool } from '../plugins/vantuz/tools/product.js';
33
- import { analyticsTool } from '../plugins/vantuz/tools/analytics.js';
34
- import { quickReportTool } from '../plugins/vantuz/tools/quick-report.js';
35
-
36
- const PLATFORM_CONFIG_MAP = {
37
- trendyol: {
38
- envPrefix: 'TRENDYOL',
39
- keys: ['supplierId', 'apiKey', 'apiSecret']
40
- },
41
- hepsiburada: {
42
- envPrefix: 'HEPSIBURADA',
43
- keys: ['merchantId', 'username', 'password']
44
- },
45
- n11: {
46
- envPrefix: 'N11',
47
- keys: ['apiKey', 'apiSecret']
48
- },
49
- amazon: {
50
- envPrefix: 'AMAZON',
51
- keys: ['sellerId', 'clientId', 'clientSecret', 'refreshToken', 'region']
52
- },
53
- ciceksepeti: {
54
- envPrefix: 'CICEKSEPETI',
55
- keys: ['apiKey', 'supplierId']
56
- },
57
- pttavm: {
58
- envPrefix: 'PTTAVM',
59
- keys: ['apiKey', 'token', 'shopId']
60
- },
61
- pazarama: {
62
- envPrefix: 'PAZARAMA',
63
- keys: ['clientId', 'clientSecret']
64
- }
65
- };
66
-
67
- // ═══════════════════════════════════════════════════════════════════════════
68
- // CONFIG
69
- // ═══════════════════════════════════════════════════════════════════════════
70
-
71
- const VANTUZ_HOME = path.join(os.homedir(), '.vantuz');
72
- const CONFIG_PATH = path.join(VANTUZ_HOME, '.env');
73
- const CONFIG_JSON = path.join(VANTUZ_HOME, 'config.json');
74
-
75
- // ═══════════════════════════════════════════════════════════════════════════
76
- // ENGINE CLASS
77
- // ═══════════════════════════════════════════════════════════════════════════
78
-
79
- export class VantuzEngine {
80
- constructor() {
81
- this.initialized = false;
82
- this.config = {};
83
- this.env = {};
84
- this.platforms = {};
85
- this.channels = null;
86
- this.gateway = null;
87
- this.context = {
88
- products: [],
89
- connectedPlatforms: []
90
- };
91
- this.eiaMonitor = null; // New property
92
- this.automation = null;
93
- this.bridge = null;
94
-
95
- // Tool Registry
96
- this.tools = {
97
- repricer: repricerTool,
98
- vision: visionTool,
99
- sentiment: sentimentTool,
100
- crossborder: crossborderTool,
101
- product: productTool,
102
- analytics: analyticsTool,
103
- quickReport: quickReportTool
104
- };
105
-
106
- // Critical Operation Queue (Lane Queue)
107
- this.queue = getCriticalQueue();
108
- this.memory = getMemory();
109
- }
110
-
111
- /**
112
- * Engine'i başlat
113
- */
114
- async initialize() {
115
- log('INFO', 'Vantuz Engine v3.2 başlatılıyor...');
116
-
117
- // Config ve env yükle
118
- this._loadConfig();
119
- this._loadEnv();
120
-
121
- // Vantuz Gateway bağlantısı
122
- try {
123
- this.gateway = await getGateway();
124
- if (this.gateway.isConnected()) {
125
- log('INFO', 'Vantuz Gateway bağlı', this.gateway.getInfo());
126
- } else if (this._shouldAutoStartGateway()) {
127
- const started = await this.gateway.ensureRunning();
128
- if (started.success) {
129
- log('INFO', 'Vantuz Gateway otomatik başlatıldı', this.gateway.getInfo());
130
- } else {
131
- log('WARN', 'Gateway otomatik başlatılamadı', { error: started.error });
132
- }
133
- }
134
- } catch (e) {
135
- log('WARN', 'Gateway bağlantısı başarısız, direkt mod', { error: e.message });
136
- }
137
-
138
- // Channel Manager'ı başlat
139
- this.channels = await getChannelManager();
140
-
141
- // Platform Hub'ı başlat
142
- await this._initPlatforms();
143
-
144
- // Context oluştur (bağlı platformlardan veri çek)
145
- await this._buildContext();
146
-
147
- // Initialize and start EIA Monitor
148
- this.eiaMonitor = getEIAMonitor(this.config, this.env);
149
- await this.eiaMonitor.initMonitoringTasks(); // New line
150
-
151
- // Automation manager
152
- this.automation = new AutomationManager(this);
153
- this.automation.init();
154
-
155
- // Gateway WS bridge (inbound)
156
- if (this._shouldStartBridge()) {
157
- try {
158
- this.bridge = new OpenClawBridge(this, this.gateway);
159
- this.bridge.start();
160
- } catch (e) {
161
- log('WARN', 'Gateway bridge başlatılamadı', { error: e.message });
162
- }
163
- }
164
-
165
- this.initialized = true;
166
- log('INFO', 'Vantuz Engine hazır', {
167
- platforms: this.context.connectedPlatforms.length,
168
- gateway: this.gateway?.isConnected() || false
169
- });
170
-
171
- return this;
172
- }
173
-
174
- /**
175
- * Gelişmiş mesaj işleme (otomasyon + onay)
176
- */
177
- async handleMessage(message, meta = { channel: 'local', from: 'local' }) {
178
- if (!this.initialized) await this.initialize();
179
- if (this.automation) {
180
- const result = await this.automation.handleMessage(message, meta);
181
- if (result?.handled) {
182
- return result.response;
183
- }
184
- }
185
- return await this.chat(message);
186
- }
187
-
188
- /**
189
- * Gateway otomatik başlatılsın mı?
190
- */
191
- _shouldAutoStartGateway() {
192
- const envValue = this.env.VANTUZ_GATEWAY_AUTOSTART;
193
- if (envValue !== undefined) {
194
- return !['0', 'false', 'no'].includes(String(envValue).toLowerCase());
195
- }
196
- if (this.config && this.config.gatewayAutoStart !== undefined) {
197
- return this.config.gatewayAutoStart !== false;
198
- }
199
- return true;
200
- }
201
-
202
- _shouldStartBridge() {
203
- const envValue = this.env.VANTUZ_OPENCLAW_BRIDGE;
204
- if (envValue !== undefined) {
205
- return !['0', 'false', 'no'].includes(String(envValue).toLowerCase());
206
- }
207
- if (this.config && this.config.openclawBridge !== undefined) {
208
- return this.config.openclawBridge !== false;
209
- }
210
- return true;
211
- }
212
-
213
- /**
214
- * Config dosyasını yükle
215
- */
216
- _loadConfig() {
217
- try {
218
- if (fs.existsSync(CONFIG_JSON)) {
219
- this.config = JSON.parse(fs.readFileSync(CONFIG_JSON, 'utf-8'));
220
- }
221
- } catch (e) {
222
- log('ERROR', 'Config yüklenemedi', { error: e.message });
223
- }
224
- }
225
-
226
- /**
227
- * Environment değişkenlerini yükle
228
- */
229
- _loadEnv() {
230
- try {
231
- if (fs.existsSync(CONFIG_PATH)) {
232
- const content = fs.readFileSync(CONFIG_PATH, 'utf-8');
233
- content.split('\n').forEach(line => {
234
- const match = line.match(/^([^=]+)=(.*)$/);
235
- if (match) {
236
- this.env[match[1].trim()] = match[2].trim();
237
- }
238
- });
239
- }
240
- } catch (e) {
241
- log('ERROR', 'Env yüklenemedi', { error: e.message });
242
- }
243
- }
244
-
245
- /**
246
- * Platform API'lerini başlat
247
- */
248
- async _initPlatforms() {
249
- const platformConfig = {};
250
-
251
- for (const platformName in PLATFORM_CONFIG_MAP) {
252
- const platformMap = PLATFORM_CONFIG_MAP[platformName];
253
-
254
- if (platformMap.envPrefix && platformMap.keys) { // Handle all platforms with direct keys
255
- const config = {};
256
- let hasRequiredEnv = false;
257
- for (const key of platformMap.keys) {
258
- const upper = key.toUpperCase();
259
- const snake = key.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toUpperCase();
260
- const envKey = `${platformMap.envPrefix}_${upper}`;
261
- const altEnvKey = `${platformMap.envPrefix}_${snake}`;
262
- const value = this.env[envKey] || this.env[altEnvKey];
263
- if (value) {
264
- config[key] = value;
265
- hasRequiredEnv = true;
266
- }
267
- }
268
- if (hasRequiredEnv) {
269
- platformConfig[platformName] = config;
270
- }
271
- }
272
- }
273
-
274
- // Platform Hub'ı başlat
275
- if (Object.keys(platformConfig).length > 0) {
276
- this.platforms = await platformHub.initAll(platformConfig);
277
- log('INFO', 'Platform Hub başlatıldı', {
278
- platforms: Object.keys(this.platforms)
279
- });
280
- }
281
- }
282
-
283
- /**
284
- * Bağlı platformlardan context oluştur
285
- */
286
- async _buildContext() {
287
- this.context.connectedPlatforms = platformHub.getConnected();
288
-
289
- for (const platform of this.context.connectedPlatforms) {
290
- try {
291
- const api = platformHub.resolve(platform);
292
- if (api && typeof api.getProducts === 'function') {
293
- const result = await api.getProducts({ page: 0, size: 10 });
294
- if (result?.success) {
295
- const data = result.data;
296
- let products = [];
297
- if (Array.isArray(data?.content)) products = data.content;
298
- else if (Array.isArray(data)) products = data;
299
- else if (Array.isArray(data?.productList?.product)) products = data.productList.product;
300
- if (products.length > 0) {
301
- this.context.products.push(...products.map(p => ({
302
- ...p,
303
- _platform: platform
304
- })));
305
- }
306
- }
307
- }
308
- } catch (e) {
309
- log('ERROR', `${platform} veri çekme hatası`, { error: e.message });
310
- }
311
- }
312
- }
313
-
314
- /**
315
- * AI ile sohbet - Tool destekli
316
- */
317
- async chat(message) {
318
- if (!this.initialized) await this.initialize();
319
-
320
- // 1. Basit komut kontrolü (Tool çağırma)
321
- const toolResult = await this._tryExecuteToolFromMessage(message);
322
- if (toolResult) return toolResult;
323
-
324
- // 1.5 Gelişmiş ajan (araç çağrıları)
325
- const agentResult = await this._tryAgent(message);
326
- if (agentResult) return agentResult;
327
-
328
- // 2. Gateway üzerinden AI (Eğer varsa)
329
- if (this.gateway?.isConnected()) {
330
- try {
331
- const gatewayResult = await this.gateway.chat(message, {
332
- systemPrompt: this._buildContextInfo()
333
- });
334
- if (gatewayResult.success) return gatewayResult.response;
335
- } catch (e) { }
336
- }
337
-
338
- // 3. Direkt API (Fallback)
339
- const enrichedConfig = {
340
- ...this.config,
341
- aiProvider: this.env.AI_PROVIDER || this.config.aiProvider || 'gemini',
342
- systemContext: this._buildContextInfo()
343
- };
344
-
345
- return await aiChat(message, enrichedConfig, this.env);
346
- }
347
-
348
- async _tryAgent(message) {
349
- const mode = this.config?.agentMode || this.env.VANTUZ_AGENT_MODE;
350
- if (!mode || mode === 'off') return null;
351
-
352
- const systemPrompt = [
353
- 'Sen Vantuz gelişmiş ajanısın.',
354
- 'Gerekirse aşağıdaki araçlardan birini çağır:',
355
- 'exec, readFile, listDir, httpGet, apiQuery',
356
- 'Sadece JSON döndür.',
357
- 'Şema: { "tool": "exec|readFile|listDir|httpGet|apiQuery", "args": { ... } }',
358
- 'apiQuery args: { "platform": "n11|trendyol|hepsiburada|amazon|ciceksepeti|pazarama|pttavm", "action": "orders|products|stock|categories", "params": { ... } }',
359
- 'Eğer araç gerekmezse: { "final": "cevap" }',
360
- 'Dosya yollarını ve komutları kısa tut.'
361
- ].join('\n');
362
-
363
- const plan = await aiChat(message, {
364
- aiProvider: this.config.aiProvider || 'gemini',
365
- systemContext: systemPrompt
366
- }, this.env);
367
-
368
- const jsonMatch = plan.match(/\{[\s\S]*\}/);
369
- if (!jsonMatch) return null;
370
- let obj;
371
- try { obj = JSON.parse(jsonMatch[0]); } catch { return null; }
372
- if (obj.final) return obj.final;
373
- if (!obj.tool) return null;
374
-
375
- let toolResult;
376
- if (obj.tool === 'apiQuery') {
377
- toolResult = await this._runApiQuery(obj.args || {});
378
- } else {
379
- toolResult = await executeTool(obj.tool, obj.args || {}, this.config);
380
- }
381
- const followup = await aiChat(
382
- `Kullanıcı mesajı: ${message}\nAraç çıktısı:\n${toolResult.output}\nCevap ver.`,
383
- { aiProvider: this.config.aiProvider || 'gemini' },
384
- this.env
385
- );
386
- return followup;
387
- }
388
-
389
- async _runApiQuery(args = {}) {
390
- const platform = (args.platform || '').toLowerCase();
391
- const action = (args.action || '').toLowerCase();
392
- const params = args.params || {};
393
- const api = platformHub.resolve(platform);
394
- if (!api) return { success: false, output: 'Platform bulunamadı.' };
395
-
396
- try {
397
- if (action === 'orders' && api.getOrders) {
398
- const result = await api.getOrders(params);
399
- return { success: true, output: JSON.stringify(result?.data || result || {}, null, 2) };
400
- }
401
- if (action === 'products' && api.getProducts) {
402
- const result = await api.getProducts(params);
403
- return { success: true, output: JSON.stringify(result?.data || result || {}, null, 2) };
404
- }
405
- if (action === 'stock' && api.getProducts) {
406
- const result = await api.getProducts(params);
407
- return { success: true, output: JSON.stringify(result?.data || result || {}, null, 2) };
408
- }
409
- if (action === 'categories' && api.getTopCategories) {
410
- const result = await api.getTopCategories(params);
411
- return { success: true, output: JSON.stringify(result?.data || result || {}, null, 2) };
412
- }
413
- return { success: false, output: 'Bu platform için istenen action desteklenmiyor.' };
414
- } catch (e) {
415
- return { success: false, output: e.message };
416
- }
417
- }
418
-
419
- /**
420
- * Mesajdan Tool tespiti (Basit NLP)
421
- */
422
- async _tryExecuteToolFromMessage(message) {
423
- const lower = message.toLowerCase().trim();
424
- const normalized = lower
425
- .replace(/[çÇ]/g, 'c')
426
- .replace(/[ğĞ]/g, 'g')
427
- .replace(/[ıİ]/g, 'i')
428
- .replace(/[öÖ]/g, 'o')
429
- .replace(/[şŞ]/g, 's')
430
- .replace(/[üÜ]/g, 'u');
431
-
432
- // Check for explicit commands
433
- if (lower.startsWith('/')) {
434
- const parts = lower.substring(1).split(' ');
435
- const command = parts[0];
436
- const args = parts.slice(1);
437
-
438
- switch (command) {
439
- case 'repricer':
440
- case 'rakip':
441
- case 'fiyat-analizi':
442
- // In a real scenario, you'd parse args and pass them to repricerTool
443
- return "Repricer aracı çalıştırılıyor... (Detaylı parametreler için /rakip komutunu kullanın)";
444
- case 'stock':
445
- case 'stok-durumu':
446
- const stocks = await this.getStock();
447
- return JSON.stringify(stocks.map(s => ({ platform: s.platform, items: s.products.length })), null, 2);
448
- case 'help':
449
- return "Kullanabileceğin komutlar: /rakip, /stok-durumu";
450
- default:
451
- return `Bilinmeyen komut: /${command}. Yardım için /help yazabilirsin.`;
452
- }
453
- }
454
-
455
- // Natural language shortcuts (no hallucination)
456
- if (
457
- lower.includes('hangi pazaryerleri bağlı') ||
458
- lower.includes('hangi pazaryeri bağlı') ||
459
- lower.includes('hangi platformlar bağlı') ||
460
- normalized.includes('hangi pazaryerleri bagli') ||
461
- normalized.includes('hangi platformlar bagli')
462
- ) {
463
- const connected = this.context.connectedPlatforms;
464
- if (connected.length === 0) return 'Şu an bağlı pazaryeri yok.';
465
- return `Bağlı pazaryerleri: ${connected.map(p => p.toUpperCase()).join(', ')}`;
466
- }
467
-
468
- const orderKeywords = [
469
- 'sipariş',
470
- 'siparis'
471
- ];
472
- const hasOrderKeyword = orderKeywords.some(k => lower.includes(k) || normalized.includes(k));
473
-
474
- if (hasOrderKeyword) {
475
- const orders = await this.getOrders({ size: 100, allStatuses: true });
476
- if (!orders || orders.length === 0) {
477
- return 'Sipariş verisine ulaşılamadı. Lütfen platform API bağlantılarını kontrol edin.';
478
- }
479
-
480
- const active = orders.filter(o => this.isActiveStatus(o.status || o.shipmentPackageStatus || o.orderStatus));
481
- const completed = orders.filter(o => !this.isActiveStatus(o.status || o.shipmentPackageStatus || o.orderStatus));
482
-
483
- let message = '';
484
- if (active.length > 0) {
485
- const summary = this._summarizeOrdersByStatus(active);
486
- message += `Şu an bağlı platformlardan gelen toplam ${active.length} YENİ/AKTİF sipariş var.${summary ? ` (${summary})` : ''}`;
487
- } else {
488
- message += 'Şu an aktif (yeni/hazırlanan) sipariş yok.';
489
- }
490
-
491
- if (completed.length > 0) {
492
- const summary = this._summarizeOrdersByStatus(completed);
493
- message += `\n(Geçmiş Siparişler: ${completed.length} adet - ${summary})`;
494
- }
495
-
496
- return message;
497
- }
498
-
499
- if (lower.includes('onaylanan')) {
500
- const orders = await this.getOrders({ size: 100, status: 'Picking' });
501
- return `Şu an onaylanan (Picking) ${orders.length} sipariş var.`;
502
- }
503
-
504
- if (lower.includes('kargoya verilmemiş') || lower.includes('henüz kargoya') || lower.includes('kargoya verilmedi') || normalized.includes('kargoya verilmemis')) {
505
- const orders = await this.getOrders({ size: 100, status: 'Created' });
506
- return `Şu an kargoya verilmemiş (Created) ${orders.length} sipariş var.`;
507
- }
508
-
509
- return null;
510
- }
511
-
512
- _summarizeOrdersByStatus(orders = []) {
513
- if (!Array.isArray(orders) || orders.length === 0) return '';
514
- const counts = {};
515
- orders.forEach(o => {
516
- const s = (o.status || o.shipmentPackageStatus || o.orderStatus || 'UNKNOWN').toString();
517
- counts[s] = (counts[s] || 0) + 1;
518
- });
519
- const entries = Object.entries(counts)
520
- .sort((a, b) => b[1] - a[1])
521
- .map(([s, n]) => `${s}:${n}`);
522
- return entries.join(', ');
523
- }
524
-
525
- /**
526
- * Context bilgisi oluştur (AI system prompt için)
527
- */
528
- _buildContextInfo() {
529
- const connected = this.context.connectedPlatforms;
530
- let info = `\n\n--- MEVCUT SİSTEM DURUMU ---\n`;
531
- info += `Bağlı Platformlar: ${connected.length > 0 ? connected.join(', ') : 'Hiçbiri'}\n`;
532
- info += `Gateway: ${this.gateway?.isConnected() ? 'BAĞLI' : 'KOPUK'}\n`;
533
- info += `Mevcut Toollar: Repricer, Vision, Sentiment, Analytics, CrossBorder\n`;
534
-
535
- if (this.context.products.length > 0) {
536
- info += `\nÖrnek Ürünler:\n`;
537
- this.context.products.slice(0, 3).forEach(p => {
538
- info += `- ${p.title} (${p._platform}): ${p.salePrice} TL\n`;
539
- });
540
- }
541
- return info;
542
- }
543
-
544
- // --- Helper Methods ---
545
-
546
- isActiveStatus(status) {
547
- const s = String(status || '').toLowerCase();
548
- return s === 'created' || s === 'picking' || s === 'unpacked' || s === 'shipped';
549
- }
550
-
551
- async getStock(platform = 'all') {
552
- const results = [];
553
- const targets = platform === 'all'
554
- ? this.context.connectedPlatforms
555
- : [platform];
556
-
557
- for (const p of targets) {
558
- try {
559
- const api = platformHub.resolve(p);
560
- if (api?.getProducts) {
561
- const result = await api.getProducts({ page: 0, size: 50 });
562
- if (result?.success) {
563
- const products = result.data?.content || result.data || [];
564
- results.push({
565
- platform: p,
566
- icon: platformHub.getIcon(p),
567
- products: products.map(prod => ({
568
- barcode: prod.barcode,
569
- title: prod.title || prod.name,
570
- stock: prod.quantity || prod.stock,
571
- price: prod.salePrice || prod.price
572
- }))
573
- });
574
- }
575
- }
576
- } catch (e) {
577
- log('ERROR', `Stok çekme hatası: ${p}`, { error: e.message });
578
- }
579
- }
580
- return results;
581
- }
582
-
583
- async getOrders(params = {}) {
584
- return await platformHub.getAllOrders(params);
585
- }
586
-
587
- getStatus() {
588
- const status = platformHub.getStatus();
589
- const connected = this.context.connectedPlatforms;
590
- const channelStatus = this.channels ? this.channels.getStatus() : {};
591
- const gatewayInfo = this.gateway ? this.gateway.getInfo() : { connected: false };
592
-
593
- return {
594
- engine: this.initialized ? 'active' : 'inactive',
595
- version: '3.2',
596
- aiProvider: this.env.AI_PROVIDER || this.config.aiProvider || 'gemini',
597
- gateway: gatewayInfo,
598
- platforms: status,
599
- channels: channelStatus,
600
- connectedCount: connected.length,
601
- totalPlatforms: 7,
602
- productCount: this.context.products.length
603
- };
604
- }
605
-
606
- async doctor() {
607
- const status = this.getStatus();
608
- return {
609
- engine: this.initialized,
610
- gateway: {
611
- status: status.gateway.connected ? 'healthy' : 'unreachable',
612
- ...status.gateway
613
- },
614
- platforms: status.platforms,
615
- ai: {
616
- provider: status.aiProvider,
617
- keyConfigured: true,
618
- gatewayFallback: status.gateway.connected
619
- },
620
- channels: status.channels
621
- };
622
- }
623
- }
624
-
625
- // Singleton instance
626
- let engineInstance = null;
627
-
628
- export async function getEngine() {
629
- if (!engineInstance) {
630
- engineInstance = new VantuzEngine();
631
- await engineInstance.initialize();
632
- }
633
- return engineInstance;
634
- }
635
-
636
- export default VantuzEngine;
1
+ /**
2
+ * 🐙 VANTUZ ENGINE v3.2
3
+ * Merkezi motor - Tüm sistemleri yönetir
4
+ *
5
+ * Vantuz Gateway üzerinden güçlendirilmiş altyapı
6
+ * Entegre Tool Sistemi
7
+ */
8
+
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+ import os from 'os';
12
+
13
+ // Platform Hub
14
+ import platformHub from '../plugins/vantuz/platforms/index.js';
15
+
16
+ // AI Provider & Gateway
17
+ import { getChannelManager } from './channels.js';
18
+ import { chat as aiChat, log } from './ai-provider.js';
19
+ import { getGateway } from './gateway.js';
20
+ import { getEIAMonitor } from './eia-monitor.js';
21
+ import AutomationManager from './automation.js';
22
+ import OpenClawBridge from './openclaw-bridge.js';
23
+ import { executeTool } from './agent.js';
24
+ import { getCriticalQueue } from './queue.js';
25
+ import { getMemory } from './memory.js';
26
+
27
+ // Multi-Agent Team
28
+ import TeamModule from '../modules/team/index.js';
29
+
30
+ // Tools
31
+ import { repricerTool } from '../plugins/vantuz/tools/repricer.js';
32
+ import { visionTool } from '../plugins/vantuz/tools/vision.js';
33
+ import { sentimentTool } from '../plugins/vantuz/tools/sentiment.js';
34
+ import { crossborderTool } from '../plugins/vantuz/tools/crossborder.js';
35
+ import { productTool } from '../plugins/vantuz/tools/product.js';
36
+ import { analyticsTool } from '../plugins/vantuz/tools/analytics.js';
37
+ import { quickReportTool } from '../plugins/vantuz/tools/quick-report.js';
38
+
39
+ const PLATFORM_CONFIG_MAP = {
40
+ trendyol: {
41
+ envPrefix: 'TRENDYOL',
42
+ keys: ['supplierId', 'apiKey', 'apiSecret']
43
+ },
44
+ hepsiburada: {
45
+ envPrefix: 'HEPSIBURADA',
46
+ keys: ['merchantId', 'username', 'password']
47
+ },
48
+ n11: {
49
+ envPrefix: 'N11',
50
+ keys: ['apiKey', 'apiSecret']
51
+ },
52
+ amazon: {
53
+ envPrefix: 'AMAZON',
54
+ keys: ['sellerId', 'clientId', 'clientSecret', 'refreshToken', 'region']
55
+ },
56
+ ciceksepeti: {
57
+ envPrefix: 'CICEKSEPETI',
58
+ keys: ['apiKey', 'supplierId']
59
+ },
60
+ pttavm: {
61
+ envPrefix: 'PTTAVM',
62
+ keys: ['apiKey', 'token', 'shopId']
63
+ },
64
+ pazarama: {
65
+ envPrefix: 'PAZARAMA',
66
+ keys: ['clientId', 'clientSecret']
67
+ }
68
+ };
69
+
70
+ // ═══════════════════════════════════════════════════════════════════════════
71
+ // CONFIG
72
+ // ═══════════════════════════════════════════════════════════════════════════
73
+
74
+ const VANTUZ_HOME = path.join(os.homedir(), '.vantuz');
75
+ const CONFIG_PATH = path.join(VANTUZ_HOME, '.env');
76
+ const CONFIG_JSON = path.join(VANTUZ_HOME, 'config.json');
77
+
78
+ // ═══════════════════════════════════════════════════════════════════════════
79
+ // ENGINE CLASS
80
+ // ═══════════════════════════════════════════════════════════════════════════
81
+
82
+ export class VantuzEngine {
83
+ constructor() {
84
+ this.initialized = false;
85
+ this.config = {};
86
+ this.env = {};
87
+ this.platforms = {};
88
+ this.channels = null;
89
+ this.gateway = null;
90
+ this.context = {
91
+ products: [],
92
+ connectedPlatforms: []
93
+ };
94
+ this.eiaMonitor = null; // New property
95
+ this.automation = null;
96
+ this.bridge = null;
97
+ this.team = null; // Multi-Agent Team
98
+
99
+ // Tool Registry
100
+ this.tools = {
101
+ repricer: repricerTool,
102
+ vision: visionTool,
103
+ sentiment: sentimentTool,
104
+ crossborder: crossborderTool,
105
+ product: productTool,
106
+ analytics: analyticsTool,
107
+ quickReport: quickReportTool
108
+ };
109
+
110
+ // Critical Operation Queue (Lane Queue)
111
+ this.queue = getCriticalQueue();
112
+ this.memory = getMemory();
113
+ }
114
+
115
+ /**
116
+ * Engine'i başlat
117
+ */
118
+ async initialize() {
119
+ log('INFO', 'Vantuz Engine v3.2 başlatılıyor...');
120
+
121
+ // Config ve env yükle
122
+ this._loadConfig();
123
+ this._loadEnv();
124
+
125
+ // Vantuz Gateway bağlantısı
126
+ try {
127
+ this.gateway = await getGateway();
128
+ if (this.gateway.isConnected()) {
129
+ log('INFO', 'Vantuz Gateway bağlı', this.gateway.getInfo());
130
+ } else if (this._shouldAutoStartGateway()) {
131
+ const started = await this.gateway.ensureRunning();
132
+ if (started.success) {
133
+ log('INFO', 'Vantuz Gateway otomatik başlatıldı', this.gateway.getInfo());
134
+ } else {
135
+ log('WARN', 'Gateway otomatik başlatılamadı', { error: started.error });
136
+ }
137
+ }
138
+ } catch (e) {
139
+ log('WARN', 'Gateway bağlantısı başarısız, direkt mod', { error: e.message });
140
+ }
141
+
142
+ // Channel Manager'ı başlat
143
+ this.channels = await getChannelManager();
144
+
145
+ // Platform Hub'ı başlat
146
+ await this._initPlatforms();
147
+
148
+ // Context oluştur (bağlı platformlardan veri çek)
149
+ await this._buildContext();
150
+
151
+ // Initialize and start EIA Monitor
152
+ this.eiaMonitor = getEIAMonitor(this.config, this.env);
153
+ await this.eiaMonitor.initMonitoringTasks(); // New line
154
+
155
+ // Multi-Agent Team
156
+ try {
157
+ this.team = new TeamModule(this);
158
+ await this.team.initialize();
159
+ } catch (e) {
160
+ log('WARN', 'Team module başlatılamadı', { error: e.message });
161
+ }
162
+
163
+ // Automation manager
164
+ this.automation = new AutomationManager(this);
165
+ this.automation.init();
166
+
167
+ // Gateway WS bridge (inbound)
168
+ if (this._shouldStartBridge()) {
169
+ try {
170
+ this.bridge = new OpenClawBridge(this, this.gateway);
171
+ this.bridge.start();
172
+ } catch (e) {
173
+ log('WARN', 'Gateway bridge başlatılamadı', { error: e.message });
174
+ }
175
+ }
176
+
177
+ this.initialized = true;
178
+ log('INFO', 'Vantuz Engine hazır', {
179
+ platforms: this.context.connectedPlatforms.length,
180
+ gateway: this.gateway?.isConnected() || false
181
+ });
182
+
183
+ return this;
184
+ }
185
+
186
+ /**
187
+ * Gelişmiş mesaj işleme (otomasyon + onay)
188
+ */
189
+ async handleMessage(message, meta = { channel: 'local', from: 'local' }) {
190
+ if (!this.initialized) await this.initialize();
191
+ if (this.automation) {
192
+ const result = await this.automation.handleMessage(message, meta);
193
+ if (result?.handled) {
194
+ return result.response;
195
+ }
196
+ }
197
+ return await this.chat(message);
198
+ }
199
+
200
+ /**
201
+ * Gateway otomatik başlatılsın mı?
202
+ */
203
+ _shouldAutoStartGateway() {
204
+ const envValue = this.env.VANTUZ_GATEWAY_AUTOSTART;
205
+ if (envValue !== undefined) {
206
+ return !['0', 'false', 'no'].includes(String(envValue).toLowerCase());
207
+ }
208
+ if (this.config && this.config.gatewayAutoStart !== undefined) {
209
+ return this.config.gatewayAutoStart !== false;
210
+ }
211
+ return true;
212
+ }
213
+
214
+ _shouldStartBridge() {
215
+ const envValue = this.env.VANTUZ_OPENCLAW_BRIDGE;
216
+ if (envValue !== undefined) {
217
+ return !['0', 'false', 'no'].includes(String(envValue).toLowerCase());
218
+ }
219
+ if (this.config && this.config.openclawBridge !== undefined) {
220
+ return this.config.openclawBridge !== false;
221
+ }
222
+ return true;
223
+ }
224
+
225
+ /**
226
+ * Config dosyasını yükle
227
+ */
228
+ _loadConfig() {
229
+ try {
230
+ if (fs.existsSync(CONFIG_JSON)) {
231
+ this.config = JSON.parse(fs.readFileSync(CONFIG_JSON, 'utf-8'));
232
+ }
233
+ } catch (e) {
234
+ log('ERROR', 'Config yüklenemedi', { error: e.message });
235
+ }
236
+ }
237
+
238
+ /**
239
+ * Environment değişkenlerini yükle
240
+ */
241
+ _loadEnv() {
242
+ try {
243
+ if (fs.existsSync(CONFIG_PATH)) {
244
+ const content = fs.readFileSync(CONFIG_PATH, 'utf-8');
245
+ content.split('\n').forEach(line => {
246
+ const match = line.match(/^([^=]+)=(.*)$/);
247
+ if (match) {
248
+ this.env[match[1].trim()] = match[2].trim();
249
+ }
250
+ });
251
+ }
252
+ } catch (e) {
253
+ log('ERROR', 'Env yüklenemedi', { error: e.message });
254
+ }
255
+ }
256
+
257
+ /**
258
+ * Platform API'lerini başlat
259
+ */
260
+ async _initPlatforms() {
261
+ const platformConfig = {};
262
+
263
+ for (const platformName in PLATFORM_CONFIG_MAP) {
264
+ const platformMap = PLATFORM_CONFIG_MAP[platformName];
265
+
266
+ if (platformMap.envPrefix && platformMap.keys) { // Handle all platforms with direct keys
267
+ const config = {};
268
+ let hasRequiredEnv = false;
269
+ for (const key of platformMap.keys) {
270
+ const upper = key.toUpperCase();
271
+ const snake = key.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toUpperCase();
272
+ const envKey = `${platformMap.envPrefix}_${upper}`;
273
+ const altEnvKey = `${platformMap.envPrefix}_${snake}`;
274
+ const value = this.env[envKey] || this.env[altEnvKey];
275
+ if (value) {
276
+ config[key] = value;
277
+ hasRequiredEnv = true;
278
+ }
279
+ }
280
+ if (hasRequiredEnv) {
281
+ platformConfig[platformName] = config;
282
+ }
283
+ }
284
+ }
285
+
286
+ // Platform Hub'ı başlat
287
+ if (Object.keys(platformConfig).length > 0) {
288
+ this.platforms = await platformHub.initAll(platformConfig);
289
+ log('INFO', 'Platform Hub başlatıldı', {
290
+ platforms: Object.keys(this.platforms)
291
+ });
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Bağlı platformlardan context oluştur
297
+ */
298
+ async _buildContext() {
299
+ this.context.connectedPlatforms = platformHub.getConnected();
300
+
301
+ for (const platform of this.context.connectedPlatforms) {
302
+ try {
303
+ const api = platformHub.resolve(platform);
304
+ if (api && typeof api.getProducts === 'function') {
305
+ const result = await api.getProducts({ page: 0, size: 10 });
306
+ if (result?.success) {
307
+ const data = result.data;
308
+ let products = [];
309
+ if (Array.isArray(data?.content)) products = data.content;
310
+ else if (Array.isArray(data)) products = data;
311
+ else if (Array.isArray(data?.productList?.product)) products = data.productList.product;
312
+ if (products.length > 0) {
313
+ this.context.products.push(...products.map(p => ({
314
+ ...p,
315
+ _platform: platform
316
+ })));
317
+ }
318
+ }
319
+ }
320
+ } catch (e) {
321
+ log('ERROR', `${platform} veri çekme hatası`, { error: e.message });
322
+ }
323
+ }
324
+ }
325
+
326
+ /**
327
+ * AI ile sohbet - Tool destekli
328
+ */
329
+ async chat(message) {
330
+ if (!this.initialized) await this.initialize();
331
+
332
+ // 1. Basit komut kontrolü (Tool çağırma)
333
+ const toolResult = await this._tryExecuteToolFromMessage(message);
334
+ if (toolResult) return toolResult;
335
+
336
+ // 1.5 Gelişmiş ajan (araç çağrıları)
337
+ const agentResult = await this._tryAgent(message);
338
+ if (agentResult) return agentResult;
339
+
340
+ // 2. Gateway üzerinden AI (Eğer varsa)
341
+ if (this.gateway?.isConnected()) {
342
+ try {
343
+ const gatewayResult = await this.gateway.chat(message, {
344
+ systemPrompt: this._buildContextInfo()
345
+ });
346
+ if (gatewayResult.success) return gatewayResult.response;
347
+ } catch (e) { }
348
+ }
349
+
350
+ // 3. Direkt API (Fallback)
351
+ const enrichedConfig = {
352
+ ...this.config,
353
+ aiProvider: this.env.AI_PROVIDER || this.config.aiProvider || 'gemini',
354
+ systemContext: this._buildContextInfo()
355
+ };
356
+
357
+ return await aiChat(message, enrichedConfig, this.env);
358
+ }
359
+
360
+ async _tryAgent(message) {
361
+ const mode = this.config?.agentMode || this.env.VANTUZ_AGENT_MODE;
362
+ if (!mode || mode === 'off') return null;
363
+
364
+ const systemPrompt = [
365
+ 'Sen Vantuz gelişmiş ajanısın.',
366
+ 'Gerekirse aşağıdaki araçlardan birini çağır:',
367
+ 'exec, readFile, listDir, httpGet, apiQuery',
368
+ 'Sadece JSON döndür.',
369
+ 'Şema: { "tool": "exec|readFile|listDir|httpGet|apiQuery", "args": { ... } }',
370
+ 'apiQuery args: { "platform": "n11|trendyol|hepsiburada|amazon|ciceksepeti|pazarama|pttavm", "action": "orders|products|stock|categories", "params": { ... } }',
371
+ 'Eğer araç gerekmezse: { "final": "cevap" }',
372
+ 'Dosya yollarını ve komutları kısa tut.'
373
+ ].join('\n');
374
+
375
+ const plan = await aiChat(message, {
376
+ aiProvider: this.config.aiProvider || 'gemini',
377
+ systemContext: systemPrompt
378
+ }, this.env);
379
+
380
+ const jsonMatch = plan.match(/\{[\s\S]*\}/);
381
+ if (!jsonMatch) return null;
382
+ let obj;
383
+ try { obj = JSON.parse(jsonMatch[0]); } catch { return null; }
384
+ if (obj.final) return obj.final;
385
+ if (!obj.tool) return null;
386
+
387
+ let toolResult;
388
+ if (obj.tool === 'apiQuery') {
389
+ toolResult = await this._runApiQuery(obj.args || {});
390
+ } else {
391
+ toolResult = await executeTool(obj.tool, obj.args || {}, this.config);
392
+ }
393
+ const followup = await aiChat(
394
+ `Kullanıcı mesajı: ${message}\nAraç çıktısı:\n${toolResult.output}\nCevap ver.`,
395
+ { aiProvider: this.config.aiProvider || 'gemini' },
396
+ this.env
397
+ );
398
+ return followup;
399
+ }
400
+
401
+ async _runApiQuery(args = {}) {
402
+ const platform = (args.platform || '').toLowerCase();
403
+ const action = (args.action || '').toLowerCase();
404
+ const params = args.params || {};
405
+ const api = platformHub.resolve(platform);
406
+ if (!api) return { success: false, output: 'Platform bulunamadı.' };
407
+
408
+ try {
409
+ if (action === 'orders' && api.getOrders) {
410
+ const result = await api.getOrders(params);
411
+ return { success: true, output: JSON.stringify(result?.data || result || {}, null, 2) };
412
+ }
413
+ if (action === 'products' && api.getProducts) {
414
+ const result = await api.getProducts(params);
415
+ return { success: true, output: JSON.stringify(result?.data || result || {}, null, 2) };
416
+ }
417
+ if (action === 'stock' && api.getProducts) {
418
+ const result = await api.getProducts(params);
419
+ return { success: true, output: JSON.stringify(result?.data || result || {}, null, 2) };
420
+ }
421
+ if (action === 'categories' && api.getTopCategories) {
422
+ const result = await api.getTopCategories(params);
423
+ return { success: true, output: JSON.stringify(result?.data || result || {}, null, 2) };
424
+ }
425
+ return { success: false, output: 'Bu platform için istenen action desteklenmiyor.' };
426
+ } catch (e) {
427
+ return { success: false, output: e.message };
428
+ }
429
+ }
430
+
431
+ /**
432
+ * Mesajdan Tool tespiti (Basit NLP)
433
+ */
434
+ async _tryExecuteToolFromMessage(message) {
435
+ const lower = message.toLowerCase().trim();
436
+ const normalized = lower
437
+ .replace(/[çÇ]/g, 'c')
438
+ .replace(/[ğĞ]/g, 'g')
439
+ .replace(/[ıİ]/g, 'i')
440
+ .replace(/[öÖ]/g, 'o')
441
+ .replace(/[şŞ]/g, 's')
442
+ .replace(/[üÜ]/g, 'u');
443
+
444
+ // Check for explicit commands
445
+ if (lower.startsWith('/')) {
446
+ const parts = lower.substring(1).split(' ');
447
+ const command = parts[0];
448
+ const args = parts.slice(1);
449
+
450
+ switch (command) {
451
+ case 'repricer':
452
+ case 'rakip':
453
+ case 'fiyat-analizi':
454
+ // In a real scenario, you'd parse args and pass them to repricerTool
455
+ return "Repricer aracı çalıştırılıyor... (Detaylı parametreler için /rakip komutunu kullanın)";
456
+ case 'stock':
457
+ case 'stok-durumu':
458
+ const stocks = await this.getStock();
459
+ return JSON.stringify(stocks.map(s => ({ platform: s.platform, items: s.products.length })), null, 2);
460
+ case 'help':
461
+ return "Kullanabileceğin komutlar: /rakip, /stok-durumu";
462
+ default:
463
+ return `Bilinmeyen komut: /${command}. Yardım için /help yazabilirsin.`;
464
+ }
465
+ }
466
+
467
+ // Natural language shortcuts (no hallucination)
468
+ if (
469
+ lower.includes('hangi pazaryerleri bağlı') ||
470
+ lower.includes('hangi pazaryeri bağlı') ||
471
+ lower.includes('hangi platformlar bağlı') ||
472
+ normalized.includes('hangi pazaryerleri bagli') ||
473
+ normalized.includes('hangi platformlar bagli')
474
+ ) {
475
+ const connected = this.context.connectedPlatforms;
476
+ if (connected.length === 0) return 'Şu an bağlı pazaryeri yok.';
477
+ return `Bağlı pazaryerleri: ${connected.map(p => p.toUpperCase()).join(', ')}`;
478
+ }
479
+
480
+ const orderKeywords = [
481
+ 'sipariş',
482
+ 'siparis'
483
+ ];
484
+ const hasOrderKeyword = orderKeywords.some(k => lower.includes(k) || normalized.includes(k));
485
+
486
+ if (hasOrderKeyword) {
487
+ const orders = await this.getOrders({ size: 100, allStatuses: true });
488
+ if (!orders || orders.length === 0) {
489
+ return 'Sipariş verisine ulaşılamadı. Lütfen platform API bağlantılarını kontrol edin.';
490
+ }
491
+
492
+ const active = orders.filter(o => this.isActiveStatus(o.status || o.shipmentPackageStatus || o.orderStatus));
493
+ const completed = orders.filter(o => !this.isActiveStatus(o.status || o.shipmentPackageStatus || o.orderStatus));
494
+
495
+ let message = '';
496
+ if (active.length > 0) {
497
+ const summary = this._summarizeOrdersByStatus(active);
498
+ message += `Şu an bağlı platformlardan gelen toplam ${active.length} YENİ/AKTİF sipariş var.${summary ? ` (${summary})` : ''}`;
499
+ } else {
500
+ message += 'Şu an aktif (yeni/hazırlanan) sipariş yok.';
501
+ }
502
+
503
+ if (completed.length > 0) {
504
+ const summary = this._summarizeOrdersByStatus(completed);
505
+ message += `\n(Geçmiş Siparişler: ${completed.length} adet - ${summary})`;
506
+ }
507
+
508
+ return message;
509
+ }
510
+
511
+ if (lower.includes('onaylanan')) {
512
+ const orders = await this.getOrders({ size: 100, status: 'Picking' });
513
+ return `Şu an onaylanan (Picking) ${orders.length} sipariş var.`;
514
+ }
515
+
516
+ if (lower.includes('kargoya verilmemiş') || lower.includes('henüz kargoya') || lower.includes('kargoya verilmedi') || normalized.includes('kargoya verilmemis')) {
517
+ const orders = await this.getOrders({ size: 100, status: 'Created' });
518
+ return `Şu an kargoya verilmemiş (Created) ${orders.length} sipariş var.`;
519
+ }
520
+
521
+ return null;
522
+ }
523
+
524
+ _summarizeOrdersByStatus(orders = []) {
525
+ if (!Array.isArray(orders) || orders.length === 0) return '';
526
+ const counts = {};
527
+ orders.forEach(o => {
528
+ const s = (o.status || o.shipmentPackageStatus || o.orderStatus || 'UNKNOWN').toString();
529
+ counts[s] = (counts[s] || 0) + 1;
530
+ });
531
+ const entries = Object.entries(counts)
532
+ .sort((a, b) => b[1] - a[1])
533
+ .map(([s, n]) => `${s}:${n}`);
534
+ return entries.join(', ');
535
+ }
536
+
537
+ /**
538
+ * Context bilgisi oluştur (AI system prompt için)
539
+ */
540
+ _buildContextInfo() {
541
+ const connected = this.context.connectedPlatforms;
542
+ let info = `\n\n--- MEVCUT SİSTEM DURUMU ---\n`;
543
+ info += `Bağlı Platformlar: ${connected.length > 0 ? connected.join(', ') : 'Hiçbiri'}\n`;
544
+ info += `Gateway: ${this.gateway?.isConnected() ? 'BAĞLI' : 'KOPUK'}\n`;
545
+ info += `Mevcut Toollar: Repricer, Vision, Sentiment, Analytics, CrossBorder\n`;
546
+
547
+ if (this.context.products.length > 0) {
548
+ info += `\nÖrnek Ürünler:\n`;
549
+ this.context.products.slice(0, 3).forEach(p => {
550
+ info += `- ${p.title} (${p._platform}): ${p.salePrice} TL\n`;
551
+ });
552
+ }
553
+ return info;
554
+ }
555
+
556
+ // --- Helper Methods ---
557
+
558
+ isActiveStatus(status) {
559
+ const s = String(status || '').toLowerCase();
560
+ return s === 'created' || s === 'picking' || s === 'unpacked' || s === 'shipped';
561
+ }
562
+
563
+ async getStock(platform = 'all') {
564
+ const results = [];
565
+ const targets = platform === 'all'
566
+ ? this.context.connectedPlatforms
567
+ : [platform];
568
+
569
+ for (const p of targets) {
570
+ try {
571
+ const api = platformHub.resolve(p);
572
+ if (api?.getProducts) {
573
+ const result = await api.getProducts({ page: 0, size: 50 });
574
+ if (result?.success) {
575
+ const products = result.data?.content || result.data || [];
576
+ results.push({
577
+ platform: p,
578
+ icon: platformHub.getIcon(p),
579
+ products: products.map(prod => ({
580
+ barcode: prod.barcode,
581
+ title: prod.title || prod.name,
582
+ stock: prod.quantity || prod.stock,
583
+ price: prod.salePrice || prod.price
584
+ }))
585
+ });
586
+ }
587
+ }
588
+ } catch (e) {
589
+ log('ERROR', `Stok çekme hatası: ${p}`, { error: e.message });
590
+ }
591
+ }
592
+ return results;
593
+ }
594
+
595
+ async getOrders(params = {}) {
596
+ return await platformHub.getAllOrders(params);
597
+ }
598
+
599
+ getStatus() {
600
+ const status = platformHub.getStatus();
601
+ const connected = this.context.connectedPlatforms;
602
+ const channelStatus = this.channels ? this.channels.getStatus() : {};
603
+ const gatewayInfo = this.gateway ? this.gateway.getInfo() : { connected: false };
604
+
605
+ return {
606
+ engine: this.initialized ? 'active' : 'inactive',
607
+ version: '3.2',
608
+ aiProvider: this.env.AI_PROVIDER || this.config.aiProvider || 'gemini',
609
+ gateway: gatewayInfo,
610
+ platforms: status,
611
+ channels: channelStatus,
612
+ connectedCount: connected.length,
613
+ totalPlatforms: 7,
614
+ productCount: this.context.products.length
615
+ };
616
+ }
617
+
618
+ async doctor() {
619
+ const status = this.getStatus();
620
+ return {
621
+ engine: this.initialized,
622
+ gateway: {
623
+ status: status.gateway.connected ? 'healthy' : 'unreachable',
624
+ ...status.gateway
625
+ },
626
+ platforms: status.platforms,
627
+ ai: {
628
+ provider: status.aiProvider,
629
+ keyConfigured: true,
630
+ gatewayFallback: status.gateway.connected
631
+ },
632
+ channels: status.channels
633
+ };
634
+ }
635
+ }
636
+
637
+ // Singleton instance
638
+ let engineInstance = null;
639
+
640
+ export async function getEngine() {
641
+ if (!engineInstance) {
642
+ engineInstance = new VantuzEngine();
643
+ await engineInstance.initialize();
644
+ }
645
+ return engineInstance;
646
+ }
647
+
648
+ export default VantuzEngine;