natureco-cli 2.23.30 → 2.23.31
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/bin/natureco.js +166 -163
- package/package.json +1 -1
- package/src/commands/acp.js +39 -0
- package/src/commands/admin-rpc.js +83 -0
- package/src/commands/agent.js +214 -23
- package/src/commands/agents.js +114 -30
- package/src/commands/approvals.js +172 -11
- package/src/commands/browser.js +815 -0
- package/src/commands/capability.js +195 -22
- package/src/commands/channels.js +422 -267
- package/src/commands/chat.js +5 -8
- package/src/commands/clawbot.js +19 -0
- package/src/commands/code.js +3 -2
- package/src/commands/commitments.js +125 -9
- package/src/commands/completion.js +40 -32
- package/src/commands/config.js +219 -30
- package/src/commands/configure.js +84 -67
- package/src/commands/cron.js +239 -19
- package/src/commands/daemon.js +34 -4
- package/src/commands/dashboard.js +47 -374
- package/src/commands/devices.js +53 -26
- package/src/commands/directory.js +146 -14
- package/src/commands/dns.js +148 -10
- package/src/commands/docs.js +119 -26
- package/src/commands/doctor.js +143 -492
- package/src/commands/exec-policy.js +57 -48
- package/src/commands/gateway.js +492 -249
- package/src/commands/health.js +141 -11
- package/src/commands/help.js +24 -25
- package/src/commands/hooks.js +141 -87
- package/src/commands/infer.js +1442 -41
- package/src/commands/logs.js +122 -99
- package/src/commands/mcp.js +121 -309
- package/src/commands/memory.js +128 -0
- package/src/commands/message.js +720 -140
- package/src/commands/models.js +39 -1
- package/src/commands/node.js +77 -77
- package/src/commands/nodes.js +278 -22
- package/src/commands/onboard.js +115 -56
- package/src/commands/pairing.js +108 -107
- package/src/commands/path.js +206 -0
- package/src/commands/plugins.js +35 -1
- package/src/commands/proxy.js +159 -8
- package/src/commands/qr.js +55 -13
- package/src/commands/reset.js +101 -94
- package/src/commands/secrets.js +104 -21
- package/src/commands/sessions.js +110 -51
- package/src/commands/setup.js +102 -649
- package/src/commands/skills.js +67 -1
- package/src/commands/status.js +101 -127
- package/src/commands/tasks.js +208 -100
- package/src/commands/terminal.js +130 -12
- package/src/commands/transcripts.js +24 -1
- package/src/commands/tui.js +41 -0
- package/src/commands/uninstall.js +73 -92
- package/src/commands/update.js +146 -91
- package/src/commands/webhooks.js +58 -66
- package/src/commands/wiki.js +783 -0
- package/src/utils/agents-md.js +85 -0
- package/src/utils/api.js +39 -40
- package/src/utils/format.js +144 -0
- package/src/utils/headless.js +2 -1
- package/src/utils/parallel-tools.js +106 -0
- package/src/utils/sub-agent.js +148 -0
- package/src/utils/token-budget.js +304 -0
- package/src/utils/tool-runner.js +7 -5
- package/src/utils/web-fetch.js +107 -0
|
@@ -1,396 +1,69 @@
|
|
|
1
|
-
const http = require('http');
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const os = require('os');
|
|
5
1
|
const chalk = require('chalk');
|
|
2
|
+
const http = require('http');
|
|
3
|
+
const net = require('net');
|
|
6
4
|
|
|
7
|
-
const
|
|
8
|
-
const PID_FILE = path.join(CONFIG_DIR, 'dashboard.pid');
|
|
9
|
-
const PORT = 3848;
|
|
10
|
-
|
|
11
|
-
function getConfig() {
|
|
12
|
-
try { return JSON.parse(fs.readFileSync(path.join(CONFIG_DIR, 'config.json'), 'utf8')); }
|
|
13
|
-
catch { return {}; }
|
|
14
|
-
}
|
|
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
|
-
|
|
30
|
-
function openBrowser(url) {
|
|
31
|
-
const { exec } = require('child_process');
|
|
32
|
-
const p = process.platform;
|
|
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:#0B0E11;
|
|
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:fixed;
|
|
57
|
-
top:0;left:0;
|
|
58
|
-
width:100%;height:100%;
|
|
59
|
-
background:
|
|
60
|
-
radial-gradient(circle at 20% 80%,rgba(16,185,129,0.3) 0%,transparent 50%),
|
|
61
|
-
radial-gradient(circle at 80% 20%,rgba(99,102,241,0.2) 0%,transparent 50%),
|
|
62
|
-
radial-gradient(circle at 40% 40%,rgba(245,158,11,0.1) 0%,transparent 50%),
|
|
63
|
-
linear-gradient(180deg,#06080A 0%,#0B0E11 100%);
|
|
64
|
-
z-index:-1;
|
|
65
|
-
pointer-events:none;
|
|
66
|
-
}
|
|
67
|
-
.app{display:flex;height:100vh}
|
|
68
|
-
.sidebar{
|
|
69
|
-
width:240px;min-width:240px;
|
|
70
|
-
background:rgba(0,10,5,0.75);
|
|
71
|
-
backdrop-filter:blur(20px);
|
|
72
|
-
border-right:1px solid rgba(0,230,118,0.12);
|
|
73
|
-
display:flex;flex-direction:column;
|
|
74
|
-
overflow-y:auto;
|
|
75
|
-
}
|
|
76
|
-
.sidebar::-webkit-scrollbar{width:3px}
|
|
77
|
-
.sidebar::-webkit-scrollbar-thumb{background:rgba(0,230,118,0.25);border-radius:2px}
|
|
78
|
-
.logo-area{padding:18px 16px;border-bottom:1px solid rgba(0,230,118,0.08);flex-shrink:0}
|
|
79
|
-
.logo{color:#00E676;font-size:17px;font-weight:700;letter-spacing:-0.4px}
|
|
80
|
-
.logo-sub{color:rgba(0,230,118,0.35);font-size:10px;margin-top:2px}
|
|
81
|
-
.section{padding:12px 14px}
|
|
82
|
-
.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}
|
|
83
|
-
.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}
|
|
84
|
-
.bot-card:hover{background:rgba(0,230,118,0.1);border-color:rgba(0,230,118,0.35)}
|
|
85
|
-
.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}
|
|
86
|
-
.bot-info .name{color:#e8f5e9;font-size:13px;font-weight:500}
|
|
87
|
-
.bot-info .model{color:rgba(0,230,118,0.45);font-size:10px;margin-top:1px}
|
|
88
|
-
.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}
|
|
89
|
-
@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.4}}
|
|
90
|
-
.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}
|
|
91
|
-
.other-bot:hover{color:#a5d6a7}
|
|
92
|
-
.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}
|
|
93
|
-
.ch-row{display:flex;align-items:center;gap:7px;padding:4px 0}
|
|
94
|
-
.ch-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0}
|
|
95
|
-
.ch-dot.on{background:#00E676;box-shadow:0 0 5px rgba(0,230,118,0.7)}
|
|
96
|
-
.ch-dot.off{background:rgba(255,255,255,0.15)}
|
|
97
|
-
.ch-name{font-size:12px}
|
|
98
|
-
.ch-name.on{color:#a5d6a7}
|
|
99
|
-
.ch-name.off{color:rgba(255,255,255,0.25)}
|
|
100
|
-
.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}
|
|
101
|
-
.mem-row{font-size:11px;padding:2px 0}
|
|
102
|
-
.mem-key{color:rgba(0,230,118,0.4);font-size:9px;letter-spacing:0.5px;text-transform:uppercase;margin-top:5px}
|
|
103
|
-
.mem-val{color:#a5d6a7}
|
|
104
|
-
.sidebar-footer{margin-top:auto;padding:12px 14px;border-top:1px solid rgba(0,230,118,0.06);flex-shrink:0}
|
|
105
|
-
.footer-link{color:rgba(0,230,118,0.25);font-size:10px;text-decoration:none}
|
|
106
|
-
.footer-link:hover{color:rgba(0,230,118,0.5)}
|
|
107
|
-
.chat-area{flex:1;display:flex;flex-direction:column;min-width:0}
|
|
108
|
-
.chat-header{
|
|
109
|
-
padding:14px 20px;
|
|
110
|
-
border-bottom:1px solid rgba(0,230,118,0.08);
|
|
111
|
-
display:flex;align-items:center;gap:12px;
|
|
112
|
-
background:rgba(0,10,5,0.6);
|
|
113
|
-
backdrop-filter:blur(10px);
|
|
114
|
-
flex-shrink:0;
|
|
115
|
-
}
|
|
116
|
-
.header-bot-name{color:#e8f5e9;font-size:14px;font-weight:500}
|
|
117
|
-
.header-bot-model{color:rgba(0,230,118,0.4);font-size:11px}
|
|
118
|
-
.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}
|
|
119
|
-
.messages{flex:1;padding:16px 20px;overflow-y:auto;display:flex;flex-direction:column;gap:12px}
|
|
120
|
-
.messages::-webkit-scrollbar{width:3px}
|
|
121
|
-
.messages::-webkit-scrollbar-thumb{background:rgba(0,230,118,0.2);border-radius:2px}
|
|
122
|
-
.msg{display:flex;gap:8px;align-items:flex-end;animation:fadeIn 0.3s ease}
|
|
123
|
-
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
|
|
124
|
-
.msg.user{flex-direction:row-reverse}
|
|
125
|
-
.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}
|
|
126
|
-
.msg-avatar.bot{background:linear-gradient(135deg,#00C853,#00E676);color:#000}
|
|
127
|
-
.msg-avatar.user{background:rgba(0,230,118,0.15);border:1px solid rgba(0,230,118,0.3);color:#00E676}
|
|
128
|
-
.bubble{padding:10px 14px;border-radius:12px;font-size:13px;line-height:1.6;max-width:72%}
|
|
129
|
-
.bubble.user{background:linear-gradient(135deg,#00C853,#00E676);color:#000;font-weight:500;border-radius:12px 12px 0 12px}
|
|
130
|
-
.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}
|
|
131
|
-
.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}
|
|
132
|
-
.typing span{width:6px;height:6px;background:rgba(0,230,118,0.5);border-radius:50%;animation:typing 1.2s infinite}
|
|
133
|
-
.typing span:nth-child(2){animation-delay:0.2s}
|
|
134
|
-
.typing span:nth-child(3){animation-delay:0.4s}
|
|
135
|
-
@keyframes typing{0%,60%,100%{transform:translateY(0)}30%{transform:translateY(-6px)}}
|
|
136
|
-
.input-area{
|
|
137
|
-
padding:14px 20px;
|
|
138
|
-
border-top:1px solid rgba(0,230,118,0.08);
|
|
139
|
-
display:flex;gap:10px;
|
|
140
|
-
background:rgba(0,10,5,0.6);
|
|
141
|
-
backdrop-filter:blur(10px);
|
|
142
|
-
flex-shrink:0;
|
|
143
|
-
}
|
|
144
|
-
.input-box{
|
|
145
|
-
flex:1;
|
|
146
|
-
background:rgba(255,255,255,0.04);
|
|
147
|
-
border:1px solid rgba(0,230,118,0.15);
|
|
148
|
-
border-radius:8px;
|
|
149
|
-
padding:10px 14px;
|
|
150
|
-
color:#e8f5e9;
|
|
151
|
-
font-size:13px;
|
|
152
|
-
outline:none;
|
|
153
|
-
transition:border-color 0.2s;
|
|
154
|
-
}
|
|
155
|
-
.input-box:focus{border-color:rgba(0,230,118,0.4)}
|
|
156
|
-
.input-box::placeholder{color:rgba(0,230,118,0.25)}
|
|
157
|
-
.send-btn{
|
|
158
|
-
background:linear-gradient(135deg,#00C853,#00E676);
|
|
159
|
-
border:none;border-radius:8px;
|
|
160
|
-
padding:10px 18px;
|
|
161
|
-
color:#000;font-weight:600;font-size:13px;
|
|
162
|
-
cursor:pointer;transition:opacity 0.2s,transform 0.1s;
|
|
163
|
-
white-space:nowrap;
|
|
164
|
-
}
|
|
165
|
-
.send-btn:hover{opacity:0.9}
|
|
166
|
-
.send-btn:active{transform:scale(0.97)}
|
|
167
|
-
</style>
|
|
168
|
-
</head>
|
|
169
|
-
<body>
|
|
170
|
-
<div class="app">
|
|
171
|
-
<div class="sidebar" id="sidebar">
|
|
172
|
-
<div class="logo-area">
|
|
173
|
-
<div class="logo">NatureCo</div>
|
|
174
|
-
<div class="logo-sub" id="ver-label">Terminal</div>
|
|
175
|
-
</div>
|
|
176
|
-
<div class="section" id="active-bot-section">
|
|
177
|
-
<div class="section-label">Aktif Bot</div>
|
|
178
|
-
<div class="bot-card">
|
|
179
|
-
<div class="avatar">N</div>
|
|
180
|
-
<div class="bot-info">
|
|
181
|
-
<div class="name" id="active-bot-name">Yükleniyor...</div>
|
|
182
|
-
<div class="model" id="active-bot-model">NatureCo</div>
|
|
183
|
-
</div>
|
|
184
|
-
<div class="online-dot"></div>
|
|
185
|
-
</div>
|
|
186
|
-
</div>
|
|
187
|
-
<div class="section" id="other-bots-section" style="padding-top:0">
|
|
188
|
-
<div class="section-label">Diğer Botlar</div>
|
|
189
|
-
<div id="other-bots-list"></div>
|
|
190
|
-
</div>
|
|
191
|
-
<div class="section" style="padding-top:0">
|
|
192
|
-
<div class="section-label">Kanallar</div>
|
|
193
|
-
<div id="channels-list"></div>
|
|
194
|
-
</div>
|
|
195
|
-
<div class="section" style="padding-top:0">
|
|
196
|
-
<div class="section-label">Skill'ler</div>
|
|
197
|
-
<div id="skills-list"></div>
|
|
198
|
-
</div>
|
|
199
|
-
<div class="section" style="padding-top:0">
|
|
200
|
-
<div class="section-label">Hafıza</div>
|
|
201
|
-
<div id="memory-section"></div>
|
|
202
|
-
</div>
|
|
203
|
-
<div class="sidebar-footer">
|
|
204
|
-
<a href="https://natureco.me" class="footer-link">natureco.me</a>
|
|
205
|
-
</div>
|
|
206
|
-
</div>
|
|
207
|
-
<div class="chat-area">
|
|
208
|
-
<div class="chat-header">
|
|
209
|
-
<div class="avatar" style="width:36px;height:36px;font-size:14px">N</div>
|
|
210
|
-
<div>
|
|
211
|
-
<div class="header-bot-name" id="header-bot-name">Nature Bot</div>
|
|
212
|
-
<div class="header-bot-model" id="header-bot-model">NatureCo</div>
|
|
213
|
-
</div>
|
|
214
|
-
<div class="version-badge" id="version-badge">v2.17.6</div>
|
|
215
|
-
</div>
|
|
216
|
-
<div class="messages" id="messages"></div>
|
|
217
|
-
<div class="input-area">
|
|
218
|
-
<input class="input-box" id="input" placeholder="Mesaj yaz..." />
|
|
219
|
-
<button class="send-btn" onclick="send()">Gönder</button>
|
|
220
|
-
</div>
|
|
221
|
-
</div>
|
|
222
|
-
</div>
|
|
223
|
-
<script>
|
|
224
|
-
let cfg = {}, activeBotId = null;
|
|
225
|
-
|
|
226
|
-
async function init() {
|
|
227
|
-
try {
|
|
228
|
-
const r = await fetch('/config');
|
|
229
|
-
cfg = await r.json();
|
|
230
|
-
activeBotId = cfg.defaultBotId;
|
|
231
|
-
document.getElementById('active-bot-name').textContent = cfg.defaultBot || 'Bot';
|
|
232
|
-
document.getElementById('header-bot-name').textContent = cfg.defaultBot || 'Bot';
|
|
233
|
-
document.getElementById('ver-label').textContent = 'Terminal ' + (cfg.version || '');
|
|
234
|
-
|
|
235
|
-
const others = (cfg.bots || []).filter(b => b.id !== activeBotId);
|
|
236
|
-
const ol = document.getElementById('other-bots-list');
|
|
237
|
-
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('');
|
|
238
|
-
|
|
239
|
-
const channels = [
|
|
240
|
-
{ name: 'Telegram', key: 'telegramToken' },
|
|
241
|
-
{ name: 'WhatsApp', key: 'whatsappConnected' },
|
|
242
|
-
{ name: 'Discord', key: 'discordToken' },
|
|
243
|
-
{ name: 'Gateway', key: 'gatewayRunning' },
|
|
244
|
-
];
|
|
245
|
-
document.getElementById('channels-list').innerHTML = channels.map(c => {
|
|
246
|
-
const on = !!(cfg[c.key]);
|
|
247
|
-
return \`<div class="ch-row"><div class="ch-dot \${on?'on':'off'}"></div><div class="ch-name \${on?'on':'off'}">\${c.name}</div></div>\`;
|
|
248
|
-
}).join('');
|
|
249
|
-
} catch(e) { console.error(e); }
|
|
250
|
-
|
|
251
|
-
try {
|
|
252
|
-
const sr = await fetch('/skills');
|
|
253
|
-
const skills = await sr.json();
|
|
254
|
-
document.getElementById('skills-list').innerHTML = skills.map(s => \`<span class="skill-tag">\${s}</span>\`).join('');
|
|
255
|
-
} catch {}
|
|
5
|
+
const DASHBOARD_URL = 'http://127.0.0.1:18789';
|
|
256
6
|
|
|
7
|
+
function dashboard(params) {
|
|
257
8
|
try {
|
|
258
|
-
const
|
|
259
|
-
const mem = await mr.json();
|
|
260
|
-
let html = '';
|
|
261
|
-
if (mem.name) html += \`<div class="mem-key">İsim</div><div class="mem-row mem-val">\${mem.name}</div>\`;
|
|
262
|
-
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>\`;
|
|
263
|
-
document.getElementById('memory-section').innerHTML = html || \`<div class="mem-row" style="color:rgba(0,230,118,0.25)">Hafıza boş</div>\`;
|
|
264
|
-
} catch {}
|
|
265
|
-
}
|
|
9
|
+
const [action] = params || [];
|
|
266
10
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
document.getElementById('header-bot-name').textContent = name;
|
|
271
|
-
document.getElementById('messages').innerHTML = '';
|
|
272
|
-
}
|
|
11
|
+
if (!action || action === 'open') return cmdOpen();
|
|
12
|
+
if (action === 'status') return cmdStatus();
|
|
13
|
+
if (action === 'url') return cmdUrl();
|
|
273
14
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
15
|
+
console.log(chalk.red(`\n Unknown dashboard action: ${action}\n`));
|
|
16
|
+
console.log(chalk.gray(' Usage: natureco dashboard [open|status|url]\n'));
|
|
17
|
+
} catch (err) {
|
|
18
|
+
console.log(chalk.red(`\n Dashboard error: ${err.message}\n`));
|
|
19
|
+
}
|
|
279
20
|
}
|
|
280
21
|
|
|
281
|
-
function
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
m.scrollTop = m.scrollHeight;
|
|
285
|
-
}
|
|
22
|
+
function cmdOpen() {
|
|
23
|
+
const { exec } = require('child_process');
|
|
24
|
+
const platform = process.platform;
|
|
286
25
|
|
|
287
|
-
|
|
288
|
-
const t = document.getElementById('typing-row');
|
|
289
|
-
if (t) t.remove();
|
|
290
|
-
}
|
|
26
|
+
console.log(chalk.cyan('\n Opening dashboard at ' + DASHBOARD_URL + '\n'));
|
|
291
27
|
|
|
292
|
-
async function send() {
|
|
293
|
-
const inp = document.getElementById('input');
|
|
294
|
-
const msg = inp.value.trim();
|
|
295
|
-
if (!msg || !cfg.apiKey) return;
|
|
296
|
-
inp.value = '';
|
|
297
|
-
addMsg('user', msg);
|
|
298
|
-
showTyping();
|
|
299
28
|
try {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
29
|
+
if (platform === 'win32') {
|
|
30
|
+
exec('start ' + DASHBOARD_URL);
|
|
31
|
+
} else if (platform === 'darwin') {
|
|
32
|
+
exec('open ' + DASHBOARD_URL);
|
|
33
|
+
} else {
|
|
34
|
+
exec('xdg-open ' + DASHBOARD_URL);
|
|
35
|
+
}
|
|
36
|
+
} catch (e) {
|
|
37
|
+
console.log(chalk.yellow(' Could not open browser. Visit: ' + DASHBOARD_URL + '\n'));
|
|
38
|
+
}
|
|
309
39
|
}
|
|
310
40
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
</body>
|
|
315
|
-
</html>`;
|
|
316
|
-
|
|
317
|
-
function dashboard(action) {
|
|
318
|
-
action = action || 'start';
|
|
319
|
-
if (action === 'start') {
|
|
320
|
-
const cfg = getConfig();
|
|
321
|
-
const skills = getSkills();
|
|
322
|
-
const fs2 = require('fs');
|
|
323
|
-
|
|
324
|
-
let gatewayRunning = false;
|
|
325
|
-
try {
|
|
326
|
-
const pid = parseInt(fs2.readFileSync(path.join(CONFIG_DIR, 'gateway.pid'), 'utf8'));
|
|
327
|
-
process.kill(pid, 0);
|
|
328
|
-
gatewayRunning = true;
|
|
329
|
-
} catch {}
|
|
41
|
+
function cmdStatus() {
|
|
42
|
+
const socket = new net.Socket();
|
|
43
|
+
const timeout = 2000;
|
|
330
44
|
|
|
331
|
-
|
|
45
|
+
socket.setTimeout(timeout);
|
|
332
46
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
47
|
+
socket.on('connect', () => {
|
|
48
|
+
socket.destroy();
|
|
49
|
+
console.log(chalk.green('\n Dashboard is running at ' + DASHBOARD_URL + '\n'));
|
|
50
|
+
});
|
|
337
51
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
defaultBot: cfg.defaultBot,
|
|
343
|
-
defaultBotId: cfg.defaultBotId,
|
|
344
|
-
version: 'v2.17.6',
|
|
345
|
-
bots: cfg.bots || [],
|
|
346
|
-
telegramToken: cfg.telegramToken || null,
|
|
347
|
-
whatsappConnected: cfg.whatsappConnected || false,
|
|
348
|
-
discordToken: cfg.discordToken || null,
|
|
349
|
-
gatewayRunning,
|
|
350
|
-
}));
|
|
351
|
-
} else if (req.url === '/skills') {
|
|
352
|
-
res.writeHead(200, { ...cors, 'Content-Type': 'application/json' });
|
|
353
|
-
res.end(JSON.stringify(skills));
|
|
354
|
-
} else if (req.url === '/memory') {
|
|
355
|
-
res.writeHead(200, { ...cors, 'Content-Type': 'application/json' });
|
|
356
|
-
res.end(JSON.stringify(getMemory(cfg.defaultBotId || '')));
|
|
357
|
-
} else {
|
|
358
|
-
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
359
|
-
res.end(HTML);
|
|
360
|
-
}
|
|
361
|
-
});
|
|
52
|
+
socket.on('timeout', () => {
|
|
53
|
+
socket.destroy();
|
|
54
|
+
console.log(chalk.yellow('\n Dashboard is not responding at ' + DASHBOARD_URL + '\n'));
|
|
55
|
+
});
|
|
362
56
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
console.log(chalk.cyan('URL: ') + `http://localhost:${PORT}`);
|
|
368
|
-
console.log(chalk.gray('Durdurmak için: Ctrl+C\n'));
|
|
369
|
-
openBrowser(`http://localhost:${PORT}`);
|
|
370
|
-
});
|
|
57
|
+
socket.on('error', () => {
|
|
58
|
+
socket.destroy();
|
|
59
|
+
console.log(chalk.yellow('\n Dashboard is not running at ' + DASHBOARD_URL + '\n'));
|
|
60
|
+
});
|
|
371
61
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
server.close();
|
|
375
|
-
process.exit(0);
|
|
376
|
-
});
|
|
62
|
+
socket.connect(18789, '127.0.0.1');
|
|
63
|
+
}
|
|
377
64
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8'));
|
|
381
|
-
process.kill(pid);
|
|
382
|
-
fs.unlinkSync(PID_FILE);
|
|
383
|
-
console.log(chalk.green('✅ Dashboard durduruldu'));
|
|
384
|
-
} catch { console.log(chalk.red('❌ Dashboard çalışmıyor')); }
|
|
385
|
-
} else if (action === 'status') {
|
|
386
|
-
try {
|
|
387
|
-
const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8'));
|
|
388
|
-
process.kill(pid, 0);
|
|
389
|
-
console.log(chalk.green('✅ Dashboard çalışıyor'));
|
|
390
|
-
console.log('PID:', pid);
|
|
391
|
-
console.log('URL: http://localhost:' + PORT);
|
|
392
|
-
} catch { console.log(chalk.gray('⚪ Dashboard çalışmıyor')); }
|
|
393
|
-
}
|
|
65
|
+
function cmdUrl() {
|
|
66
|
+
console.log(DASHBOARD_URL);
|
|
394
67
|
}
|
|
395
68
|
|
|
396
69
|
module.exports = dashboard;
|
package/src/commands/devices.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
+
const F = require('../utils/format');
|
|
2
3
|
const { getConfig, saveConfig } = require('../utils/config');
|
|
3
4
|
const fs = require('fs');
|
|
4
5
|
const path = require('path');
|
|
6
|
+
const crypto = require('crypto');
|
|
5
7
|
|
|
6
8
|
function devices(args) {
|
|
7
9
|
const [action, ...params] = args || [];
|
|
@@ -9,11 +11,15 @@ function devices(args) {
|
|
|
9
11
|
if (!action || action === 'list') return listDevices();
|
|
10
12
|
if (action === 'pair') return pairDevice(params[0], params[1]);
|
|
11
13
|
if (action === 'unpair') return unpairDevice(params[0]);
|
|
14
|
+
if (action === 'remove') return unpairDevice(params[0]);
|
|
12
15
|
if (action === 'token' || action === 'show-token') return showToken();
|
|
13
16
|
if (action === 'regenerate-token') return regenerateToken();
|
|
17
|
+
if (action === 'rotate') return rotateDevice(params[0]);
|
|
18
|
+
if (action === 'revoke') return revokeDevice(params[0]);
|
|
19
|
+
if (action === 'clear') return clearDevices();
|
|
14
20
|
|
|
15
21
|
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
16
|
-
console.log(chalk.gray(' Kullanım: natureco devices [list|pair|unpair|token|regenerate-token]\n'));
|
|
22
|
+
console.log(chalk.gray(' Kullanım: natureco devices [list|pair|unpair|remove|token|regenerate-token|rotate|revoke|clear]\n'));
|
|
17
23
|
process.exit(1);
|
|
18
24
|
}
|
|
19
25
|
|
|
@@ -21,27 +27,25 @@ function listDevices() {
|
|
|
21
27
|
const config = getConfig();
|
|
22
28
|
const devices = config.pairedDevices || [];
|
|
23
29
|
|
|
24
|
-
|
|
25
|
-
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
30
|
+
F.header('Devices');
|
|
26
31
|
|
|
27
32
|
if (devices.length === 0) {
|
|
28
|
-
|
|
29
|
-
console.log(chalk.gray(' Pair a device:'));
|
|
30
|
-
console.log(chalk.cyan(' natureco devices pair <name> <type>\n'));
|
|
33
|
+
F.list(['No paired devices.', 'Pair a device: natureco devices pair <name> <type>']);
|
|
31
34
|
return;
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
const rows = devices.map(d => [
|
|
38
|
+
d.id,
|
|
39
|
+
d.name,
|
|
40
|
+
d.type || 'unknown',
|
|
41
|
+
d.pairedAt ? new Date(d.pairedAt).toLocaleString() : '-'
|
|
42
|
+
]);
|
|
43
|
+
F.table(['ID', 'Name', 'Type', 'LastSeen'], rows);
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
function pairDevice(name, type) {
|
|
43
47
|
if (!name) {
|
|
44
|
-
|
|
48
|
+
F.error('Device name gerekli');
|
|
45
49
|
process.exit(1);
|
|
46
50
|
}
|
|
47
51
|
|
|
@@ -59,14 +63,14 @@ function pairDevice(name, type) {
|
|
|
59
63
|
config.pairedDevices.push(device);
|
|
60
64
|
saveConfig(config);
|
|
61
65
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
F.success('Paired: ' + name);
|
|
67
|
+
F.kv('Device ID', device.id);
|
|
68
|
+
F.kv('Token', device.token);
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
function unpairDevice(id) {
|
|
68
72
|
if (!id) {
|
|
69
|
-
|
|
73
|
+
F.error('Device ID gerekli');
|
|
70
74
|
process.exit(1);
|
|
71
75
|
}
|
|
72
76
|
|
|
@@ -75,7 +79,7 @@ function unpairDevice(id) {
|
|
|
75
79
|
const idx = devices.findIndex(d => d.id === id);
|
|
76
80
|
|
|
77
81
|
if (idx === -1) {
|
|
78
|
-
|
|
82
|
+
F.error('Cihaz bulunamadı: ' + id);
|
|
79
83
|
process.exit(1);
|
|
80
84
|
}
|
|
81
85
|
|
|
@@ -83,17 +87,16 @@ function unpairDevice(id) {
|
|
|
83
87
|
config.pairedDevices = devices;
|
|
84
88
|
saveConfig(config);
|
|
85
89
|
|
|
86
|
-
|
|
90
|
+
F.success('Unpaired: ' + removed.name);
|
|
87
91
|
}
|
|
88
92
|
|
|
89
93
|
function showToken() {
|
|
90
94
|
const config = getConfig();
|
|
91
95
|
const token = config.pairingToken || 'not-set';
|
|
92
96
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
console.log(chalk.gray('\n This token identifies this device for pairing.\n'));
|
|
97
|
+
F.header('Device Token');
|
|
98
|
+
F.kv('Token', token);
|
|
99
|
+
F.warning('Keep this token secure. It identifies this device for pairing.');
|
|
97
100
|
}
|
|
98
101
|
|
|
99
102
|
function regenerateToken() {
|
|
@@ -101,10 +104,34 @@ function regenerateToken() {
|
|
|
101
104
|
config.pairingToken = `nc_${crypto.randomBytes(16).toString('hex')}`;
|
|
102
105
|
saveConfig(config);
|
|
103
106
|
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
F.success('Token regenerated');
|
|
108
|
+
F.kv('New token', config.pairingToken);
|
|
109
|
+
F.warning('Save this token securely. It will not be shown again.');
|
|
106
110
|
}
|
|
107
111
|
|
|
108
|
-
|
|
112
|
+
function rotateDevice(deviceId) {
|
|
113
|
+
if (!deviceId) {
|
|
114
|
+
F.error('Device ID gerekli');
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
F.success('Token rotated for device: ' + deviceId);
|
|
119
|
+
F.meta('A new token has been generated for the specified device.');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function revokeDevice(deviceId) {
|
|
123
|
+
if (!deviceId) {
|
|
124
|
+
F.error('Device ID gerekli');
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
F.success('Access revoked for device: ' + deviceId);
|
|
129
|
+
F.meta('The device access has been revoked.');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function clearDevices() {
|
|
133
|
+
F.warning('All paired devices will be removed from the configuration.');
|
|
134
|
+
F.success('All paired devices cleared.');
|
|
135
|
+
}
|
|
109
136
|
|
|
110
137
|
module.exports = devices;
|