natureco-cli 2.23.29 → 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/README.md +94 -11
- package/bin/natureco.js +495 -94
- package/package.json +1 -1
- package/src/commands/acp.js +39 -0
- package/src/commands/admin-rpc.js +302 -0
- package/src/commands/agent.js +280 -0
- package/src/commands/agents.js +114 -30
- package/src/commands/approvals.js +214 -0
- package/src/commands/backup.js +124 -0
- package/src/commands/bonjour.js +167 -0
- package/src/commands/browser.js +815 -0
- package/src/commands/capability.js +237 -0
- package/src/commands/channels.js +422 -267
- package/src/commands/chat.js +5 -8
- package/src/commands/clawbot.js +19 -0
- package/src/commands/clickclack.js +130 -0
- package/src/commands/code.js +3 -2
- package/src/commands/commitments.js +148 -0
- package/src/commands/completion.js +84 -0
- package/src/commands/config.js +219 -30
- package/src/commands/configure.js +110 -0
- package/src/commands/crestodian.js +92 -0
- package/src/commands/cron.js +239 -19
- package/src/commands/daemon.js +90 -0
- package/src/commands/dashboard.js +47 -374
- package/src/commands/device-pair.js +248 -0
- package/src/commands/devices.js +137 -0
- package/src/commands/directory.js +179 -0
- package/src/commands/dns.js +196 -0
- package/src/commands/docs.js +136 -0
- package/src/commands/doctor.js +143 -492
- package/src/commands/exec-policy.js +80 -0
- package/src/commands/gateway-server.js +1155 -24
- package/src/commands/gateway.js +492 -249
- package/src/commands/health.js +148 -0
- package/src/commands/help.js +24 -25
- package/src/commands/hooks.js +141 -87
- package/src/commands/imessage.js +128 -14
- package/src/commands/infer.js +1474 -0
- package/src/commands/irc.js +64 -15
- package/src/commands/logs.js +122 -99
- package/src/commands/mattermost.js +114 -12
- package/src/commands/mcp.js +121 -309
- package/src/commands/memory-cmd.js +134 -1
- package/src/commands/memory.js +128 -0
- package/src/commands/message.js +720 -134
- package/src/commands/migrate.js +213 -2
- package/src/commands/models.js +39 -1
- package/src/commands/node.js +98 -0
- package/src/commands/nodes.js +362 -0
- package/src/commands/oc-path.js +200 -0
- package/src/commands/onboard.js +129 -0
- package/src/commands/open-prose.js +67 -0
- package/src/commands/pairing.js +108 -107
- package/src/commands/path.js +206 -0
- package/src/commands/plugins.js +35 -1
- package/src/commands/policy.js +176 -0
- package/src/commands/proxy.js +306 -0
- package/src/commands/qr.js +70 -0
- package/src/commands/reset.js +101 -94
- package/src/commands/sandbox.js +125 -0
- package/src/commands/secrets.js +201 -0
- package/src/commands/sessions.js +110 -51
- package/src/commands/setup.js +102 -543
- package/src/commands/signal.js +447 -18
- package/src/commands/skills.js +67 -1
- package/src/commands/sms.js +123 -19
- package/src/commands/status.js +101 -127
- package/src/commands/system.js +53 -0
- package/src/commands/tasks.js +208 -100
- package/src/commands/terminal.js +139 -0
- package/src/commands/thread-ownership.js +157 -0
- package/src/commands/transcripts.js +95 -0
- package/src/commands/tui.js +41 -0
- package/src/commands/uninstall.js +73 -92
- package/src/commands/update.js +146 -91
- package/src/commands/voice.js +82 -0
- package/src/commands/vydra.js +98 -0
- package/src/commands/webhooks.js +58 -66
- package/src/commands/wiki.js +783 -0
- package/src/commands/workboard.js +207 -0
- package/src/tools/audio_understanding.js +154 -0
- package/src/tools/browser.js +112 -0
- package/src/tools/canvas.js +104 -0
- package/src/tools/document_extract.js +84 -0
- package/src/tools/duckduckgo.js +54 -0
- package/src/tools/exa_search.js +66 -0
- package/src/tools/firecrawl.js +104 -0
- package/src/tools/image_generation.js +99 -0
- package/src/tools/llm_task.js +118 -0
- package/src/tools/media_understanding.js +128 -0
- package/src/tools/music_generation.js +113 -0
- package/src/tools/parallel_search.js +77 -0
- package/src/tools/phone_control.js +80 -0
- package/src/tools/phone_control_enhanced.js +184 -0
- package/src/tools/searxng.js +61 -0
- package/src/tools/speech_to_text.js +135 -0
- package/src/tools/text_to_speech.js +105 -0
- package/src/tools/thread_ownership.js +88 -0
- package/src/tools/video_generation.js +72 -0
- package/src/tools/web_readability.js +104 -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/memory.js +200 -0
- 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
package/src/commands/doctor.js
CHANGED
|
@@ -1,492 +1,143 @@
|
|
|
1
|
-
const chalk = require('chalk');
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (
|
|
39
|
-
console.log(chalk.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
console.log(chalk.yellow('⚠️ MCP sunucuları:'), chalk.white('Kayıtlı sunucu yok'));
|
|
145
|
-
results.push({ status: 'warning', message: 'MCP sunucusu yok' });
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// 7. Hafıza kontrolü
|
|
149
|
-
total++;
|
|
150
|
-
const memoryDir = path.join(CONFIG_DIR, 'memory');
|
|
151
|
-
let memoryActive = false;
|
|
152
|
-
|
|
153
|
-
if (fs.existsSync(memoryDir)) {
|
|
154
|
-
try {
|
|
155
|
-
const files = fs.readdirSync(memoryDir);
|
|
156
|
-
const memoryFiles = files.filter(f => f.endsWith('.json'));
|
|
157
|
-
if (memoryFiles.length > 0) {
|
|
158
|
-
memoryActive = true;
|
|
159
|
-
console.log(chalk.green('✅ Hafıza:'), chalk.white(`Aktif (${memoryFiles.length} dosya)`));
|
|
160
|
-
passed++;
|
|
161
|
-
results.push({ status: 'ok', message: `Hafıza aktif (${memoryFiles.length} dosya)` });
|
|
162
|
-
} else {
|
|
163
|
-
console.log(chalk.yellow('⚠️ Hafıza:'), chalk.white('Klasör var, dosya yok'));
|
|
164
|
-
results.push({ status: 'warning', message: 'Hafıza dosyası yok' });
|
|
165
|
-
}
|
|
166
|
-
} catch (err) {
|
|
167
|
-
console.log(chalk.yellow('⚠️ Hafıza:'), chalk.white('Kontrol edilemedi'));
|
|
168
|
-
results.push({ status: 'warning', message: 'Hafıza kontrol edilemedi' });
|
|
169
|
-
}
|
|
170
|
-
} else {
|
|
171
|
-
console.log(chalk.yellow('⚠️ Hafıza:'), chalk.white('Pasif'));
|
|
172
|
-
results.push({ status: 'warning', message: 'Hafıza pasif' });
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// 8. Telegram kontrolü (opsiyonel)
|
|
176
|
-
if (config && config.telegramToken) {
|
|
177
|
-
console.log(chalk.green('✅ Telegram:'), chalk.white('Bağlı'));
|
|
178
|
-
results.push({ status: 'ok', message: 'Telegram bağlı', optional: true });
|
|
179
|
-
} else {
|
|
180
|
-
console.log(chalk.gray('⚪ Telegram:'), chalk.white('Bağlı değil'));
|
|
181
|
-
results.push({ status: 'info', message: 'Telegram bağlı değil', optional: true });
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// 9. Discord kontrolü (opsiyonel)
|
|
185
|
-
if (config && config.discordToken) {
|
|
186
|
-
console.log(chalk.green('✅ Discord:'), chalk.white('Bağlı'));
|
|
187
|
-
results.push({ status: 'ok', message: 'Discord bağlı', optional: true });
|
|
188
|
-
} else {
|
|
189
|
-
console.log(chalk.gray('⚪ Discord:'), chalk.white('Bağlı değil'));
|
|
190
|
-
results.push({ status: 'info', message: 'Discord bağlı değil', optional: true });
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// 10. Slack kontrolü (opsiyonel)
|
|
194
|
-
if (config && config.slackToken) {
|
|
195
|
-
console.log(chalk.green('✅ Slack:'), chalk.white('Bağlı'));
|
|
196
|
-
results.push({ status: 'ok', message: 'Slack bağlı', optional: true });
|
|
197
|
-
} else {
|
|
198
|
-
console.log(chalk.gray('⚪ Slack:'), chalk.white('Bağlı değil'));
|
|
199
|
-
results.push({ status: 'info', message: 'Slack bağlı değil', optional: true });
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// 11. WhatsApp kontrolü (opsiyonel)
|
|
203
|
-
if (config && config.whatsappConnected) {
|
|
204
|
-
console.log(chalk.green('✅ WhatsApp:'), chalk.white('Bağlı'));
|
|
205
|
-
results.push({ status: 'ok', message: 'WhatsApp bağlı', optional: true });
|
|
206
|
-
} else {
|
|
207
|
-
console.log(chalk.gray('⚪ WhatsApp:'), chalk.white('Bağlı değil'));
|
|
208
|
-
results.push({ status: 'info', message: 'WhatsApp bağlı değil', optional: true });
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// 12. Dashboard kontrolü (opsiyonel)
|
|
212
|
-
const dashboardRunning = await checkPort(3848);
|
|
213
|
-
if (dashboardRunning) {
|
|
214
|
-
console.log(chalk.green('✅ Dashboard:'), chalk.white('Çalışıyor (port 3848)'));
|
|
215
|
-
results.push({ status: 'ok', message: 'Dashboard çalışıyor', optional: true });
|
|
216
|
-
} else {
|
|
217
|
-
console.log(chalk.gray('⚪ Dashboard:'), chalk.white('Çalışmıyor'));
|
|
218
|
-
results.push({ status: 'info', message: 'Dashboard çalışmıyor', fix: 'natureco dashboard start', optional: true });
|
|
219
|
-
|
|
220
|
-
if (shouldFix) {
|
|
221
|
-
console.log(chalk.yellow(' 🔧 Dashboard başlatılıyor...'));
|
|
222
|
-
console.log(chalk.gray(' Lütfen manuel başlatın: natureco dashboard start'));
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// 13. Gateway kontrolü (opsiyonel)
|
|
227
|
-
const gatewayPidFile = path.join(CONFIG_DIR, 'gateway.pid');
|
|
228
|
-
let gatewayRunning = false;
|
|
229
|
-
|
|
230
|
-
if (fs.existsSync(gatewayPidFile)) {
|
|
231
|
-
try {
|
|
232
|
-
const pid = parseInt(fs.readFileSync(gatewayPidFile, 'utf-8').trim());
|
|
233
|
-
|
|
234
|
-
// Check if process is running
|
|
235
|
-
try {
|
|
236
|
-
process.kill(pid, 0); // Signal 0 checks if process exists
|
|
237
|
-
gatewayRunning = true;
|
|
238
|
-
console.log(chalk.green('✅ Gateway:'), chalk.white(`Çalışıyor (PID: ${pid})`));
|
|
239
|
-
results.push({ status: 'ok', message: 'Gateway çalışıyor', optional: true });
|
|
240
|
-
} catch {
|
|
241
|
-
console.log(chalk.yellow('⚠️ Gateway:'), chalk.white('PID dosyası var ama process çalışmıyor'));
|
|
242
|
-
results.push({ status: 'warning', message: 'Gateway PID stale', fix: 'natureco gateway start', optional: true });
|
|
243
|
-
}
|
|
244
|
-
} catch {
|
|
245
|
-
console.log(chalk.gray('⚪ Gateway:'), chalk.white('PID dosyası okunamadı'));
|
|
246
|
-
results.push({ status: 'info', message: 'Gateway PID okunamadı', optional: true });
|
|
247
|
-
}
|
|
248
|
-
} else {
|
|
249
|
-
console.log(chalk.gray('⚪ Gateway:'), chalk.white('Çalışmıyor'));
|
|
250
|
-
results.push({ status: 'info', message: 'Gateway çalışmıyor', fix: 'natureco gateway start', optional: true });
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// 14. Tavily API key kontrolü (web search için)
|
|
254
|
-
total++;
|
|
255
|
-
if (config && config.tavilyApiKey) {
|
|
256
|
-
console.log(chalk.green('✅ Tavily API:'), chalk.white(config.tavilyApiKey.slice(0, 10) + '...'));
|
|
257
|
-
passed++;
|
|
258
|
-
results.push({ status: 'ok', message: 'Tavily API key ayarlanmış' });
|
|
259
|
-
} else {
|
|
260
|
-
console.log(chalk.yellow('⚠️ Tavily API:'), chalk.white('Ayarlanmamış (web search çalışmayacak)'));
|
|
261
|
-
results.push({ status: 'warning', message: 'Tavily API key yok', fix: 'natureco config set tavilyApiKey tvly_xxx' });
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// 15. Provider erişim kontrolü (gerçek API doğrulama)
|
|
265
|
-
total++;
|
|
266
|
-
criticalTotal++;
|
|
267
|
-
if (config && config.providerUrl) {
|
|
268
|
-
try {
|
|
269
|
-
const response = await fetch(config.providerUrl, {
|
|
270
|
-
method: 'POST',
|
|
271
|
-
headers: {
|
|
272
|
-
'Content-Type': 'application/json',
|
|
273
|
-
...(config.providerApiKey ? { 'Authorization': `Bearer ${config.providerApiKey}` } : {}),
|
|
274
|
-
},
|
|
275
|
-
body: JSON.stringify({
|
|
276
|
-
model: config.providerModel || 'llama-3.3-70b-versatile',
|
|
277
|
-
messages: [{ role: 'user', content: 'test' }],
|
|
278
|
-
max_tokens: 1,
|
|
279
|
-
}),
|
|
280
|
-
signal: AbortSignal.timeout(15000),
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
if (response.ok) {
|
|
284
|
-
console.log(chalk.green('✅ Provider:'), chalk.white('API doğrulandı'));
|
|
285
|
-
passed++;
|
|
286
|
-
criticalPassed++;
|
|
287
|
-
results.push({ status: 'ok', message: 'Provider API doğrulandı' });
|
|
288
|
-
} else if (response.status === 401 || response.status === 403) {
|
|
289
|
-
console.log(chalk.red('❌ Provider:'), chalk.white('API key geçersiz'));
|
|
290
|
-
results.push({ status: 'error', message: 'API key reddedildi', fix: 'natureco config set providerApiKey <key>' });
|
|
291
|
-
} else {
|
|
292
|
-
console.log(chalk.yellow('⚠️ Provider:'), chalk.white(`HTTP ${response.status} — beklenmeyen yanıt`));
|
|
293
|
-
results.push({ status: 'warning', message: `Provider HTTP ${response.status} döndü` });
|
|
294
|
-
}
|
|
295
|
-
} catch (err) {
|
|
296
|
-
console.log(chalk.red('❌ Provider:'), chalk.white('Bağlantı hatası: ' + err.message));
|
|
297
|
-
results.push({ status: 'error', message: 'Provider bağlantı hatası' });
|
|
298
|
-
}
|
|
299
|
-
} else {
|
|
300
|
-
console.log(chalk.gray('⚪ Provider Erişim:'), chalk.white('Provider URL ayarlanmamış'));
|
|
301
|
-
results.push({ status: 'info', message: 'Provider URL yok' });
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// 16. Güncelleme kontrolü
|
|
305
|
-
total++;
|
|
306
|
-
try {
|
|
307
|
-
const packageJson = require('../../package.json');
|
|
308
|
-
const currentVersion = packageJson.version;
|
|
309
|
-
|
|
310
|
-
const response = await fetch('https://registry.npmjs.org/natureco-cli/latest', {
|
|
311
|
-
signal: AbortSignal.timeout(5000),
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
if (response.ok) {
|
|
315
|
-
const data = await response.json();
|
|
316
|
-
const latestVersion = data.version;
|
|
317
|
-
|
|
318
|
-
if (currentVersion === latestVersion) {
|
|
319
|
-
console.log(chalk.green('✅ Versiyon:'), chalk.white(`${currentVersion} (güncel)`));
|
|
320
|
-
passed++;
|
|
321
|
-
results.push({ status: 'ok', message: 'Versiyon güncel' });
|
|
322
|
-
} else {
|
|
323
|
-
console.log(chalk.yellow('⚠️ Versiyon:'), chalk.white(`${currentVersion} → ${latestVersion} mevcut`));
|
|
324
|
-
results.push({ status: 'warning', message: 'Yeni versiyon mevcut', fix: 'npm install -g natureco-cli@latest' });
|
|
325
|
-
|
|
326
|
-
if (shouldFix) {
|
|
327
|
-
console.log(chalk.yellow(' 🔧 Güncelleme başlatılıyor...'));
|
|
328
|
-
console.log(chalk.gray(' Lütfen manuel güncelleyin: npm install -g natureco-cli@latest'));
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
} else {
|
|
332
|
-
console.log(chalk.gray('⚪ Versiyon:'), chalk.white('Kontrol edilemedi'));
|
|
333
|
-
results.push({ status: 'info', message: 'Versiyon kontrol edilemedi' });
|
|
334
|
-
}
|
|
335
|
-
} catch (err) {
|
|
336
|
-
console.log(chalk.red('Bağlantı hatası: ' + err.message));
|
|
337
|
-
results.push({ status: 'info', message: 'Versiyon kontrol edilemedi' });
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// 17. Exec approvals kontrolü
|
|
341
|
-
total++;
|
|
342
|
-
const approvals = loadApprovals();
|
|
343
|
-
const policy = resolveEffectivePolicy(approvals);
|
|
344
|
-
const allowlistCount = (approvals.allowlist || []).length;
|
|
345
|
-
if (policy !== 'deny' || allowlistCount > 0) {
|
|
346
|
-
passed++;
|
|
347
|
-
results.push({ status: 'ok', message: `Güvenlik: ${policy} (${allowlistCount} allowlist)` });
|
|
348
|
-
console.log(chalk.green('✅ Exec Güvenlik:'), chalk.white(`${policy} — ${allowlistCount} allowlist kuralı`));
|
|
349
|
-
} else {
|
|
350
|
-
results.push({ status: 'warning', message: 'Exec güvenlik deny modunda', fix: 'natureco security policy set allowlist' });
|
|
351
|
-
console.log(chalk.yellow('⚠️ Exec Güvenlik:'), chalk.white('deny modunda, komut çalıştırma engelli'));
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// 18. Exec approvals allowlist durumu (opsiyonel detay)
|
|
355
|
-
if (allowlistCount > 0) {
|
|
356
|
-
const expired = (approvals.allowlist || []).filter(e => e.expires && new Date(e.expires) < new Date()).length;
|
|
357
|
-
if (expired > 0) {
|
|
358
|
-
console.log(chalk.yellow(` ⚠ ${expired} allowlist kuralı süresi dolmuş`));
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// 19. Config yedekleri kontrolü
|
|
363
|
-
total++;
|
|
364
|
-
try {
|
|
365
|
-
const backupDir = path.join(CONFIG_DIR, 'backups');
|
|
366
|
-
if (fs.existsSync(backupDir)) {
|
|
367
|
-
const backups = fs.readdirSync(backupDir).filter(f => f.startsWith('config-') && f.endsWith('.json'));
|
|
368
|
-
if (backups.length > 0) {
|
|
369
|
-
passed++;
|
|
370
|
-
results.push({ status: 'ok', message: `${backups.length} config yedeği mevcut` });
|
|
371
|
-
console.log(chalk.green('✅ Config Yedek:'), chalk.white(`${backups.length} yedek`));
|
|
372
|
-
|
|
373
|
-
if (backups.length >= 10) {
|
|
374
|
-
console.log(chalk.yellow(' ⚠ Maksimum yedek sayısına ulaşıldı (10)'));
|
|
375
|
-
}
|
|
376
|
-
} else {
|
|
377
|
-
results.push({ status: 'info', message: 'Config yedeği yok' });
|
|
378
|
-
console.log(chalk.gray('⚪ Config Yedek:'), chalk.white('Yedek bulunamadı'));
|
|
379
|
-
}
|
|
380
|
-
} else {
|
|
381
|
-
results.push({ status: 'info', message: 'Config yedeği yok' });
|
|
382
|
-
console.log(chalk.gray('⚪ Config Yedek:'), chalk.white('Yedek klasörü yok'));
|
|
383
|
-
}
|
|
384
|
-
} catch {
|
|
385
|
-
results.push({ status: 'info', message: 'Config yedekleri kontrol edilemedi' });
|
|
386
|
-
console.log(chalk.gray('⚪ Config Yedek:'), chalk.white('Kontrol edilemedi'));
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// 20. Secret referansları kontrolü
|
|
390
|
-
total++;
|
|
391
|
-
try {
|
|
392
|
-
const secretRefs = listSecretRefs(config || {});
|
|
393
|
-
if (secretRefs.length > 0) {
|
|
394
|
-
const unresolved = secretRefs.filter(ref => {
|
|
395
|
-
try {
|
|
396
|
-
return resolveSecretRef(ref) === null;
|
|
397
|
-
} catch {
|
|
398
|
-
return true;
|
|
399
|
-
}
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
if (unresolved.length === 0) {
|
|
403
|
-
passed++;
|
|
404
|
-
results.push({ status: 'ok', message: `${secretRefs.length} secret referansı çözüldü` });
|
|
405
|
-
console.log(chalk.green('✅ Secrets:'), chalk.white(`${secretRefs.length} referans çözüldü`));
|
|
406
|
-
} else {
|
|
407
|
-
results.push({ status: 'warning', message: `${unresolved.length}/${secretRefs.length} secret çözülemedi`, fix: '.env dosyası oluşturun' });
|
|
408
|
-
console.log(chalk.yellow('⚠️ Secrets:'), chalk.white(`${unresolved.length}/${secretRefs.length} referans çözülemedi`));
|
|
409
|
-
}
|
|
410
|
-
} else {
|
|
411
|
-
results.push({ status: 'info', message: 'Secret referansı yok' });
|
|
412
|
-
console.log(chalk.gray('⚪ Secrets:'), chalk.white('Referans yok'));
|
|
413
|
-
}
|
|
414
|
-
} catch {
|
|
415
|
-
results.push({ status: 'info', message: 'Secrets kontrol edilemedi' });
|
|
416
|
-
console.log(chalk.gray('⚪ Secrets:'), chalk.white('Kontrol edilemedi'));
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// 21. .env dosyası varlığı (secret ref varsa)
|
|
420
|
-
if (config) {
|
|
421
|
-
const envFile = path.join(CONFIG_DIR, '.env');
|
|
422
|
-
if (fs.existsSync(envFile)) {
|
|
423
|
-
console.log(chalk.gray(' 📄 .env dosyası:'), chalk.white('Mevcut'));
|
|
424
|
-
} else {
|
|
425
|
-
console.log(chalk.gray(' 📄 .env dosyası:'), chalk.white('Yok'));
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// Özet
|
|
430
|
-
console.log('');
|
|
431
|
-
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
432
|
-
|
|
433
|
-
const criticalPercentage = criticalTotal > 0 ? Math.round((criticalPassed / criticalTotal) * 100) : 100;
|
|
434
|
-
let statusColor = chalk.green;
|
|
435
|
-
let statusText = 'Mükemmel';
|
|
436
|
-
|
|
437
|
-
if (criticalPercentage < 75) {
|
|
438
|
-
statusColor = chalk.red;
|
|
439
|
-
statusText = 'Kritik sorun var';
|
|
440
|
-
} else if (criticalPercentage < 100) {
|
|
441
|
-
statusColor = chalk.yellow;
|
|
442
|
-
statusText = 'Dikkat gerekiyor';
|
|
443
|
-
} else if (passed < total) {
|
|
444
|
-
statusColor = chalk.cyan;
|
|
445
|
-
statusText = 'İyi';
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
console.log('');
|
|
449
|
-
console.log(chalk.gray(' Durum : ') + statusColor.bold(statusText));
|
|
450
|
-
console.log(chalk.gray(' Kontrol : ') + chalk.white(`${passed}/${total} geçti`));
|
|
451
|
-
console.log(chalk.gray(' Kritik : ') + chalk.white(`${criticalPassed}/${criticalTotal}`));
|
|
452
|
-
|
|
453
|
-
const errors = results.filter(r => r.status === 'error');
|
|
454
|
-
const warnings = results.filter(r => r.status === 'warning');
|
|
455
|
-
|
|
456
|
-
if (errors.length > 0) {
|
|
457
|
-
console.log(chalk.red(`\n ❌ ${errors.length} hata bulundu`));
|
|
458
|
-
}
|
|
459
|
-
if (warnings.length > 0) {
|
|
460
|
-
console.log(chalk.yellow(` ⚠ ${warnings.length} uyarı bulundu`));
|
|
461
|
-
}
|
|
462
|
-
if (!shouldFix && (errors.length > 0 || warnings.length > 0)) {
|
|
463
|
-
console.log(chalk.gray('\n Otomatik onarım: ') + chalk.cyan('natureco doctor --fix'));
|
|
464
|
-
}
|
|
465
|
-
console.log('');
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
function checkPort(port) {
|
|
469
|
-
return new Promise((resolve) => {
|
|
470
|
-
const socket = new net.Socket();
|
|
471
|
-
|
|
472
|
-
socket.setTimeout(1000);
|
|
473
|
-
|
|
474
|
-
socket.on('connect', () => {
|
|
475
|
-
socket.destroy();
|
|
476
|
-
resolve(true);
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
socket.on('timeout', () => {
|
|
480
|
-
socket.destroy();
|
|
481
|
-
resolve(false);
|
|
482
|
-
});
|
|
483
|
-
|
|
484
|
-
socket.on('error', () => {
|
|
485
|
-
resolve(false);
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
socket.connect(port, '127.0.0.1');
|
|
489
|
-
});
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
module.exports = doctor;
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const F = require('../utils/format');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
|
|
7
|
+
const BASE_DIR = path.join(os.homedir(), '.natureco');
|
|
8
|
+
const CONFIG_FILE = path.join(BASE_DIR, 'config.json');
|
|
9
|
+
|
|
10
|
+
const CHECKS = [
|
|
11
|
+
{ name: 'configExists', label: 'Config file exists' },
|
|
12
|
+
{ name: 'nodeVersion', label: 'Node.js version >= 18' },
|
|
13
|
+
{ name: 'npmPackages', label: 'Required npm packages installed' },
|
|
14
|
+
{ name: 'diskSpace', label: 'Sufficient disk space' },
|
|
15
|
+
{ name: 'writePermission', label: 'Write permission on ~/.natureco' },
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
function doctor(params) {
|
|
19
|
+
try {
|
|
20
|
+
const [action, checkName] = params || [];
|
|
21
|
+
|
|
22
|
+
if (!action || action === 'run') return cmdRun();
|
|
23
|
+
if (action === 'list') return cmdList();
|
|
24
|
+
if (action === 'check') return cmdCheck(checkName);
|
|
25
|
+
|
|
26
|
+
console.log(chalk.red(`\n Unknown doctor action: ${action}\n`));
|
|
27
|
+
console.log(chalk.gray(' Usage: natureco doctor [run|list|check <name>]\n'));
|
|
28
|
+
} catch (err) {
|
|
29
|
+
console.log(chalk.red(`\n Doctor error: ${err.message}\n`));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function cmdList() {
|
|
34
|
+
F.list(CHECKS.map(c => ({ label: c.name, value: c.label })));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function cmdCheck(name) {
|
|
38
|
+
if (!name) {
|
|
39
|
+
console.log(chalk.red('\n Usage: natureco doctor check <name>\n'));
|
|
40
|
+
console.log(chalk.gray(' Available checks: ' + CHECKS.map(c => c.name).join(', ') + '\n'));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const check = CHECKS.find(c => c.name === name);
|
|
45
|
+
if (!check) {
|
|
46
|
+
console.log(chalk.red(`\n Unknown check: ${name}\n`));
|
|
47
|
+
console.log(chalk.gray(' Available checks: ' + CHECKS.map(c => c.name).join(', ') + '\n'));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const result = runCheck(name);
|
|
52
|
+
F.kv('Check', check.label);
|
|
53
|
+
if (result.pass) {
|
|
54
|
+
F.success(result.message);
|
|
55
|
+
} else {
|
|
56
|
+
F.error(result.message);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function cmdRun() {
|
|
61
|
+
F.header('System Doctor');
|
|
62
|
+
|
|
63
|
+
const rows = [];
|
|
64
|
+
let passed = 0;
|
|
65
|
+
let failed = 0;
|
|
66
|
+
|
|
67
|
+
for (const check of CHECKS) {
|
|
68
|
+
const result = runCheck(check.name);
|
|
69
|
+
rows.push([
|
|
70
|
+
check.label,
|
|
71
|
+
result.pass ? '✓' : '✗',
|
|
72
|
+
result.message,
|
|
73
|
+
]);
|
|
74
|
+
if (result.pass) passed++; else failed++;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
F.table(['Check', 'Status', 'Message'], rows);
|
|
78
|
+
|
|
79
|
+
const total = passed + failed;
|
|
80
|
+
F.meta(`${passed}/${total} checks passed`);
|
|
81
|
+
|
|
82
|
+
if (failed > 0) {
|
|
83
|
+
F.warning('Some checks failed. Run individual checks for details.');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function runCheck(name) {
|
|
88
|
+
switch (name) {
|
|
89
|
+
case 'configExists':
|
|
90
|
+
return {
|
|
91
|
+
pass: fs.existsSync(CONFIG_FILE),
|
|
92
|
+
message: fs.existsSync(CONFIG_FILE) ? 'Found at ' + CONFIG_FILE : 'Missing at ' + CONFIG_FILE,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
case 'nodeVersion': {
|
|
96
|
+
const v = process.version.slice(1).split('.')[0];
|
|
97
|
+
const ok = parseInt(v) >= 18;
|
|
98
|
+
return {
|
|
99
|
+
pass: ok,
|
|
100
|
+
message: ok ? 'Running Node ' + process.version : 'Node 18+ required, found ' + process.version,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
case 'npmPackages': {
|
|
105
|
+
const required = ['chalk', 'commander'];
|
|
106
|
+
const missing = required.filter(p => { try { require.resolve(p); return false; } catch { return true; } });
|
|
107
|
+
return {
|
|
108
|
+
pass: missing.length === 0,
|
|
109
|
+
message: missing.length === 0 ? 'All dependencies installed' : 'Missing: ' + missing.join(', '),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
case 'diskSpace': {
|
|
114
|
+
try {
|
|
115
|
+
const stats = require('os').freemem();
|
|
116
|
+
const freeGB = stats / 1024 / 1024 / 1024;
|
|
117
|
+
return {
|
|
118
|
+
pass: freeGB > 0.5,
|
|
119
|
+
message: freeGB > 0.5 ? `${freeGB.toFixed(1)} GB free` : 'Less than 500 MB free',
|
|
120
|
+
};
|
|
121
|
+
} catch {
|
|
122
|
+
return { pass: true, message: 'Unable to check' };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
case 'writePermission': {
|
|
127
|
+
try {
|
|
128
|
+
if (!fs.existsSync(BASE_DIR)) fs.mkdirSync(BASE_DIR, { recursive: true });
|
|
129
|
+
const testFile = path.join(BASE_DIR, '.write-test');
|
|
130
|
+
fs.writeFileSync(testFile, 'test');
|
|
131
|
+
fs.unlinkSync(testFile);
|
|
132
|
+
return { pass: true, message: 'Write access OK' };
|
|
133
|
+
} catch (e) {
|
|
134
|
+
return { pass: false, message: e.message };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
default:
|
|
139
|
+
return { pass: false, message: 'Unknown check' };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
module.exports = doctor;
|