vantuz 3.4.2 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +45 -45
- package/admin-keygen.js +51 -0
- package/cli.js +685 -585
- package/config.js +733 -733
- package/core/agent-loop.js +190 -190
- package/core/ai-provider.js +298 -261
- package/core/automation.js +523 -523
- package/core/brand-analyst.js +101 -0
- package/core/channels.js +167 -167
- package/core/dashboard.js +230 -230
- package/core/database.js +135 -37
- package/core/eia-monitor.js +3 -1
- package/core/engine.js +648 -636
- package/core/gateway.js +447 -447
- package/core/learning.js +214 -214
- package/core/license.js +113 -0
- package/core/marketplace-adapter.js +168 -168
- package/core/memory.js +190 -190
- package/core/migrations/001-initial-schema.sql +1 -1
- package/core/queue.js +120 -120
- package/core/self-healer.js +314 -314
- package/core/unified-product.js +214 -214
- package/core/vision-service.js +113 -113
- package/index.js +217 -174
- package/modules/crm/sentiment-crm.js +231 -231
- package/modules/healer/listing-healer.js +201 -201
- package/modules/oracle/predictor.js +214 -214
- package/modules/researcher/agent.js +169 -169
- package/modules/team/agents/base.js +92 -92
- package/modules/team/agents/dev.js +33 -33
- package/modules/team/agents/josh.js +40 -40
- package/modules/team/agents/marketing.js +33 -33
- package/modules/team/agents/milo.js +36 -36
- package/modules/team/index.js +78 -78
- package/modules/team/shared-memory.js +87 -87
- package/modules/war-room/competitor-tracker.js +250 -250
- package/modules/war-room/pricing-engine.js +308 -308
- package/nodes/warehouse.js +238 -238
- package/onboard.js +1 -1
- package/package.json +7 -5
- package/platforms/pttavm.js +14 -14
- package/plugins/vantuz/index.js +528 -528
- package/plugins/vantuz/memory/hippocampus.js +465 -465
- package/plugins/vantuz/package.json +20 -20
- package/plugins/vantuz/platforms/_template.js +118 -118
- package/plugins/vantuz/platforms/amazon.js +236 -236
- package/plugins/vantuz/platforms/ciceksepeti.js +166 -166
- package/plugins/vantuz/platforms/hepsiburada.js +180 -180
- package/plugins/vantuz/platforms/index.js +165 -165
- package/plugins/vantuz/platforms/n11.js +229 -229
- package/plugins/vantuz/platforms/pazarama.js +154 -154
- package/plugins/vantuz/platforms/pttavm.js +127 -127
- package/plugins/vantuz/platforms/trendyol.js +326 -326
- package/plugins/vantuz/services/alerts.js +253 -253
- package/plugins/vantuz/services/license.js +34 -34
- package/plugins/vantuz/services/scheduler.js +232 -232
- package/plugins/vantuz/tools/analytics.js +152 -152
- package/plugins/vantuz/tools/crossborder.js +187 -187
- package/plugins/vantuz/tools/nl-parser.js +211 -211
- package/plugins/vantuz/tools/product.js +110 -110
- package/plugins/vantuz/tools/quick-report.js +175 -175
- package/plugins/vantuz/tools/repricer.js +314 -314
- package/plugins/vantuz/tools/sentiment.js +115 -115
- package/plugins/vantuz/tools/vision.js +257 -257
- package/private.pem +28 -0
- package/public.pem +9 -0
- package/server/app.js +260 -260
- package/server/public/index.html +514 -514
- package/start.bat +33 -33
- package/vantuz.sqlite +0 -0
package/core/learning.js
CHANGED
|
@@ -1,214 +1,214 @@
|
|
|
1
|
-
// core/learning.js
|
|
2
|
-
// Reinforcement Learning Module for Vantuz OS V2
|
|
3
|
-
// Weighted scoring system — tracks AI decisions and adjusts behavior.
|
|
4
|
-
|
|
5
|
-
import fs from 'fs';
|
|
6
|
-
import path from 'path';
|
|
7
|
-
import os from 'os';
|
|
8
|
-
import { log } from './ai-provider.js';
|
|
9
|
-
|
|
10
|
-
const LEARNING_FILE = path.join(os.homedir(), '.vantuz', 'memory', 'learning.json');
|
|
11
|
-
|
|
12
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
13
|
-
// WEIGHTED SCORE DEFINITIONS
|
|
14
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
15
|
-
|
|
16
|
-
const SCORE_WEIGHTS = {
|
|
17
|
-
// Positive Outcomes (Ödül)
|
|
18
|
-
'successful_price_update': +1,
|
|
19
|
-
'successful_stock_update': +1,
|
|
20
|
-
'good_prediction': +2,
|
|
21
|
-
'user_approval': +3,
|
|
22
|
-
'successful_auto_reply': +1,
|
|
23
|
-
'sale_after_optimization': +2,
|
|
24
|
-
|
|
25
|
-
// Negative Outcomes (Ceza)
|
|
26
|
-
'price_increase_rejected': -2,
|
|
27
|
-
'stock_error': -5, // Stok hataları kritik
|
|
28
|
-
'user_rejection': -3,
|
|
29
|
-
'wrong_prediction': -1,
|
|
30
|
-
'listing_error': -2,
|
|
31
|
-
'kill_switch_triggered': -4,
|
|
32
|
-
'escalated_customer': -2,
|
|
33
|
-
|
|
34
|
-
// Custom (Kullanıcı tanımlı)
|
|
35
|
-
'custom_positive': +1,
|
|
36
|
-
'custom_negative': -1
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
40
|
-
// AUTONOMOUS MODE CONTROL
|
|
41
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
42
|
-
|
|
43
|
-
const AUTONOMY_THRESHOLD = -10; // Below this → manual mode
|
|
44
|
-
|
|
45
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
46
|
-
// LEARNING MODULE
|
|
47
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
48
|
-
|
|
49
|
-
class LearningModule {
|
|
50
|
-
constructor() {
|
|
51
|
-
this.data = this._load();
|
|
52
|
-
log('INFO', 'LearningModule initialized', {
|
|
53
|
-
netScore: this.data.netScore,
|
|
54
|
-
totalEvents: this.data.events.length,
|
|
55
|
-
autonomousMode: this.isAutonomous()
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
_load() {
|
|
60
|
-
try {
|
|
61
|
-
if (fs.existsSync(LEARNING_FILE)) {
|
|
62
|
-
return JSON.parse(fs.readFileSync(LEARNING_FILE, 'utf-8'));
|
|
63
|
-
}
|
|
64
|
-
} catch (e) { /* ignore */ }
|
|
65
|
-
return {
|
|
66
|
-
netScore: 0,
|
|
67
|
-
events: [],
|
|
68
|
-
autonomousModeOverride: null, // null = auto, true/false = manual override
|
|
69
|
-
categoryScores: {} // per-category running totals
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
_save() {
|
|
74
|
-
const dir = path.dirname(LEARNING_FILE);
|
|
75
|
-
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
76
|
-
const tmp = LEARNING_FILE + '.tmp';
|
|
77
|
-
fs.writeFileSync(tmp, JSON.stringify(this.data, null, 2), 'utf-8');
|
|
78
|
-
fs.renameSync(tmp, LEARNING_FILE);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Record a learning event.
|
|
83
|
-
* @param {string} eventType - Event type (must be in SCORE_WEIGHTS or 'custom_*').
|
|
84
|
-
* @param {string} context - Human-readable context.
|
|
85
|
-
* @param {string} category - Category for grouping (e.g., 'pricing', 'stock').
|
|
86
|
-
*/
|
|
87
|
-
record(eventType, context = '', category = 'general') {
|
|
88
|
-
const weight = SCORE_WEIGHTS[eventType];
|
|
89
|
-
if (weight === undefined) {
|
|
90
|
-
log('WARN', `Unknown learning event type: ${eventType}`);
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const event = {
|
|
95
|
-
type: eventType,
|
|
96
|
-
weight,
|
|
97
|
-
context,
|
|
98
|
-
category,
|
|
99
|
-
timestamp: new Date().toISOString()
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
this.data.events.push(event);
|
|
103
|
-
this.data.netScore += weight;
|
|
104
|
-
|
|
105
|
-
// Category scoring
|
|
106
|
-
if (!this.data.categoryScores[category]) {
|
|
107
|
-
this.data.categoryScores[category] = 0;
|
|
108
|
-
}
|
|
109
|
-
this.data.categoryScores[category] += weight;
|
|
110
|
-
|
|
111
|
-
// Trim old events (keep last 500)
|
|
112
|
-
if (this.data.events.length > 500) {
|
|
113
|
-
this.data.events = this.data.events.slice(-500);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
this._save();
|
|
117
|
-
|
|
118
|
-
// Check autonomy
|
|
119
|
-
if (!this.isAutonomous()) {
|
|
120
|
-
log('WARN', `⚠️ OTONOM MOD KAPANDI! Net skor: ${this.data.netScore} (eşik: ${AUTONOMY_THRESHOLD}). Manuel onay gerekiyor.`);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
log('INFO', `Learning: ${eventType} (${weight > 0 ? '+' : ''}${weight})`, {
|
|
124
|
-
context, netScore: this.data.netScore
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
return event;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Is the system in autonomous mode?
|
|
132
|
-
*/
|
|
133
|
-
isAutonomous() {
|
|
134
|
-
// Manual override takes precedence
|
|
135
|
-
if (this.data.autonomousModeOverride !== null) {
|
|
136
|
-
return this.data.autonomousModeOverride;
|
|
137
|
-
}
|
|
138
|
-
return this.data.netScore >= AUTONOMY_THRESHOLD;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Force autonomous mode on/off (manual override).
|
|
143
|
-
*/
|
|
144
|
-
setAutonomousMode(enabled) {
|
|
145
|
-
this.data.autonomousModeOverride = enabled;
|
|
146
|
-
this._save();
|
|
147
|
-
log('INFO', `Autonomous mode manually set to: ${enabled}`);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Clear the manual override (revert to score-based control).
|
|
152
|
-
*/
|
|
153
|
-
clearOverride() {
|
|
154
|
-
this.data.autonomousModeOverride = null;
|
|
155
|
-
this._save();
|
|
156
|
-
log('INFO', 'Autonomous mode override cleared — score-based control active');
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Get net score.
|
|
161
|
-
*/
|
|
162
|
-
getNetScore() {
|
|
163
|
-
return this.data.netScore;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Get per-category breakdown.
|
|
168
|
-
*/
|
|
169
|
-
getCategoryScores() {
|
|
170
|
-
return { ...this.data.categoryScores };
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Get recent events.
|
|
175
|
-
*/
|
|
176
|
-
getRecentEvents(limit = 20) {
|
|
177
|
-
return this.data.events.slice(-limit);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Reset score (nuclear option).
|
|
182
|
-
*/
|
|
183
|
-
reset() {
|
|
184
|
-
this.data.netScore = 0;
|
|
185
|
-
this.data.events = [];
|
|
186
|
-
this.data.categoryScores = {};
|
|
187
|
-
this.data.autonomousModeOverride = null;
|
|
188
|
-
this._save();
|
|
189
|
-
log('INFO', 'Learning module reset');
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
getStatus() {
|
|
193
|
-
return {
|
|
194
|
-
netScore: this.data.netScore,
|
|
195
|
-
autonomous: this.isAutonomous(),
|
|
196
|
-
threshold: AUTONOMY_THRESHOLD,
|
|
197
|
-
override: this.data.autonomousModeOverride,
|
|
198
|
-
totalEvents: this.data.events.length,
|
|
199
|
-
categoryScores: this.data.categoryScores
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
let learningInstance = null;
|
|
205
|
-
|
|
206
|
-
export function getLearning() {
|
|
207
|
-
if (!learningInstance) {
|
|
208
|
-
learningInstance = new LearningModule();
|
|
209
|
-
}
|
|
210
|
-
return learningInstance;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
export { SCORE_WEIGHTS, AUTONOMY_THRESHOLD };
|
|
214
|
-
export default LearningModule;
|
|
1
|
+
// core/learning.js
|
|
2
|
+
// Reinforcement Learning Module for Vantuz OS V2
|
|
3
|
+
// Weighted scoring system — tracks AI decisions and adjusts behavior.
|
|
4
|
+
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import os from 'os';
|
|
8
|
+
import { log } from './ai-provider.js';
|
|
9
|
+
|
|
10
|
+
const LEARNING_FILE = path.join(os.homedir(), '.vantuz', 'memory', 'learning.json');
|
|
11
|
+
|
|
12
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
13
|
+
// WEIGHTED SCORE DEFINITIONS
|
|
14
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
15
|
+
|
|
16
|
+
const SCORE_WEIGHTS = {
|
|
17
|
+
// Positive Outcomes (Ödül)
|
|
18
|
+
'successful_price_update': +1,
|
|
19
|
+
'successful_stock_update': +1,
|
|
20
|
+
'good_prediction': +2,
|
|
21
|
+
'user_approval': +3,
|
|
22
|
+
'successful_auto_reply': +1,
|
|
23
|
+
'sale_after_optimization': +2,
|
|
24
|
+
|
|
25
|
+
// Negative Outcomes (Ceza)
|
|
26
|
+
'price_increase_rejected': -2,
|
|
27
|
+
'stock_error': -5, // Stok hataları kritik
|
|
28
|
+
'user_rejection': -3,
|
|
29
|
+
'wrong_prediction': -1,
|
|
30
|
+
'listing_error': -2,
|
|
31
|
+
'kill_switch_triggered': -4,
|
|
32
|
+
'escalated_customer': -2,
|
|
33
|
+
|
|
34
|
+
// Custom (Kullanıcı tanımlı)
|
|
35
|
+
'custom_positive': +1,
|
|
36
|
+
'custom_negative': -1
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
40
|
+
// AUTONOMOUS MODE CONTROL
|
|
41
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
42
|
+
|
|
43
|
+
const AUTONOMY_THRESHOLD = -10; // Below this → manual mode
|
|
44
|
+
|
|
45
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
46
|
+
// LEARNING MODULE
|
|
47
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
48
|
+
|
|
49
|
+
class LearningModule {
|
|
50
|
+
constructor() {
|
|
51
|
+
this.data = this._load();
|
|
52
|
+
log('INFO', 'LearningModule initialized', {
|
|
53
|
+
netScore: this.data.netScore,
|
|
54
|
+
totalEvents: this.data.events.length,
|
|
55
|
+
autonomousMode: this.isAutonomous()
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
_load() {
|
|
60
|
+
try {
|
|
61
|
+
if (fs.existsSync(LEARNING_FILE)) {
|
|
62
|
+
return JSON.parse(fs.readFileSync(LEARNING_FILE, 'utf-8'));
|
|
63
|
+
}
|
|
64
|
+
} catch (e) { /* ignore */ }
|
|
65
|
+
return {
|
|
66
|
+
netScore: 0,
|
|
67
|
+
events: [],
|
|
68
|
+
autonomousModeOverride: null, // null = auto, true/false = manual override
|
|
69
|
+
categoryScores: {} // per-category running totals
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
_save() {
|
|
74
|
+
const dir = path.dirname(LEARNING_FILE);
|
|
75
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
76
|
+
const tmp = LEARNING_FILE + '.tmp';
|
|
77
|
+
fs.writeFileSync(tmp, JSON.stringify(this.data, null, 2), 'utf-8');
|
|
78
|
+
fs.renameSync(tmp, LEARNING_FILE);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Record a learning event.
|
|
83
|
+
* @param {string} eventType - Event type (must be in SCORE_WEIGHTS or 'custom_*').
|
|
84
|
+
* @param {string} context - Human-readable context.
|
|
85
|
+
* @param {string} category - Category for grouping (e.g., 'pricing', 'stock').
|
|
86
|
+
*/
|
|
87
|
+
record(eventType, context = '', category = 'general') {
|
|
88
|
+
const weight = SCORE_WEIGHTS[eventType];
|
|
89
|
+
if (weight === undefined) {
|
|
90
|
+
log('WARN', `Unknown learning event type: ${eventType}`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const event = {
|
|
95
|
+
type: eventType,
|
|
96
|
+
weight,
|
|
97
|
+
context,
|
|
98
|
+
category,
|
|
99
|
+
timestamp: new Date().toISOString()
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
this.data.events.push(event);
|
|
103
|
+
this.data.netScore += weight;
|
|
104
|
+
|
|
105
|
+
// Category scoring
|
|
106
|
+
if (!this.data.categoryScores[category]) {
|
|
107
|
+
this.data.categoryScores[category] = 0;
|
|
108
|
+
}
|
|
109
|
+
this.data.categoryScores[category] += weight;
|
|
110
|
+
|
|
111
|
+
// Trim old events (keep last 500)
|
|
112
|
+
if (this.data.events.length > 500) {
|
|
113
|
+
this.data.events = this.data.events.slice(-500);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this._save();
|
|
117
|
+
|
|
118
|
+
// Check autonomy
|
|
119
|
+
if (!this.isAutonomous()) {
|
|
120
|
+
log('WARN', `⚠️ OTONOM MOD KAPANDI! Net skor: ${this.data.netScore} (eşik: ${AUTONOMY_THRESHOLD}). Manuel onay gerekiyor.`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
log('INFO', `Learning: ${eventType} (${weight > 0 ? '+' : ''}${weight})`, {
|
|
124
|
+
context, netScore: this.data.netScore
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
return event;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Is the system in autonomous mode?
|
|
132
|
+
*/
|
|
133
|
+
isAutonomous() {
|
|
134
|
+
// Manual override takes precedence
|
|
135
|
+
if (this.data.autonomousModeOverride !== null) {
|
|
136
|
+
return this.data.autonomousModeOverride;
|
|
137
|
+
}
|
|
138
|
+
return this.data.netScore >= AUTONOMY_THRESHOLD;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Force autonomous mode on/off (manual override).
|
|
143
|
+
*/
|
|
144
|
+
setAutonomousMode(enabled) {
|
|
145
|
+
this.data.autonomousModeOverride = enabled;
|
|
146
|
+
this._save();
|
|
147
|
+
log('INFO', `Autonomous mode manually set to: ${enabled}`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Clear the manual override (revert to score-based control).
|
|
152
|
+
*/
|
|
153
|
+
clearOverride() {
|
|
154
|
+
this.data.autonomousModeOverride = null;
|
|
155
|
+
this._save();
|
|
156
|
+
log('INFO', 'Autonomous mode override cleared — score-based control active');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get net score.
|
|
161
|
+
*/
|
|
162
|
+
getNetScore() {
|
|
163
|
+
return this.data.netScore;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get per-category breakdown.
|
|
168
|
+
*/
|
|
169
|
+
getCategoryScores() {
|
|
170
|
+
return { ...this.data.categoryScores };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Get recent events.
|
|
175
|
+
*/
|
|
176
|
+
getRecentEvents(limit = 20) {
|
|
177
|
+
return this.data.events.slice(-limit);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Reset score (nuclear option).
|
|
182
|
+
*/
|
|
183
|
+
reset() {
|
|
184
|
+
this.data.netScore = 0;
|
|
185
|
+
this.data.events = [];
|
|
186
|
+
this.data.categoryScores = {};
|
|
187
|
+
this.data.autonomousModeOverride = null;
|
|
188
|
+
this._save();
|
|
189
|
+
log('INFO', 'Learning module reset');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
getStatus() {
|
|
193
|
+
return {
|
|
194
|
+
netScore: this.data.netScore,
|
|
195
|
+
autonomous: this.isAutonomous(),
|
|
196
|
+
threshold: AUTONOMY_THRESHOLD,
|
|
197
|
+
override: this.data.autonomousModeOverride,
|
|
198
|
+
totalEvents: this.data.events.length,
|
|
199
|
+
categoryScores: this.data.categoryScores
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
let learningInstance = null;
|
|
205
|
+
|
|
206
|
+
export function getLearning() {
|
|
207
|
+
if (!learningInstance) {
|
|
208
|
+
learningInstance = new LearningModule();
|
|
209
|
+
}
|
|
210
|
+
return learningInstance;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export { SCORE_WEIGHTS, AUTONOMY_THRESHOLD };
|
|
214
|
+
export default LearningModule;
|
package/core/license.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import crypto from 'crypto';
|
|
5
|
+
import { log } from './ai-provider.js';
|
|
6
|
+
import os from 'os';
|
|
7
|
+
|
|
8
|
+
const LICENSE_FILE = path.join(os.homedir(), '.vantuz', 'license.json');
|
|
9
|
+
|
|
10
|
+
// PUBLIC KEY (Müşteriye giden kodun içine gömülü)
|
|
11
|
+
// Sadece senin Private Key'inle imzalanmış veriyi doğrular.
|
|
12
|
+
const PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
13
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnOaEFB+3s2ouGnbfGlbE
|
|
14
|
+
XO55/RFjoifn2dMNTLt49Ul6CsDES0VaKOQ3+Vmyw8OjYwy773Z/wunX09qCEXDE
|
|
15
|
+
vKHAhxxBa3RQafIbQ/2MIyGTjvxrGelDPzB6yStSwLgShcXtRvAh69aXpFjXCLaW
|
|
16
|
+
svNq+7vcnNdXeZ2c0ipWbnqjpPiFKDe+wZ//gkx70zYXc4WijyLtTQWC6BobhpOA
|
|
17
|
+
isx5uykTzr+LLtMb2n1TpxEopSRbkLQQD4NMskH9Eb1Nx3znl+PjZooUXvr+8eJr
|
|
18
|
+
jQp0PTDTL32LHo2iaWwkKZ38PDc/hfSuu3Kt31t0SIxAwObcCmO2OtiZ7wTKxDow
|
|
19
|
+
RwIDAQAB
|
|
20
|
+
-----END PUBLIC KEY-----`;
|
|
21
|
+
|
|
22
|
+
export class LicenseManager {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.data = this._load();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
_load() {
|
|
28
|
+
try {
|
|
29
|
+
if (fs.existsSync(LICENSE_FILE)) {
|
|
30
|
+
return JSON.parse(fs.readFileSync(LICENSE_FILE, 'utf-8'));
|
|
31
|
+
}
|
|
32
|
+
} catch (e) {}
|
|
33
|
+
return { key: null, activatedAt: null, type: 'DEMO', expiresAt: null };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
_save() {
|
|
37
|
+
fs.writeFileSync(LICENSE_FILE, JSON.stringify(this.data, null, 2));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Lisans anahtarını doğrula (Signature Verification)
|
|
42
|
+
* Format: BASE64_PAYLOAD.BASE64_SIGNATURE
|
|
43
|
+
*/
|
|
44
|
+
activate(licenseString) {
|
|
45
|
+
try {
|
|
46
|
+
const [payloadB64, signatureB64] = licenseString.split('.');
|
|
47
|
+
if (!payloadB64 || !signatureB64) {
|
|
48
|
+
return { success: false, message: 'Geçersiz lisans formatı.' };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 1. İmzayı Doğrula
|
|
52
|
+
const verify = crypto.createVerify('SHA256');
|
|
53
|
+
verify.update(payloadB64);
|
|
54
|
+
verify.end();
|
|
55
|
+
const isValid = verify.verify(PUBLIC_KEY, signatureB64, 'base64');
|
|
56
|
+
|
|
57
|
+
if (!isValid) {
|
|
58
|
+
return { success: false, message: '❌ SAHTE LİSANS! İmza doğrulanamadı.' };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 2. İçeriği Çöz
|
|
62
|
+
const payload = JSON.parse(Buffer.from(payloadB64, 'base64').toString('utf-8'));
|
|
63
|
+
|
|
64
|
+
// 3. Son Kullanma Tarihini Kontrol Et (Payload içinden gelir)
|
|
65
|
+
// Payload: { type: 'ANNUAL', expires: '2027-01-01', user: '...' }
|
|
66
|
+
|
|
67
|
+
this.data = {
|
|
68
|
+
key: licenseString,
|
|
69
|
+
activatedAt: new Date().toISOString(),
|
|
70
|
+
expiresAt: payload.expires,
|
|
71
|
+
type: payload.type || 'PRO'
|
|
72
|
+
};
|
|
73
|
+
this._save();
|
|
74
|
+
|
|
75
|
+
return { success: true, message: `Lisans aktif! Bitiş: ${payload.expires}` };
|
|
76
|
+
|
|
77
|
+
} catch (e) {
|
|
78
|
+
return { success: false, message: 'Lisans işlenirken hata oluştu: ' + e.message };
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
check() {
|
|
83
|
+
if (!this.data.key || !this.data.expiresAt) {
|
|
84
|
+
return { valid: false, reason: 'NO_LICENSE', message: 'Lisans bulunamadı.' };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const now = new Date();
|
|
88
|
+
const expires = new Date(this.data.expiresAt);
|
|
89
|
+
const daysLeft = Math.ceil((expires - now) / (1000 * 60 * 60 * 24));
|
|
90
|
+
|
|
91
|
+
if (daysLeft <= 0) {
|
|
92
|
+
return { valid: false, reason: 'EXPIRED', message: 'Lisans süresi doldu.' };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
valid: true,
|
|
97
|
+
type: this.data.type,
|
|
98
|
+
daysLeft: daysLeft,
|
|
99
|
+
expiresAt: this.data.expiresAt
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
getInfo() {
|
|
104
|
+
const check = this.check();
|
|
105
|
+
return {
|
|
106
|
+
...this.data,
|
|
107
|
+
valid: check.valid,
|
|
108
|
+
daysLeft: check.daysLeft || 0
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export const licenseManager = new LicenseManager();
|