vantuz 3.3.7 β†’ 3.4.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.
@@ -0,0 +1,238 @@
1
+ // nodes/warehouse.js
2
+ // Warehouse Node β€” Lightweight hardware peripheral for Vantuz Gateway
3
+ // Connects to Gateway via WebSocket as a "node" role.
4
+ // Provides: camera.snap, barcode.scan, voice.listen commands.
5
+
6
+ import WebSocket from 'ws';
7
+ import fs from 'fs';
8
+ import path from 'path';
9
+ import { log } from '../core/ai-provider.js';
10
+
11
+ const DEFAULT_GATEWAY_URL = 'ws://localhost:18789';
12
+
13
+ class WarehouseNode {
14
+ constructor(options = {}) {
15
+ this.id = options.nodeId || `warehouse-${Date.now().toString(36)}`;
16
+ this.name = options.name || 'Depo Terminali';
17
+ this.gatewayUrl = options.gatewayUrl || DEFAULT_GATEWAY_URL;
18
+ this.token = options.token || process.env.OPENCLAW_GATEWAY_TOKEN || '';
19
+ this.ws = null;
20
+ this.connected = false;
21
+
22
+ // Capabilities this node exposes
23
+ this.capabilities = [
24
+ 'camera.snap', // Take a photo
25
+ 'camera.clip', // Record short video
26
+ 'barcode.scan', // Scan barcode (simulated via image)
27
+ 'location.get', // GPS / warehouse zone
28
+ 'status.report' // Node health status
29
+ ];
30
+
31
+ log('INFO', `WarehouseNode "${this.name}" created`, { id: this.id });
32
+ }
33
+
34
+ /**
35
+ * Connect to Gateway as a Node peripheral.
36
+ */
37
+ async connect() {
38
+ return new Promise((resolve, reject) => {
39
+ try {
40
+ this.ws = new WebSocket(this.gatewayUrl);
41
+
42
+ this.ws.on('open', () => {
43
+ // Send handshake frame
44
+ this.ws.send(JSON.stringify({
45
+ type: 'connect',
46
+ role: 'node',
47
+ nodeId: this.id,
48
+ name: this.name,
49
+ token: this.token,
50
+ capabilities: this.capabilities,
51
+ meta: {
52
+ platform: process.platform,
53
+ version: '1.0.0',
54
+ location: 'warehouse'
55
+ }
56
+ }));
57
+
58
+ this.connected = true;
59
+ log('INFO', `WarehouseNode connected to Gateway`, { url: this.gatewayUrl });
60
+ resolve(true);
61
+ });
62
+
63
+ this.ws.on('message', (data) => {
64
+ this._handleCommand(JSON.parse(data.toString()));
65
+ });
66
+
67
+ this.ws.on('close', () => {
68
+ this.connected = false;
69
+ log('WARN', 'WarehouseNode disconnected from Gateway');
70
+ // Auto-reconnect after 5s
71
+ setTimeout(() => this.connect().catch(() => { }), 5000);
72
+ });
73
+
74
+ this.ws.on('error', (err) => {
75
+ log('ERROR', 'WarehouseNode WebSocket error', { error: err.message });
76
+ reject(err);
77
+ });
78
+
79
+ } catch (e) {
80
+ reject(e);
81
+ }
82
+ });
83
+ }
84
+
85
+ /**
86
+ * Handle incoming commands from Gateway/Agent.
87
+ */
88
+ async _handleCommand(frame) {
89
+ const { type, command, requestId, params = {} } = frame;
90
+
91
+ if (type !== 'command') return;
92
+
93
+ log('INFO', `Node command received: ${command}`, { requestId, params });
94
+
95
+ let result;
96
+
97
+ switch (command) {
98
+ case 'camera.snap':
99
+ result = await this._cameraSnap(params);
100
+ break;
101
+
102
+ case 'barcode.scan':
103
+ result = await this._barcodeScan(params);
104
+ break;
105
+
106
+ case 'status.report':
107
+ result = this._statusReport();
108
+ break;
109
+
110
+ default:
111
+ result = { success: false, error: `Unknown command: ${command}` };
112
+ }
113
+
114
+ // Send response back to Gateway
115
+ this._sendResponse(requestId, result);
116
+ }
117
+
118
+ /**
119
+ * Capture an image from camera.
120
+ * In production: uses device camera API.
121
+ * Prototype: reads from a configured watch directory.
122
+ */
123
+ async _cameraSnap(params = {}) {
124
+ const watchDir = params.watchDir || path.join(process.cwd(), 'warehouse', 'camera');
125
+
126
+ // Prototype: look for the latest image in watch directory
127
+ if (!fs.existsSync(watchDir)) {
128
+ fs.mkdirSync(watchDir, { recursive: true });
129
+ return {
130
+ success: false,
131
+ error: `Kamera klasârü oluşturuldu: ${watchDir}. Fotoğraf dosyasını buraya koyun.`
132
+ };
133
+ }
134
+
135
+ const files = fs.readdirSync(watchDir)
136
+ .filter(f => /\.(jpg|jpeg|png|webp)$/i.test(f))
137
+ .map(f => ({
138
+ name: f,
139
+ path: path.join(watchDir, f),
140
+ time: fs.statSync(path.join(watchDir, f)).mtimeMs
141
+ }))
142
+ .sort((a, b) => b.time - a.time);
143
+
144
+ if (files.length === 0) {
145
+ return {
146
+ success: false,
147
+ error: 'Kamera klasâründe fotoğraf bulunamadı.'
148
+ };
149
+ }
150
+
151
+ const latest = files[0];
152
+ const buffer = fs.readFileSync(latest.path);
153
+ const base64 = buffer.toString('base64');
154
+
155
+ log('INFO', `Camera snap: ${latest.name}`, { size: buffer.length });
156
+
157
+ return {
158
+ success: true,
159
+ image: `data:image/jpeg;base64,${base64}`,
160
+ filename: latest.name,
161
+ capturedAt: new Date().toISOString()
162
+ };
163
+ }
164
+
165
+ /**
166
+ * Scan barcode from latest camera image.
167
+ * In production: uses barcode scanning library.
168
+ * Prototype: extracts from filename convention (e.g., "barcode_123456.jpg").
169
+ */
170
+ async _barcodeScan(params = {}) {
171
+ const snap = await this._cameraSnap(params);
172
+ if (!snap.success) return snap;
173
+
174
+ // Prototype: extract barcode from filename
175
+ const match = snap.filename.match(/barcode[_-]?(\d+)/i);
176
+ if (match) {
177
+ return {
178
+ success: true,
179
+ barcode: match[1],
180
+ format: 'CODE128',
181
+ source: 'filename',
182
+ image: snap.image
183
+ };
184
+ }
185
+
186
+ // In production, this would use a barcode scanning library
187
+ return {
188
+ success: true,
189
+ barcode: null,
190
+ note: 'Barkod tespit edilemedi. Üretim sürümünde barkod kütüphanesi kullanılacak.',
191
+ image: snap.image
192
+ };
193
+ }
194
+
195
+ /**
196
+ * Report node status / health.
197
+ */
198
+ _statusReport() {
199
+ return {
200
+ success: true,
201
+ nodeId: this.id,
202
+ name: this.name,
203
+ connected: this.connected,
204
+ uptime: process.uptime(),
205
+ memoryMB: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
206
+ capabilities: this.capabilities,
207
+ platform: process.platform
208
+ };
209
+ }
210
+
211
+ /**
212
+ * Send response frame back to Gateway.
213
+ */
214
+ _sendResponse(requestId, result) {
215
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
216
+ log('WARN', 'Cannot send response, WebSocket not open');
217
+ return;
218
+ }
219
+
220
+ this.ws.send(JSON.stringify({
221
+ type: 'response',
222
+ requestId,
223
+ ...result
224
+ }));
225
+ }
226
+
227
+ /**
228
+ * Disconnect from Gateway.
229
+ */
230
+ disconnect() {
231
+ if (this.ws) {
232
+ this.ws.close();
233
+ this.connected = false;
234
+ }
235
+ }
236
+ }
237
+
238
+ export default WarehouseNode;
package/onboard.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,88 +1,49 @@
1
- {
2
- "name": "vantuz",
3
- "version": "3.3.7",
4
- "description": "Yapay Zeka Destekli E-Ticaret YΓΆnetim Platformu - 7 Pazaryeri + WhatsApp/Telegram",
5
- "type": "module",
6
- "main": "cli.js",
7
- "bin": {
8
- "vantuz": "cli.js",
9
- "vantuz-onboard": "onboard.js"
10
- },
11
- "scripts": {
12
- "start": "node cli.js tui",
13
- "tui": "node cli.js tui",
14
- "config": "node cli.js config",
15
- "status": "node cli.js status",
16
- "postinstall": "echo \u0027Vantuz kuruldu! Baslatmak icin: npx vantuz-onboard\u0027",
17
- "test": "node --test",
18
- "lint": "eslint plugins/"
19
- },
20
- "keywords": [
21
- "ecommerce",
22
- "e-ticaret",
23
- "trendyol",
24
- "hepsiburada",
25
- "amazon",
26
- "n11",
27
- "ciceksepeti",
28
- "pttavm",
29
- "pazarama",
30
- "marketplace",
31
- "pazaryeri",
32
- "ai",
33
- "yapay-zeka",
34
- "repricer",
35
- "fiyatlama",
36
- "whatsapp",
37
- "telegram",
38
- "enterprise",
39
- "gateway",
40
- "management",
41
- "cli"
42
- ],
43
- "author": "Vantuz",
44
- "license": "SEE LICENSE IN LICENSE",
45
- "repository": {
46
- "type": "git",
47
- "url": "git+https://github.com/cokdalazimdegil/vantuz.git"
48
- },
49
- "homepage": "https://nuricanavsar.com/public/vantuz",
50
- "bugs": {
51
- "url": "https://github.com/cokdalazimdegil/vantuz/issues"
52
- },
53
- "dependencies": {
54
- "axios": "^1.13.5",
55
- "cors": "^2.8.6",
56
- "cron": "^4.4.0",
57
- "dotenv": "^16.0.0",
58
- "express": "^5.2.1",
59
- "openclaw": "^0.0.1",
60
- "playwright": "^1.58.2",
61
- "sqlite": "^5.1.1",
62
- "sqlite3": "^5.0.2",
63
- "xml2js": "^0.6.2"
64
- },
65
- "devDependencies": {
66
- "eslint": "^8.0.0"
67
- },
68
- "os": [
69
- "darwin",
70
- "linux",
71
- "win32"
72
- ],
73
- "engines": {
74
- "node": "\u003e=18.0.0"
75
- },
76
- "files": [
77
- "cli.js",
78
- "onboard.js",
79
- "config.js",
80
- "core",
81
- "server",
82
- "platforms",
83
- "plugins",
84
- "start.bat",
85
- "LICENSE",
86
- "README.md"
87
- ]
1
+ {
2
+ "name": "vantuz",
3
+ "version": "3.4.1",
4
+ "description": "Yapay Zeka Destekli Yeni Nesil E-Ticaret YΓΆnetim Platformu (CLI)",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "vantuz": "index.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node index.js",
11
+ "postinstall": "npm rebuild sqlite3",
12
+ "test": "echo \"Error: no test specified\" && exit 1"
13
+ },
14
+ "keywords": [
15
+ "ecommerce",
16
+ "trendyol",
17
+ "hepsiburada",
18
+ "amazon",
19
+ "n11",
20
+ "marketplace",
21
+ "ai",
22
+ "cli"
23
+ ],
24
+ "author": "Nuri Can Avşar <nuricanavsar2000@gmail.com>",
25
+ "license": "Commercial",
26
+ "dependencies": {
27
+ "axios": "^1.6.0",
28
+ "boxen": "^5.1.2",
29
+ "chalk": "^4.1.2",
30
+ "conf": "^10.2.0",
31
+ "console-clear": "^1.1.1",
32
+ "dotenv": "^16.0.0",
33
+ "figlet": "^1.5.0",
34
+ "inquirer": "^8.2.0",
35
+ "ora": "^5.4.1",
36
+ "pkg": "^5.8.1",
37
+ "sequelize": "^6.37.7",
38
+ "sqlite3": "^5.1.7",
39
+ "table": "^6.8.0"
40
+ },
41
+ "os": [
42
+ "darwin",
43
+ "linux",
44
+ "win32"
45
+ ],
46
+ "engines": {
47
+ "node": ">=16.0.0"
48
+ }
88
49
  }
@@ -1,13 +1,8 @@
1
- export default {
1
+ module.exports = {
2
2
  name: 'Amazon',
3
- icon: '🟑', // Yellow circle icon for Amazon
4
- description: 'Global E-ticaret Platformu',
5
3
  requiredFields: [
6
- { key: 'sellerId', label: 'Seller ID', env: 'AMAZON_SELLER_ID' },
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' }
4
+ { key: 'sellerId', label: 'Seller ID' },
5
+ { key: 'authToken', label: 'Auth Token' }
11
6
  ],
12
7
  async getOrders(creds) {
13
8
  // Stub
@@ -1,10 +1,7 @@
1
- export default {
1
+ module.exports = {
2
2
  name: 'Γ‡iΓ§ekSepeti',
3
- icon: '🌸', // Flower icon for Γ‡iΓ§ekSepeti
4
- description: 'Entegre Γ‡evrimiΓ§i Γ‡iΓ§ek ve Hediye Platformu',
5
3
  requiredFields: [
6
- { key: 'apiKey', label: 'API Key', env: 'CICEKSEPETI_API_KEY' },
7
- { key: 'supplierId', label: 'Supplier ID', env: 'CICEKSEPETI_SUPPLIER_ID' }
4
+ { key: 'apiKey', label: 'API Key' }
8
5
  ],
9
6
  async getOrders(creds) {
10
7
  // Stub
@@ -1,11 +1,9 @@
1
- export default {
1
+ module.exports = {
2
2
  name: 'Hepsiburada',
3
- icon: '🟣', // Purple circle icon for Hepsiburada
4
- description: 'PopΓΌler E-ticaret Platformu',
5
3
  requiredFields: [
6
- { key: 'merchantId', label: 'Merchant ID', env: 'HEPSIBURADA_MERCHANT_ID' },
7
- { key: 'username', label: 'Username', env: 'HEPSIBURADA_USERNAME' },
8
- { key: 'password', label: 'Password', env: 'HEPSIBURADA_PASSWORD' }
4
+ { key: 'merchantId', label: 'Merchant ID' },
5
+ { key: 'username', label: 'Username' },
6
+ { key: 'password', label: 'Password' }
9
7
  ],
10
8
  async getOrders(creds) {
11
9
  // Stub
package/platforms/n11.js CHANGED
@@ -1,10 +1,8 @@
1
- export default {
1
+ module.exports = {
2
2
  name: 'N11',
3
- icon: 'πŸ”΅', // Blue circle icon for N11
4
- description: 'Alternatif E-ticaret Platformu',
5
3
  requiredFields: [
6
- { key: 'apiKey', label: 'App Key', env: 'N11_API_KEY' },
7
- { key: 'apiSecret', label: 'App Secret', env: 'N11_API_SECRET' }
4
+ { key: 'apiKey', label: 'API Key' },
5
+ { key: 'apiSecret', label: 'API Secret' }
8
6
  ],
9
7
  async getOrders(creds) {
10
8
  // Stub
@@ -1,10 +1,7 @@
1
- export default {
1
+ module.exports = {
2
2
  name: 'Pazarama',
3
- icon: 'πŸ›’', // Shopping cart icon for Pazarama
4
- description: 'Yeni Nesil Mobil Alışveriş Platformu',
5
3
  requiredFields: [
6
- { key: 'clientId', label: 'Client ID', env: 'PAZARAMA_CLIENT_ID' },
7
- { key: 'clientSecret', label: 'Client Secret', env: 'PAZARAMA_CLIENT_SECRET' }
4
+ { key: 'apiKey', label: 'API Key' }
8
5
  ],
9
6
  async getOrders(creds) {
10
7
  // Stub
@@ -1,7 +1,7 @@
1
- export default {
1
+ const axios = require('axios');
2
+
3
+ module.exports = {
2
4
  name: 'Trendyol',
3
- icon: '🟠', // Orange circle icon for Trendyol
4
- description: 'TΓΌrkiye\'nin En BΓΌyΓΌk E-ticaret Platformu',
5
5
  requiredFields: [
6
6
  { key: 'supplierId', label: 'Supplier ID', env: 'TRENDYOL_SUPPLIER_ID' },
7
7
  { key: 'apiKey', label: 'API Key', env: 'TRENDYOL_API_KEY' },
@@ -347,6 +347,54 @@ export default function (api) {
347
347
  }
348
348
  });
349
349
 
350
+ // πŸ‘₯ Multi-Agent Team Command
351
+ api.registerCommand({
352
+ name: 'team',
353
+ description: 'Yapay Zeka Takımı ile konuş (Milo, Josh, Marketing, Dev)',
354
+ acceptsArgs: true,
355
+ handler: async (ctx) => {
356
+ // Lazy load to avoid circular deps or early init issues
357
+ const TeamModule = (await import('../../modules/team/index.js')).default;
358
+ const team = new TeamModule(api);
359
+ await team.initialize();
360
+
361
+ const args = ctx.args ? ctx.args.trim().split(' ') : [];
362
+ const subCommand = args[0];
363
+
364
+ if (!subCommand) {
365
+ return { text: 'Komutlar: /team chat [agent] [mesaj], /team status, /team broadcast [mesaj]' };
366
+ }
367
+
368
+ if (subCommand === 'chat') {
369
+ const agentName = args[1];
370
+ const message = args.slice(2).join(' ');
371
+ if (!agentName || !message) return { text: 'KullanΔ±m: /team chat [milo|josh|marketing|dev] [mesaj]' };
372
+
373
+ const response = await team.chat(agentName, message);
374
+ return { text: `**@${agentName}**: ${response}` };
375
+ }
376
+
377
+ if (subCommand === 'broadcast') {
378
+ const message = args.slice(1).join(' ');
379
+ if (!message) return { text: 'Mesaj yazΔ±n.' };
380
+
381
+ const results = await team.broadcast(message);
382
+ let report = 'πŸ“’ **TakΔ±m YanΔ±tlarΔ±**\n\n';
383
+ for (const [name, res] of Object.entries(results)) {
384
+ report += `**@${name}**: ${res}\n\n`;
385
+ }
386
+ return { text: report };
387
+ }
388
+
389
+ if (subCommand === 'status') {
390
+ const memory = team.getSharedMemory().getEverything();
391
+ return { text: `πŸ“ **TakΔ±m Durumu**\n\n**Hedefler:**\n${memory.goals}\n\n**Durum:**\n${memory.status}` };
392
+ }
393
+
394
+ return { text: 'GeΓ§ersiz komut. KullanΔ±labilir: chat, broadcast, status' };
395
+ }
396
+ });
397
+
350
398
  // ═══════════════════════════════════════════════════════════════════════════
351
399
  // βš™οΈ SERVICES - Arka plan servisleri
352
400
  // ═══════════════════════════════════════════════════════════════════════════
Binary file