natureco-cli 1.0.45 → 1.0.49

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "natureco-cli",
3
- "version": "1.0.45",
3
+ "version": "1.0.49",
4
4
  "description": "NatureCo AI Bot Terminal Interface",
5
5
  "main": "bin/natureco.js",
6
6
  "bin": {
@@ -13,55 +13,396 @@ function getConfig() {
13
13
  catch { return {}; }
14
14
  }
15
15
 
16
+ function getSkills() {
17
+ try {
18
+ const skillsUtil = require('../utils/skills');
19
+ return skillsUtil.getSkills().map(s => s.name || s.slug);
20
+ } catch { return []; }
21
+ }
22
+
23
+ function getMemory(botId) {
24
+ try {
25
+ const memFile = path.join(CONFIG_DIR, 'memory', `${botId}.json`);
26
+ return JSON.parse(fs.readFileSync(memFile, 'utf8'));
27
+ } catch { return {}; }
28
+ }
29
+
16
30
  function openBrowser(url) {
17
31
  const { exec } = require('child_process');
18
32
  const p = process.platform;
19
- exec(p === 'darwin' ? 'open ' + url : p === 'win32' ? 'start ' + url : 'xdg-open ' + url);
33
+ exec(p === 'darwin' ? `open ${url}` : p === 'win32' ? `start ${url}` : `xdg-open ${url}`);
34
+ }
35
+
36
+ const HTML = `<!DOCTYPE html>
37
+ <html lang="tr">
38
+ <head>
39
+ <meta charset="UTF-8">
40
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
41
+ <title>NatureCo Dashboard</title>
42
+ <style>
43
+ *{margin:0;padding:0;box-sizing:border-box;font-family:system-ui,-apple-system,sans-serif}
44
+ html,body{height:100%;overflow:hidden}
45
+ body{
46
+ background:#0d1117;
47
+ color:#eceff1;
48
+ font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;
49
+ display:flex;
50
+ height:100vh;
51
+ overflow:hidden;
52
+ position:relative;
53
+ }
54
+ body::before{
55
+ content:'';
56
+ position:absolute;
57
+ top:0;left:0;right:0;bottom:0;
58
+ background:
59
+ radial-gradient(ellipse 80% 50% at 50% -20%,rgba(16,185,129,0.15),transparent 60%),
60
+ radial-gradient(ellipse 60% 40% at 80% 80%,rgba(59,130,246,0.08),transparent 50%),
61
+ radial-gradient(ellipse 40% 30% at 20% 60%,rgba(16,185,129,0.06),transparent 40%);
62
+ animation:gradientShift 15s ease-in-out infinite alternate;
63
+ pointer-events:none;
64
+ z-index:0;
65
+ }
66
+ @keyframes gradientShift{
67
+ 0%{
68
+ background:
69
+ radial-gradient(ellipse 80% 50% at 50% -20%,rgba(16,185,129,0.15),transparent 60%),
70
+ radial-gradient(ellipse 60% 40% at 80% 80%,rgba(59,130,246,0.08),transparent 50%),
71
+ radial-gradient(ellipse 40% 30% at 20% 60%,rgba(16,185,129,0.06),transparent 40%);
72
+ }
73
+ 100%{
74
+ background:
75
+ radial-gradient(ellipse 80% 50% at 30% 120%,rgba(16,185,129,0.12),transparent 60%),
76
+ radial-gradient(ellipse 60% 40% at 90% 20%,rgba(59,130,246,0.1),transparent 50%),
77
+ radial-gradient(ellipse 40% 30% at 10% 80%,rgba(16,185,129,0.08),transparent 40%);
78
+ }
20
79
  }
80
+ .app{display:flex;height:100vh}
81
+ .sidebar{
82
+ width:240px;min-width:240px;
83
+ background:rgba(0,10,5,0.75);
84
+ backdrop-filter:blur(20px);
85
+ border-right:1px solid rgba(0,230,118,0.12);
86
+ display:flex;flex-direction:column;
87
+ overflow-y:auto;
88
+ }
89
+ .sidebar::-webkit-scrollbar{width:3px}
90
+ .sidebar::-webkit-scrollbar-thumb{background:rgba(0,230,118,0.25);border-radius:2px}
91
+ .logo-area{padding:18px 16px;border-bottom:1px solid rgba(0,230,118,0.08);flex-shrink:0}
92
+ .logo{color:#00E676;font-size:17px;font-weight:700;letter-spacing:-0.4px}
93
+ .logo-sub{color:rgba(0,230,118,0.35);font-size:10px;margin-top:2px}
94
+ .section{padding:12px 14px}
95
+ .section-label{color:rgba(0,230,118,0.35);font-size:9px;font-weight:600;letter-spacing:1.8px;text-transform:uppercase;margin-bottom:8px}
96
+ .bot-card{background:rgba(0,230,118,0.06);border:1px solid rgba(0,230,118,0.2);border-radius:8px;padding:10px;display:flex;align-items:center;gap:8px;cursor:pointer;transition:all 0.2s}
97
+ .bot-card:hover{background:rgba(0,230,118,0.1);border-color:rgba(0,230,118,0.35)}
98
+ .avatar{width:32px;height:32px;border-radius:50%;background:linear-gradient(135deg,#00C853,#00E676);display:flex;align-items:center;justify-content:center;color:#000;font-weight:700;font-size:13px;flex-shrink:0}
99
+ .bot-info .name{color:#e8f5e9;font-size:13px;font-weight:500}
100
+ .bot-info .model{color:rgba(0,230,118,0.45);font-size:10px;margin-top:1px}
101
+ .online-dot{width:7px;height:7px;background:#00E676;border-radius:50%;margin-left:auto;flex-shrink:0;box-shadow:0 0 6px rgba(0,230,118,0.8);animation:pulse 2s infinite}
102
+ @keyframes pulse{0%,100%{opacity:1}50%{opacity:0.4}}
103
+ .other-bot{padding:5px 0;color:rgba(0,230,118,0.4);font-size:12px;cursor:pointer;transition:color 0.2s;display:flex;align-items:center;gap:6px}
104
+ .other-bot:hover{color:#a5d6a7}
105
+ .other-avatar{width:22px;height:22px;border-radius:50%;background:rgba(0,230,118,0.1);border:1px solid rgba(0,230,118,0.15);display:flex;align-items:center;justify-content:center;color:rgba(0,230,118,0.5);font-size:9px;font-weight:700}
106
+ .ch-row{display:flex;align-items:center;gap:7px;padding:4px 0}
107
+ .ch-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0}
108
+ .ch-dot.on{background:#00E676;box-shadow:0 0 5px rgba(0,230,118,0.7)}
109
+ .ch-dot.off{background:rgba(255,255,255,0.15)}
110
+ .ch-name{font-size:12px}
111
+ .ch-name.on{color:#a5d6a7}
112
+ .ch-name.off{color:rgba(255,255,255,0.25)}
113
+ .skill-tag{display:inline-block;background:rgba(0,230,118,0.06);border:1px solid rgba(0,230,118,0.15);border-radius:4px;padding:3px 8px;color:#81c784;font-size:10px;margin:2px 2px 2px 0}
114
+ .mem-row{font-size:11px;padding:2px 0}
115
+ .mem-key{color:rgba(0,230,118,0.4);font-size:9px;letter-spacing:0.5px;text-transform:uppercase;margin-top:5px}
116
+ .mem-val{color:#a5d6a7}
117
+ .sidebar-footer{margin-top:auto;padding:12px 14px;border-top:1px solid rgba(0,230,118,0.06);flex-shrink:0}
118
+ .footer-link{color:rgba(0,230,118,0.25);font-size:10px;text-decoration:none}
119
+ .footer-link:hover{color:rgba(0,230,118,0.5)}
120
+ .chat-area{flex:1;display:flex;flex-direction:column;min-width:0}
121
+ .chat-header{
122
+ padding:14px 20px;
123
+ border-bottom:1px solid rgba(0,230,118,0.08);
124
+ display:flex;align-items:center;gap:12px;
125
+ background:rgba(0,10,5,0.6);
126
+ backdrop-filter:blur(10px);
127
+ flex-shrink:0;
128
+ }
129
+ .header-bot-name{color:#e8f5e9;font-size:14px;font-weight:500}
130
+ .header-bot-model{color:rgba(0,230,118,0.4);font-size:11px}
131
+ .version-badge{margin-left:auto;background:rgba(0,230,118,0.06);border:1px solid rgba(0,230,118,0.15);border-radius:20px;padding:3px 10px;color:rgba(0,230,118,0.5);font-size:10px}
132
+ .messages{flex:1;padding:16px 20px;overflow-y:auto;display:flex;flex-direction:column;gap:12px}
133
+ .messages::-webkit-scrollbar{width:3px}
134
+ .messages::-webkit-scrollbar-thumb{background:rgba(0,230,118,0.2);border-radius:2px}
135
+ .msg{display:flex;gap:8px;align-items:flex-end;animation:fadeIn 0.3s ease}
136
+ @keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
137
+ .msg.user{flex-direction:row-reverse}
138
+ .msg-avatar{width:28px;height:28px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:11px;flex-shrink:0}
139
+ .msg-avatar.bot{background:linear-gradient(135deg,#00C853,#00E676);color:#000}
140
+ .msg-avatar.user{background:rgba(0,230,118,0.15);border:1px solid rgba(0,230,118,0.3);color:#00E676}
141
+ .bubble{padding:10px 14px;border-radius:12px;font-size:13px;line-height:1.6;max-width:72%}
142
+ .bubble.user{background:linear-gradient(135deg,#00C853,#00E676);color:#000;font-weight:500;border-radius:12px 12px 0 12px}
143
+ .bubble.bot{background:rgba(255,255,255,0.04);border:1px solid rgba(0,230,118,0.1);color:#c8e6c9;border-radius:12px 12px 12px 0}
144
+ .typing{display:flex;gap:4px;padding:10px 14px;background:rgba(255,255,255,0.04);border:1px solid rgba(0,230,118,0.1);border-radius:12px 12px 12px 0;width:fit-content}
145
+ .typing span{width:6px;height:6px;background:rgba(0,230,118,0.5);border-radius:50%;animation:typing 1.2s infinite}
146
+ .typing span:nth-child(2){animation-delay:0.2s}
147
+ .typing span:nth-child(3){animation-delay:0.4s}
148
+ @keyframes typing{0%,60%,100%{transform:translateY(0)}30%{transform:translateY(-6px)}}
149
+ .input-area{
150
+ padding:14px 20px;
151
+ border-top:1px solid rgba(0,230,118,0.08);
152
+ display:flex;gap:10px;
153
+ background:rgba(0,10,5,0.6);
154
+ backdrop-filter:blur(10px);
155
+ flex-shrink:0;
156
+ }
157
+ .input-box{
158
+ flex:1;
159
+ background:rgba(255,255,255,0.04);
160
+ border:1px solid rgba(0,230,118,0.15);
161
+ border-radius:8px;
162
+ padding:10px 14px;
163
+ color:#e8f5e9;
164
+ font-size:13px;
165
+ outline:none;
166
+ transition:border-color 0.2s;
167
+ }
168
+ .input-box:focus{border-color:rgba(0,230,118,0.4)}
169
+ .input-box::placeholder{color:rgba(0,230,118,0.25)}
170
+ .send-btn{
171
+ background:linear-gradient(135deg,#00C853,#00E676);
172
+ border:none;border-radius:8px;
173
+ padding:10px 18px;
174
+ color:#000;font-weight:600;font-size:13px;
175
+ cursor:pointer;transition:opacity 0.2s,transform 0.1s;
176
+ white-space:nowrap;
177
+ }
178
+ .send-btn:hover{opacity:0.9}
179
+ .send-btn:active{transform:scale(0.97)}
180
+ </style>
181
+ </head>
182
+ <body>
183
+ <div class="app">
184
+ <div class="sidebar" id="sidebar">
185
+ <div class="logo-area">
186
+ <div class="logo">NatureCo</div>
187
+ <div class="logo-sub" id="ver-label">Terminal</div>
188
+ </div>
189
+ <div class="section" id="active-bot-section">
190
+ <div class="section-label">Aktif Bot</div>
191
+ <div class="bot-card">
192
+ <div class="avatar">N</div>
193
+ <div class="bot-info">
194
+ <div class="name" id="active-bot-name">Yükleniyor...</div>
195
+ <div class="model" id="active-bot-model">NatureCo</div>
196
+ </div>
197
+ <div class="online-dot"></div>
198
+ </div>
199
+ </div>
200
+ <div class="section" id="other-bots-section" style="padding-top:0">
201
+ <div class="section-label">Diğer Botlar</div>
202
+ <div id="other-bots-list"></div>
203
+ </div>
204
+ <div class="section" style="padding-top:0">
205
+ <div class="section-label">Kanallar</div>
206
+ <div id="channels-list"></div>
207
+ </div>
208
+ <div class="section" style="padding-top:0">
209
+ <div class="section-label">Skill'ler</div>
210
+ <div id="skills-list"></div>
211
+ </div>
212
+ <div class="section" style="padding-top:0">
213
+ <div class="section-label">Hafıza</div>
214
+ <div id="memory-section"></div>
215
+ </div>
216
+ <div class="sidebar-footer">
217
+ <a href="https://natureco.me" class="footer-link">natureco.me</a>
218
+ </div>
219
+ </div>
220
+ <div class="chat-area">
221
+ <div class="chat-header">
222
+ <div class="avatar" style="width:36px;height:36px;font-size:14px">N</div>
223
+ <div>
224
+ <div class="header-bot-name" id="header-bot-name">Nature Bot</div>
225
+ <div class="header-bot-model" id="header-bot-model">NatureCo</div>
226
+ </div>
227
+ <div class="version-badge" id="version-badge">v1.0.49</div>
228
+ </div>
229
+ <div class="messages" id="messages"></div>
230
+ <div class="input-area">
231
+ <input class="input-box" id="input" placeholder="Mesaj yaz..." />
232
+ <button class="send-btn" onclick="send()">Gönder</button>
233
+ </div>
234
+ </div>
235
+ </div>
236
+ <script>
237
+ let cfg = {}, activeBotId = null;
21
238
 
22
- const HTML = '<!DOCTYPE html><html><head><meta charset="UTF-8"><title>NatureCo Dashboard</title><style>*{margin:0;padding:0;box-sizing:border-box}body{background:#050a0e;color:#eceff1;font-family:system-ui,sans-serif;display:flex;height:100vh}.sidebar{width:260px;background:rgba(255,255,255,0.03);border-right:1px solid rgba(0,230,118,0.1);padding:20px;display:flex;flex-direction:column}.logo{color:#00E676;font-size:20px;font-weight:700;margin-bottom:8px;letter-spacing:1px}.chat{flex:1;display:flex;flex-direction:column}.header{padding:16px 20px;border-bottom:1px solid rgba(0,230,118,0.1);display:flex;align-items:center;gap:8px}.messages{flex:1;padding:20px;overflow-y:auto}.input-area{padding:20px;border-top:1px solid rgba(0,230,118,0.1);display:flex;gap:10px}.input-area input{flex:1;background:rgba(255,255,255,0.05);border:1px solid rgba(0,230,118,0.2);border-radius:8px;padding:12px;color:#eceff1;outline:none;font-size:14px}.input-area button{background:linear-gradient(135deg,#00E676,#00BCD4);border:none;border-radius:8px;padding:12px 24px;color:#000;font-weight:700;cursor:pointer;font-size:14px}.msg{margin:8px 0;display:flex}.msg.user{justify-content:flex-end}.msg.user .bubble{background:linear-gradient(135deg,#00E676,#00BCD4);color:#000;border-radius:12px 12px 0 12px;padding:10px 14px;max-width:70%;font-size:14px}.msg.bot .bubble{background:rgba(255,255,255,0.05);border:1px solid rgba(0,230,118,0.1);border-radius:12px 12px 12px 0;padding:10px 14px;max-width:70%;font-size:14px}</style></head><body><div class="sidebar"><div class="logo">NatureCo</div><div id="botName" style="color:#546e7a;font-size:14px;margin-top:4px">Loading...</div><div style="margin-top:auto;color:#546e7a;font-size:12px">natureco.me</div></div><div class="chat"><div class="header"><span id="chatBot" style="color:#eceff1;font-weight:600">Dashboard</span><span style="width:8px;height:8px;background:#00E676;border-radius:50%;display:inline-block"></span><span style="color:#00E676;font-size:12px">Online</span></div><div class="messages" id="messages"></div><div class="input-area"><input id="input" placeholder="Mesaj yaz..." onkeydown="if(event.key===\')send()"><button onclick="send()">Gonder</button></div></div><script>var cfg={};fetch("/config").then(function(r){return r.json()}).then(function(d){cfg=d;document.getElementById("botName").textContent=d.defaultBot||"-";document.getElementById("chatBot").textContent=d.defaultBot||"-"});function send(){var i=document.getElementById("input");var m=i.value.trim();if(!m)return;i.value="";addMsg("user",m);fetch("https://api.natureco.me/api/agent/chat",{method:"POST",headers:{"Content-Type":"application/json","Authorization":"Bearer "+cfg.apiKey,"X-User-ID":"dashboard-user"},body:JSON.stringify({agent_id:cfg.defaultBotId,message:m,platform:"dashboard",user_id:"dashboard-user"})}).then(function(r){return r.json()}).then(function(d){addMsg("bot",d.reply||d.message||"Hata")}).catch(function(){addMsg("bot","Baglanti hatasi")})}function addMsg(t,m){var d=document.getElementById("messages");var el=document.createElement("div");el.className="msg "+t;el.innerHTML="<div class=bubble>"+m+"</div>";d.appendChild(el);d.scrollTop=d.scrollHeight}</script></body></html>';
239
+ async function init() {
240
+ try {
241
+ const r = await fetch('/config');
242
+ cfg = await r.json();
243
+ activeBotId = cfg.defaultBotId;
244
+ document.getElementById('active-bot-name').textContent = cfg.defaultBot || 'Bot';
245
+ document.getElementById('header-bot-name').textContent = cfg.defaultBot || 'Bot';
246
+ document.getElementById('ver-label').textContent = 'Terminal ' + (cfg.version || '');
247
+
248
+ const others = (cfg.bots || []).filter(b => b.id !== activeBotId);
249
+ const ol = document.getElementById('other-bots-list');
250
+ ol.innerHTML = others.map(b => \`<div class="other-bot" onclick="switchBot('\${b.id}','\${b.name}')"><div class="other-avatar">\${b.name[0]}</div>\${b.name}</div>\`).join('');
251
+
252
+ const channels = [
253
+ { name: 'Telegram', key: 'telegramToken' },
254
+ { name: 'WhatsApp', key: 'whatsappConnected' },
255
+ { name: 'Discord', key: 'discordToken' },
256
+ { name: 'Gateway', key: 'gatewayRunning' },
257
+ ];
258
+ document.getElementById('channels-list').innerHTML = channels.map(c => {
259
+ const on = !!(cfg[c.key]);
260
+ return \`<div class="ch-row"><div class="ch-dot \${on?'on':'off'}"></div><div class="ch-name \${on?'on':'off'}">\${c.name}</div></div>\`;
261
+ }).join('');
262
+ } catch(e) { console.error(e); }
263
+
264
+ try {
265
+ const sr = await fetch('/skills');
266
+ const skills = await sr.json();
267
+ document.getElementById('skills-list').innerHTML = skills.map(s => \`<span class="skill-tag">\${s}</span>\`).join('');
268
+ } catch {}
269
+
270
+ try {
271
+ const mr = await fetch('/memory');
272
+ const mem = await mr.json();
273
+ let html = '';
274
+ if (mem.name) html += \`<div class="mem-key">İsim</div><div class="mem-row mem-val">\${mem.name}</div>\`;
275
+ if (mem.facts && mem.facts.length) html += \`<div class="mem-key">Bilgiler</div><div class="mem-row mem-val">\${mem.facts.map(f=>typeof f==='object'?f.value:f).join(' · ')}</div>\`;
276
+ document.getElementById('memory-section').innerHTML = html || \`<div class="mem-row" style="color:rgba(0,230,118,0.25)">Hafıza boş</div>\`;
277
+ } catch {}
278
+ }
279
+
280
+ function switchBot(id, name) {
281
+ activeBotId = id;
282
+ document.getElementById('active-bot-name').textContent = name;
283
+ document.getElementById('header-bot-name').textContent = name;
284
+ document.getElementById('messages').innerHTML = '';
285
+ }
286
+
287
+ function addMsg(type, text) {
288
+ const m = document.getElementById('messages');
289
+ const initials = type === 'user' ? 'G' : 'N';
290
+ m.innerHTML += \`<div class="msg \${type}"><div class="msg-avatar \${type}">\${initials}</div><div class="bubble \${type}">\${text}</div></div>\`;
291
+ m.scrollTop = m.scrollHeight;
292
+ }
293
+
294
+ function showTyping() {
295
+ const m = document.getElementById('messages');
296
+ m.innerHTML += \`<div class="msg" id="typing-row"><div class="msg-avatar bot">N</div><div class="typing"><span></span><span></span><span></span></div></div>\`;
297
+ m.scrollTop = m.scrollHeight;
298
+ }
299
+
300
+ function hideTyping() {
301
+ const t = document.getElementById('typing-row');
302
+ if (t) t.remove();
303
+ }
304
+
305
+ async function send() {
306
+ const inp = document.getElementById('input');
307
+ const msg = inp.value.trim();
308
+ if (!msg || !cfg.apiKey) return;
309
+ inp.value = '';
310
+ addMsg('user', msg);
311
+ showTyping();
312
+ try {
313
+ const r = await fetch('https://api.natureco.me/api/agent/chat', {
314
+ method: 'POST',
315
+ headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + cfg.apiKey, 'X-User-ID': 'dashboard-user' },
316
+ body: JSON.stringify({ agent_id: activeBotId, message: msg, platform: 'dashboard', user_id: 'dashboard-user' })
317
+ });
318
+ const d = await r.json();
319
+ hideTyping();
320
+ addMsg('bot', d.reply || d.message || 'Hata');
321
+ } catch { hideTyping(); addMsg('bot', 'Bağlantı hatası'); }
322
+ }
323
+
324
+ document.getElementById('input').addEventListener('keydown', e => { if (e.key === 'Enter') send(); });
325
+ init();
326
+ </script>
327
+ </body>
328
+ </html>`;
23
329
 
24
330
  function dashboard(action) {
25
331
  action = action || 'start';
26
332
  if (action === 'start') {
27
333
  const cfg = getConfig();
28
- const server = http.createServer((req, res) => {
334
+ const skills = getSkills();
335
+ const fs2 = require('fs');
336
+
337
+ let gatewayRunning = false;
338
+ try {
339
+ const pid = parseInt(fs2.readFileSync(path.join(CONFIG_DIR, 'gateway.pid'), 'utf8'));
340
+ process.kill(pid, 0);
341
+ gatewayRunning = true;
342
+ } catch {}
343
+
344
+ const bots = [];
345
+
346
+ const server = http.createServer(async (req, res) => {
347
+ const cors = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET,POST,DELETE', 'Access-Control-Allow-Headers': 'Content-Type' };
348
+
349
+ if (req.method === 'OPTIONS') { res.writeHead(204, cors); res.end(); return; }
350
+
29
351
  if (req.url === '/config') {
30
- res.writeHead(200, { 'Content-Type': 'application/json' });
31
- res.end(JSON.stringify({ apiKey: cfg.apiKey, defaultBot: cfg.defaultBot, defaultBotId: cfg.defaultBotId }));
352
+ res.writeHead(200, { ...cors, 'Content-Type': 'application/json' });
353
+ res.end(JSON.stringify({
354
+ apiKey: cfg.apiKey,
355
+ defaultBot: cfg.defaultBot,
356
+ defaultBotId: cfg.defaultBotId,
357
+ version: 'v1.0.49',
358
+ bots: cfg.bots || [],
359
+ telegramToken: cfg.telegramToken || null,
360
+ whatsappConnected: cfg.whatsappConnected || false,
361
+ discordToken: cfg.discordToken || null,
362
+ gatewayRunning,
363
+ }));
364
+ } else if (req.url === '/skills') {
365
+ res.writeHead(200, { ...cors, 'Content-Type': 'application/json' });
366
+ res.end(JSON.stringify(skills));
367
+ } else if (req.url === '/memory') {
368
+ res.writeHead(200, { ...cors, 'Content-Type': 'application/json' });
369
+ res.end(JSON.stringify(getMemory(cfg.defaultBotId || '')));
32
370
  } else {
33
371
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
34
372
  res.end(HTML);
35
373
  }
36
374
  });
375
+
37
376
  server.listen(PORT, () => {
38
377
  fs.mkdirSync(CONFIG_DIR, { recursive: true });
39
378
  fs.writeFileSync(PID_FILE, String(process.pid));
40
- console.log(chalk.green('Dashboard started!'));
41
- console.log(chalk.cyan('URL: ') + 'http://localhost:' + PORT);
42
- openBrowser('http://localhost:' + PORT);
43
- console.log(chalk.gray('Press Ctrl+C to stop'));
379
+ console.log(chalk.green('\n✅ Dashboard başlatıldı!'));
380
+ console.log(chalk.cyan('URL: ') + `http://localhost:${PORT}`);
381
+ console.log(chalk.gray('Durdurmak için: Ctrl+C\n'));
382
+ openBrowser(`http://localhost:${PORT}`);
44
383
  });
384
+
45
385
  process.on('SIGINT', () => {
46
386
  try { fs.unlinkSync(PID_FILE); } catch {}
47
387
  server.close();
48
- console.log(chalk.green('Dashboard stopped'));
49
388
  process.exit(0);
50
389
  });
390
+
51
391
  } else if (action === 'stop') {
52
392
  try {
53
393
  const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8'));
54
394
  process.kill(pid);
55
395
  fs.unlinkSync(PID_FILE);
56
- console.log(chalk.green('Dashboard stopped'));
57
- } catch { console.log(chalk.red('Dashboard not running')); }
396
+ console.log(chalk.green('Dashboard durduruldu'));
397
+ } catch { console.log(chalk.red('Dashboard çalışmıyor')); }
58
398
  } else if (action === 'status') {
59
399
  try {
60
400
  const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8'));
61
- console.log(chalk.green('Dashboard running'));
401
+ process.kill(pid, 0);
402
+ console.log(chalk.green('✅ Dashboard çalışıyor'));
62
403
  console.log('PID:', pid);
63
404
  console.log('URL: http://localhost:' + PORT);
64
- } catch { console.log(chalk.gray('Dashboard not running')); }
405
+ } catch { console.log(chalk.gray('Dashboard çalışmıyor')); }
65
406
  }
66
407
  }
67
408