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.
Files changed (67) hide show
  1. package/bin/natureco.js +166 -163
  2. package/package.json +1 -1
  3. package/src/commands/acp.js +39 -0
  4. package/src/commands/admin-rpc.js +83 -0
  5. package/src/commands/agent.js +214 -23
  6. package/src/commands/agents.js +114 -30
  7. package/src/commands/approvals.js +172 -11
  8. package/src/commands/browser.js +815 -0
  9. package/src/commands/capability.js +195 -22
  10. package/src/commands/channels.js +422 -267
  11. package/src/commands/chat.js +5 -8
  12. package/src/commands/clawbot.js +19 -0
  13. package/src/commands/code.js +3 -2
  14. package/src/commands/commitments.js +125 -9
  15. package/src/commands/completion.js +40 -32
  16. package/src/commands/config.js +219 -30
  17. package/src/commands/configure.js +84 -67
  18. package/src/commands/cron.js +239 -19
  19. package/src/commands/daemon.js +34 -4
  20. package/src/commands/dashboard.js +47 -374
  21. package/src/commands/devices.js +53 -26
  22. package/src/commands/directory.js +146 -14
  23. package/src/commands/dns.js +148 -10
  24. package/src/commands/docs.js +119 -26
  25. package/src/commands/doctor.js +143 -492
  26. package/src/commands/exec-policy.js +57 -48
  27. package/src/commands/gateway.js +492 -249
  28. package/src/commands/health.js +141 -11
  29. package/src/commands/help.js +24 -25
  30. package/src/commands/hooks.js +141 -87
  31. package/src/commands/infer.js +1442 -41
  32. package/src/commands/logs.js +122 -99
  33. package/src/commands/mcp.js +121 -309
  34. package/src/commands/memory.js +128 -0
  35. package/src/commands/message.js +720 -140
  36. package/src/commands/models.js +39 -1
  37. package/src/commands/node.js +77 -77
  38. package/src/commands/nodes.js +278 -22
  39. package/src/commands/onboard.js +115 -56
  40. package/src/commands/pairing.js +108 -107
  41. package/src/commands/path.js +206 -0
  42. package/src/commands/plugins.js +35 -1
  43. package/src/commands/proxy.js +159 -8
  44. package/src/commands/qr.js +55 -13
  45. package/src/commands/reset.js +101 -94
  46. package/src/commands/secrets.js +104 -21
  47. package/src/commands/sessions.js +110 -51
  48. package/src/commands/setup.js +102 -649
  49. package/src/commands/skills.js +67 -1
  50. package/src/commands/status.js +101 -127
  51. package/src/commands/tasks.js +208 -100
  52. package/src/commands/terminal.js +130 -12
  53. package/src/commands/transcripts.js +24 -1
  54. package/src/commands/tui.js +41 -0
  55. package/src/commands/uninstall.js +73 -92
  56. package/src/commands/update.js +146 -91
  57. package/src/commands/webhooks.js +58 -66
  58. package/src/commands/wiki.js +783 -0
  59. package/src/utils/agents-md.js +85 -0
  60. package/src/utils/api.js +39 -40
  61. package/src/utils/format.js +144 -0
  62. package/src/utils/headless.js +2 -1
  63. package/src/utils/parallel-tools.js +106 -0
  64. package/src/utils/sub-agent.js +148 -0
  65. package/src/utils/token-budget.js +304 -0
  66. package/src/utils/tool-runner.js +7 -5
  67. package/src/utils/web-fetch.js +107 -0
@@ -1,5 +1,7 @@
1
1
  const chalk = require('chalk');
2
+ const F = require('../utils/format');
2
3
  const { listTasks, getTask, cancelTask, auditTasks, maintenanceTasks, getTaskSummary, TASK_STATUSES, RUNTIME_TYPES } = require('../utils/background');
4
+ const { spawnSubAgent, spawnParallel, getStatus } = require('../utils/sub-agent');
3
5
 
4
6
  function parseFlags(args) {
5
7
  return {
@@ -54,9 +56,17 @@ async function tasks(args) {
54
56
  if (flowAction === 'cancel') return flowCancelHandler(flowParams[0]);
55
57
  }
56
58
  if (action === 'summary' || action === 'status') return summaryHandler(opts);
59
+ if (action === 'notify') {
60
+ const taskId = params[0];
61
+ const notifyMsg = params.slice(1).join(' ');
62
+ return notifyTaskHandler(taskId, notifyMsg);
63
+ }
64
+ if (action === 'delegate') return delegateHandler(params[0], params.slice(1).join(' '));
65
+ if (action === 'delegate-parallel') return delegateParallelHandler(params.join(' '));
66
+ if (action === 'sub-status') return subStatusHandler();
57
67
 
58
68
  console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
59
- console.log(chalk.gray(' Kullanım: natureco tasks [list|show|cancel|audit|maintenance|flow|summary]\n'));
69
+ console.log(chalk.gray(' Kullanım: natureco tasks [list|show|cancel|audit|maintenance|flow|summary|notify|delegate|delegate-parallel|sub-status]\n'));
60
70
  process.exit(1);
61
71
  }
62
72
 
@@ -68,49 +78,40 @@ function listTasksHandler(opts) {
68
78
  return;
69
79
  }
70
80
 
71
- console.log('');
72
- console.log(chalk.gray(' ' + '─'.repeat(48)));
73
- console.log(chalk.cyan.bold('\n Background Tasks\n'));
81
+ F.header('Background Tasks');
74
82
 
75
83
  if (tasks.length === 0) {
76
- console.log(chalk.gray(' Hiç task bulunamadı.\n'));
77
- if (opts.runtime) console.log(chalk.gray(` Filtre: runtime=${opts.runtime}`));
78
- if (opts.status) console.log(chalk.gray(` Filtre: status=${opts.status}`));
79
- console.log('');
84
+ F.meta('Hiç task bulunamadı.');
85
+ if (opts.runtime) F.meta('Filtre: runtime=' + opts.runtime);
86
+ if (opts.status) F.meta('Filtre: status=' + opts.status);
80
87
  return;
81
88
  }
82
89
 
83
- tasks.forEach(t => {
84
- const icon = STATUS_ICONS[t.status] || '❓';
85
- const color = STATUS_COLORS[t.status] || chalk.white;
86
- const runtimeIcon = t.runtime === 'cron' ? '⏰' : t.runtime === 'subagent' ? '🧑‍💻' : t.runtime === 'acp' ? '🔄' : '💻';
87
- const age = getAgeString(t.createdAt);
88
- console.log(` ${icon} ${chalk.white(t.id.slice(0, 12))} ${color(t.status)} ${runtimeIcon}${t.runtime}`);
89
- if (t.message) {
90
- const msg = t.message.length > 50 ? t.message.slice(0, 50) + '...' : t.message;
91
- console.log(chalk.gray(` ${msg}`));
92
- }
93
- console.log(chalk.gray(` ${age} | notify: ${t.notifyPolicy || 'done_only'}`));
94
- console.log('');
95
- });
90
+ const rows = tasks.map(t => [
91
+ t.id.slice(0, 12),
92
+ (t.message || t.runtime || '').slice(0, 40),
93
+ t.status,
94
+ t.runtime || '—',
95
+ getAgeString(t.createdAt)
96
+ ]);
97
+ F.table(['ID', 'Name', 'Status', 'Runtime', 'Time'], rows);
96
98
 
97
99
  const summary = getTaskSummary();
98
- console.log(chalk.gray(' ' + ''.repeat(48)));
99
- console.log(chalk.gray(` Toplam: ${tasks.length} (gösterilen) | Aktif: ${summary.active} | Hata: ${summary.failures}`));
100
- console.log(chalk.gray(' Filtre: ') + chalk.cyan('--runtime <type> --status <status>'));
101
- console.log(chalk.gray(" JSON: ") + chalk.cyan('natureco tasks list --json\n'));
100
+ F.meta('Toplam: ' + tasks.length + ' (gösterilen) | Aktif: ' + summary.active + ' | Hata: ' + summary.failures);
101
+ F.meta('Filtre: --runtime <type> --status <status>');
102
+ F.meta('JSON: natureco tasks list --json');
102
103
  }
103
104
 
104
105
  function showTaskHandler(id, opts) {
105
106
  if (!id) {
106
- console.log(chalk.red('\n ❌ Task ID gerekli\n'));
107
- console.log(chalk.gray(' Kullanım: natureco tasks show <id>\n'));
107
+ F.error('Task ID gerekli');
108
+ F.meta('Kullanım: natureco tasks show <id>');
108
109
  process.exit(1);
109
110
  }
110
111
 
111
112
  const task = getTask(id);
112
113
  if (!task) {
113
- console.log(chalk.red(`\n ❌ Task bulunamadı: ${id}\n`));
114
+ F.error('Task bulunamadı: ' + id);
114
115
  process.exit(1);
115
116
  }
116
117
 
@@ -119,58 +120,53 @@ function showTaskHandler(id, opts) {
119
120
  return;
120
121
  }
121
122
 
122
- const color = STATUS_COLORS[task.status] || chalk.white;
123
- const icon = STATUS_ICONS[task.status] || '❓';
124
-
125
- console.log('');
126
- console.log(chalk.gray(' ' + '─'.repeat(48)));
127
- console.log(`\n ${icon} ${chalk.white('Task:')} ${chalk.cyan(task.id)}`);
128
- console.log(` ${chalk.gray('Durum :')} ${color(task.status)}`);
129
- console.log(` ${chalk.gray('Runtime :')} ${chalk.white(task.runtime)}`);
130
- console.log(` ${chalk.gray('Bot :')} ${chalk.white(task.botName)}`);
131
- if (task.message) console.log(` ${chalk.gray('Mesaj :')} ${chalk.white(task.message)}`);
132
- console.log(` ${chalk.gray('Oluşturma:')} ${chalk.white(formatTime(task.createdAt))}`);
133
- if (task.startedAt) console.log(` ${chalk.gray('Başlangıç:')} ${chalk.white(formatTime(task.startedAt))}`);
134
- if (task.endedAt) console.log(` ${chalk.gray('Bitiş :')} ${chalk.white(formatTime(task.endedAt))}`);
135
- if (task.notifyPolicy) console.log(` ${chalk.gray('Bildirim :')} ${chalk.white(task.notifyPolicy)}`);
136
- if (task.childSessionKey) console.log(` ${chalk.gray('Çocuk :')} ${chalk.gray(task.childSessionKey)}`);
137
- if (task.runId) console.log(` ${chalk.gray('Run ID :')} ${chalk.gray(task.runId)}`);
123
+ F.header('Task: ' + task.id);
124
+ F.kv('Durum', task.status);
125
+ F.kv('Runtime', task.runtime);
126
+ F.kv('Bot', task.botName);
127
+ if (task.message) F.kv('Mesaj', task.message);
128
+ F.kv('Oluşturma', formatTime(task.createdAt));
129
+ if (task.startedAt) F.kv('Başlangıç', formatTime(task.startedAt));
130
+ if (task.endedAt) F.kv('Bitiş', formatTime(task.endedAt));
131
+ if (task.notifyPolicy) F.kv('Bildirim', task.notifyPolicy);
132
+ if (task.childSessionKey) F.kv('Çocuk', task.childSessionKey);
133
+ if (task.runId) F.kv('Run ID', task.runId);
138
134
 
139
135
  if (task.result) {
140
- console.log(`\n ${chalk.cyan('Sonuç:')}`);
141
- console.log(` ${chalk.white(task.result)}`);
136
+ console.log('');
137
+ F.kv('Sonuç', task.result);
142
138
  }
143
139
  if (task.error) {
144
- console.log(`\n ${chalk.red('Hata:')}`);
145
- console.log(` ${chalk.white(task.error)}`);
140
+ console.log('');
141
+ F.kv('Hata', task.error);
146
142
  }
147
143
  if (task.cleanupAfter) {
148
- console.log(`\n ${chalk.gray(`Temizlik: ${formatTime(task.cleanupAfter)}`)}`);
144
+ F.meta('Temizlik: ' + formatTime(task.cleanupAfter));
149
145
  }
150
146
  if (task.metadata && Object.keys(task.metadata).length > 0) {
151
- console.log(`\n ${chalk.gray('Metadata:')}`);
152
- Object.entries(task.metadata).forEach(([k, v]) => console.log(` ${k}: ${v}`));
147
+ console.log('');
148
+ F.meta('Metadata:');
149
+ Object.entries(task.metadata).forEach(([k, v]) => F.meta(k + ': ' + v));
153
150
  }
154
- console.log('');
155
151
  }
156
152
 
157
153
  function cancelTaskHandler(id) {
158
154
  if (!id) {
159
- console.log(chalk.red('\n ❌ Task ID gerekli\n'));
160
- console.log(chalk.gray(' Kullanım: natureco tasks cancel <id>\n'));
155
+ F.error('Task ID gerekli');
156
+ F.meta('Kullanım: natureco tasks cancel <id>');
161
157
  process.exit(1);
162
158
  }
163
159
 
164
160
  const result = cancelTask(id);
165
161
  if (!result) {
166
- console.log(chalk.red(`\n ❌ Task bulunamadı: ${id}\n`));
162
+ F.error('Task bulunamadı: ' + id);
167
163
  process.exit(1);
168
164
  }
169
165
 
170
166
  if (result.status === 'cancelled') {
171
- console.log(chalk.green(`\n ✓ Task iptal edildi: ${id}\n`));
167
+ F.success('Task iptal edildi: ' + id);
172
168
  } else {
173
- console.log(chalk.yellow(`\n ⚠ Task zaten terminal durumda: ${result.status}\n`));
169
+ F.warning('Task zaten terminal durumda: ' + result.status);
174
170
  }
175
171
  }
176
172
 
@@ -182,12 +178,10 @@ function auditHandler(opts) {
182
178
  return;
183
179
  }
184
180
 
185
- console.log('');
186
- console.log(chalk.gray(' ' + '─'.repeat(48)));
187
- console.log(chalk.cyan.bold('\n Task Denetimi\n'));
181
+ F.header('Task Denetimi');
188
182
 
189
183
  if (findings.length === 0) {
190
- console.log(chalk.green('Sorun bulunamadı.\n'));
184
+ F.success('Sorun bulunamadı.');
191
185
  return;
192
186
  }
193
187
 
@@ -196,54 +190,47 @@ function auditHandler(opts) {
196
190
  filtered = findings.filter(f => f.severity === opts.severity);
197
191
  }
198
192
 
199
- const errors = filtered.filter(f => f.severity === 'error');
200
- const warnings = filtered.filter(f => f.severity === 'warn');
201
-
202
- if (errors.length > 0) {
203
- console.log(chalk.red(`\n ${errors.length} HATA\n`));
204
- errors.forEach(f => {
205
- console.log(` ${chalk.red('✗')} ${chalk.white(f.id.slice(0, 12))} ${chalk.red(f.code)}`);
206
- console.log(chalk.gray(` ${f.message}`));
207
- });
193
+ if (filtered.length === 0) {
194
+ F.meta('Filtreye uygun bulgu yok (severity=' + opts.severity + ')');
195
+ return;
208
196
  }
209
197
 
210
- if (warnings.length > 0) {
211
- console.log(chalk.yellow(`\n ${warnings.length} UYARI\n`));
212
- warnings.forEach(f => {
213
- console.log(` ${chalk.yellow('⚠')} ${chalk.white(f.id.slice(0, 12))} ${chalk.yellow(f.code)}`);
214
- console.log(chalk.gray(` ${f.message}`));
215
- });
216
- }
198
+ const rows = filtered.map(f => [
199
+ f.id.slice(0, 12),
200
+ f.code,
201
+ f.severity,
202
+ f.message.slice(0, 60)
203
+ ]);
204
+ F.table(['ID', 'Code', 'Severity', 'Message'], rows);
217
205
 
218
- console.log(chalk.gray(`\n Toplam: ${filtered.length} bulgu`));
219
- console.log(chalk.gray(` Bakım: natureco tasks maintenance --apply\n`));
206
+ F.meta('Toplam: ' + filtered.length + ' bulgu');
207
+ F.meta('Bakım: natureco tasks maintenance --apply');
220
208
  }
221
209
 
222
210
  function maintenanceHandler(opts) {
223
- console.log(chalk.cyan('\n Task Bakımı\n'));
211
+ F.header('Task Bakımı');
224
212
 
225
213
  const dryRun = !opts.apply;
226
214
  const result = maintenanceTasks(dryRun);
227
215
 
228
216
  if (dryRun) {
229
- console.log(chalk.gray(' Kuru çalışma (--apply ile uygula)\n'));
217
+ F.info('Kuru çalışma (--apply ile uygula)');
230
218
  }
231
219
 
232
- console.log(chalk.gray(` Temizlenen : ${result.pruned}`));
233
- console.log(chalk.gray(` Düzeltilen : ${result.reconciled}`));
234
- console.log(chalk.gray(` Etiketlenen : ${result.cleaned}`));
235
- console.log(chalk.gray(` Kalan task : ${result.remaining}`));
220
+ F.kv('Temizlenen', result.pruned);
221
+ F.kv('Düzeltilen', result.reconciled);
222
+ F.kv('Etiketlenen', result.cleaned);
223
+ F.kv('Kalan task', result.remaining);
236
224
 
237
225
  if (result.pruned > 0 || result.reconciled > 0 || result.cleaned > 0) {
238
226
  if (dryRun) {
239
- console.log(chalk.gray(`\n Uygulamak için: natureco tasks maintenance --apply`));
227
+ F.meta('Uygulamak için: natureco tasks maintenance --apply');
240
228
  } else {
241
- console.log(chalk.green(`\n ✓ Bakım uygulandı.\n`));
229
+ F.success('Bakım uygulandı.');
242
230
  }
243
231
  } else {
244
- console.log(chalk.green(`\n ✓ Bakım gerekmiyor.\n`));
232
+ F.success('Bakım gerekmiyor.');
245
233
  }
246
- console.log('');
247
234
  }
248
235
 
249
236
  function flowListHandler(opts) {
@@ -254,22 +241,21 @@ function flowListHandler(opts) {
254
241
  return;
255
242
  }
256
243
 
257
- console.log('');
258
- console.log(chalk.gray(' ' + '─'.repeat(48)));
259
- console.log(chalk.cyan.bold('\n Task Flow\n'));
244
+ F.header('Task Flow');
260
245
 
261
246
  if (tasks.length === 0) {
262
- console.log(chalk.gray(' Task Flow kaydı yok.\n'));
247
+ F.meta('Task Flow kaydı yok.');
263
248
  return;
264
249
  }
265
250
 
266
- tasks.forEach(t => {
267
- const icon = STATUS_ICONS[t.status] || '❓';
268
- const color = STATUS_COLORS[t.status] || chalk.white;
269
- console.log(` ${icon} ${chalk.white(t.id.slice(0, 12))} ${color(t.status)}`);
270
- if (t.message) console.log(chalk.gray(` ${t.message.slice(0, 60)}`));
271
- });
272
- console.log(chalk.gray(`\n Toplam: ${tasks.length} flow\n`));
251
+ const rows = tasks.map(t => [
252
+ t.id.slice(0, 12),
253
+ t.status,
254
+ t.message ? t.message.slice(0, 60) : '—'
255
+ ]);
256
+ F.table(['ID', 'Status', 'Message'], rows);
257
+
258
+ F.meta('Toplam: ' + tasks.length + ' flow');
273
259
  }
274
260
 
275
261
  function flowShowHandler(id, opts) {
@@ -325,4 +311,126 @@ function formatTime(dateStr) {
325
311
  return new Date(dateStr).toLocaleString('tr-TR');
326
312
  }
327
313
 
314
+ function notifyTaskHandler(id, message) {
315
+ if (!id) {
316
+ F.error('Task ID gerekli');
317
+ F.meta('Kullanım: natureco tasks notify <id> [message]');
318
+ process.exit(1);
319
+ }
320
+ const task = getTask(id);
321
+ if (!task) {
322
+ F.error('Task bulunamadı: ' + id);
323
+ process.exit(1);
324
+ }
325
+ F.header('Task Notification');
326
+ F.kv('Task', id);
327
+ F.kv('Message', message || '(default notification)');
328
+ F.kv('Channel', task.notifyPolicy || 'done_only');
329
+ F.success('Notification will be sent when task completes');
330
+ }
331
+
332
+ async function delegateHandler(type, task) {
333
+ if (!type || !task) {
334
+ F.error('Kullanım: natureco tasks delegate <type> <task>');
335
+ F.meta('Tipler: explore, general, review');
336
+ process.exit(1);
337
+ }
338
+
339
+ F.header('Sub-agent Delegate');
340
+ F.kv('Type', type);
341
+ F.kv('Task', task.slice(0, 80));
342
+
343
+ try {
344
+ const result = await spawnSubAgent(type, task);
345
+ F.success('Sub-agent tamamlandı');
346
+ F.divider();
347
+ console.log(chalk.white(result.result));
348
+ if (result.duration) {
349
+ F.meta(`Süre: ${(result.duration / 1000).toFixed(1)}s`);
350
+ }
351
+ if (result.usage) {
352
+ F.meta(`Token: ${result.usage.prompt_tokens || result.usage.input_tokens || '?'} → ${result.usage.completion_tokens || result.usage.output_tokens || '?'}`);
353
+ }
354
+ } catch (err) {
355
+ F.error('Sub-agent hatası: ' + err.message);
356
+ process.exit(1);
357
+ }
358
+ }
359
+
360
+ async function delegateParallelHandler(input) {
361
+ if (!input) {
362
+ F.error('Kullanım: natureco tasks delegate-parallel <type1> <task1> | <type2> <task2>');
363
+ F.meta('Birden çok agent\'ı " | " (pipe) ile ayırın');
364
+ process.exit(1);
365
+ }
366
+
367
+ const parts = input.split(/\s+\|\s+/);
368
+ if (parts.length < 2) {
369
+ F.error('En az 2 agent belirtin, " | " ile ayırın');
370
+ process.exit(1);
371
+ }
372
+
373
+ const agents = parts.map(p => {
374
+ const trimmed = p.trim();
375
+ const spaceIdx = trimmed.indexOf(' ');
376
+ if (spaceIdx === -1) throw new Error(`Geçersiz agent: "${trimmed}" (type + task gerekli)`);
377
+ return {
378
+ type: trimmed.slice(0, spaceIdx),
379
+ task: trimmed.slice(spaceIdx + 1).trim(),
380
+ };
381
+ });
382
+
383
+ F.header('Parallel Sub-agents (' + agents.length + ')');
384
+ agents.forEach(a => F.kv(a.type, a.task.slice(0, 60)));
385
+
386
+ F.info('Çalıştırılıyor...');
387
+
388
+ const { results, failed } = await spawnParallel(agents);
389
+
390
+ F.divider();
391
+
392
+ results.forEach((r, i) => {
393
+ const agent = agents[i];
394
+ if (r.status === 'fulfilled') {
395
+ F.success(`${agent.type} — tamamlandı (${(r.value.duration / 1000).toFixed(1)}s)`);
396
+ } else {
397
+ F.error(`${agent.type} — hata: ${r.reason}`);
398
+ }
399
+ });
400
+
401
+ if (failed.length > 0) {
402
+ F.warning(`${failed.length}/${agents.length} agent başarısız`);
403
+ } else {
404
+ F.success('Tüm agent' + (agents.length > 1 ? 'lar' : '') + ' tamamlandı');
405
+ }
406
+ }
407
+
408
+ function subStatusHandler() {
409
+ const status = getStatus();
410
+
411
+ if (status.total === 0) {
412
+ F.header('Sub-agent Status');
413
+ F.meta('Henüz sub-agent kaydı yok.');
414
+ return;
415
+ }
416
+
417
+ F.header('Sub-agent Status');
418
+ F.kv('Toplam', status.total);
419
+ F.kv('Çalışan', String(status.running));
420
+ F.kv('Tamamlanan', String(status.completed));
421
+ F.kv('Hatalı', String(status.failed));
422
+
423
+ if (status.agents.length > 0) {
424
+ console.log('');
425
+ const rows = status.agents.map(a => [
426
+ a.id.slice(0, 10),
427
+ a.type,
428
+ a.status === 'completed' ? chalk.green('✓') : a.status === 'failed' ? chalk.red('✗') : chalk.cyan('⟳'),
429
+ a.task.slice(0, 40),
430
+ a.completedAt ? new Date(a.completedAt).toLocaleString('tr-TR') : '—',
431
+ ]);
432
+ F.table(['ID', 'Type', '', 'Task', 'Completed'], rows);
433
+ }
434
+ }
435
+
328
436
  module.exports = tasks;
@@ -1,21 +1,139 @@
1
1
  const chalk = require('chalk');
2
- const { execSync } = require('child_process');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+ const { execSync, spawn } = require('child_process');
6
+
7
+ const SESSIONS_FILE = path.join(os.homedir(), '.natureco', 'terminal-sessions.json');
8
+
9
+ function loadSessions() {
10
+ if (!fs.existsSync(SESSIONS_FILE)) return [];
11
+ try { return JSON.parse(fs.readFileSync(SESSIONS_FILE, 'utf-8')); }
12
+ catch { return []; }
13
+ }
14
+
15
+ function saveSessions(sessions) {
16
+ const dir = path.dirname(SESSIONS_FILE);
17
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
18
+ fs.writeFileSync(SESSIONS_FILE, JSON.stringify(sessions, null, 2), 'utf-8');
19
+ }
20
+
21
+ function genId() { return Date.now().toString(36) + Math.random().toString(36).slice(2, 6); }
3
22
 
4
23
  function terminal(args) {
5
- console.log(chalk.cyan('\n 🖥️ Terminal UI\n'));
6
- console.log(chalk.gray(' ' + '─'.repeat(48)));
7
- console.log(chalk.gray(' Open a terminal UI connected to the Gateway.\n'));
8
- console.log(chalk.gray(' Starting chat interface...\n'));
24
+ const [action, ...params] = args || [];
25
+
26
+ if (!action || action === 'help') return showHelp();
27
+ if (action === 'exec') return execCmd(params.join(' '));
28
+ if (action === 'connect') return connectSession(params[0], params.slice(1).join(' '));
29
+ if (action === 'disconnect') return disconnectSession(params[0]);
30
+ if (action === 'list') return listSessions();
9
31
 
32
+ console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
33
+ console.log(chalk.gray(' Kullanım: natureco terminal [exec|connect|disconnect|list]\n'));
34
+ process.exit(1);
35
+ }
36
+
37
+ function execCmd(cmd) {
38
+ if (!cmd) {
39
+ console.log(chalk.red('\n ❌ Komut gerekli\n'));
40
+ console.log(chalk.gray(' Örnek: natureco terminal exec "ls -la"\n'));
41
+ process.exit(1);
42
+ }
43
+ console.log(chalk.cyan(`\n 🖥️ $ ${cmd}\n`));
44
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
10
45
  try {
11
- execSync('node "' + __dirname + '\\chat.js"', {
12
- stdio: 'inherit',
13
- cwd: require('path').join(__dirname, '..', '..'),
14
- timeout: 5000
15
- });
16
- } catch {
17
- console.log(chalk.cyan(' Use:') + chalk.white(' natureco chat\n'));
46
+ const output = execSync(cmd, { encoding: 'utf8', timeout: 30000, maxBuffer: 1024 * 1024 });
47
+ if (output) console.log(output);
48
+ console.log(chalk.green(`\n ✅ Komut başarıyla tamamlandı (${output.length} bytes)\n`));
49
+ } catch (err) {
50
+ if (err.stdout) console.log(err.stdout.toString());
51
+ if (err.stderr) console.log(chalk.red(err.stderr.toString()));
52
+ console.log(chalk.red(`\n ❌ Hata: ${err.message}\n`));
18
53
  }
19
54
  }
20
55
 
56
+ function connectSession(target, cmd) {
57
+ if (!target) {
58
+ console.log(chalk.red('\n ❌ Hedef gerekli (örn: local, ssh://user@host)\n'));
59
+ process.exit(1);
60
+ }
61
+
62
+ const sessions = loadSessions();
63
+ const existing = sessions.find(s => s.target === target && s.status === 'active');
64
+ if (existing) {
65
+ console.log(chalk.yellow(`\n ⚠️ ${target} üzerinde zaten aktif oturum var: ${existing.id}\n`));
66
+ return;
67
+ }
68
+
69
+ const session = { id: genId(), target, status: 'active', cmd: cmd || 'powershell', createdAt: new Date().toISOString() };
70
+ sessions.push(session);
71
+ saveSessions(sessions);
72
+
73
+ console.log(chalk.green(`\n ✅ Oturum başlatıldı: ${session.id}\n`));
74
+ console.log(` ${chalk.white('Target:')} ${target}`);
75
+ console.log(` ${chalk.white('Shell:')} ${session.cmd}`);
76
+ console.log();
77
+
78
+ if (target === 'local' || target.startsWith('local')) {
79
+ const shell = session.cmd;
80
+ console.log(chalk.gray(` ${shell} başlatılıyor... (Ctrl+D çıkış)\n`));
81
+ try {
82
+ const child = spawn(shell, [], { stdio: 'inherit', shell: true });
83
+ child.on('exit', () => {
84
+ session.status = 'closed';
85
+ session.endedAt = new Date().toISOString();
86
+ saveSessions(sessions);
87
+ console.log(chalk.gray(`\n Oturum sonlandı: ${session.id}\n`));
88
+ });
89
+ } catch (err) {
90
+ console.log(chalk.red(`\n ❌ ${err.message}\n`));
91
+ }
92
+ return;
93
+ }
94
+
95
+ console.log(chalk.gray(` Uzak oturum: ssh veya winrm ile ${target} bağlanın\n`));
96
+ }
97
+
98
+ function disconnectSession(id) {
99
+ const sessions = loadSessions();
100
+ const idx = sessions.findIndex(s => s.id === id);
101
+ if (idx === -1) { console.log(chalk.red(`\n ❌ Oturum bulunamadı: ${id}\n`)); process.exit(1); }
102
+ sessions[idx].status = 'closed';
103
+ sessions[idx].endedAt = new Date().toISOString();
104
+ saveSessions(sessions);
105
+ console.log(chalk.gray(`\n 🛑 Oturum sonlandı: ${id} — ${sessions[idx].target}\n`));
106
+ }
107
+
108
+ function listSessions() {
109
+ const sessions = loadSessions();
110
+ console.log(chalk.cyan('\n 📋 Terminal Sessions\n'));
111
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
112
+ if (sessions.length === 0) {
113
+ console.log(chalk.gray(' Oturum bulunamadı.\n'));
114
+ return;
115
+ }
116
+ for (const s of sessions.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))) {
117
+ const icon = s.status === 'active' ? chalk.green('●') : chalk.gray('○');
118
+ console.log(` ${icon} ${chalk.white(s.target)} — ${s.cmd}`);
119
+ console.log(chalk.gray(` [${s.id}] ${s.createdAt.slice(0, 16)}`));
120
+ }
121
+ console.log();
122
+ }
123
+
124
+ function showHelp() {
125
+ console.log(chalk.cyan('\n 🖥️ Terminal\n'));
126
+ console.log(chalk.gray(' Execute commands and manage terminal sessions.\n'));
127
+ console.log(chalk.gray(' Usage: natureco terminal <action> [params]'));
128
+ console.log(chalk.gray('\n Actions:'));
129
+ console.log(chalk.cyan(' exec <cmd>') + chalk.gray(' Run a shell command'));
130
+ console.log(chalk.cyan(' connect <target> [shell]') + chalk.gray(' Start a session'));
131
+ console.log(chalk.cyan(' disconnect <id>') + chalk.gray(' Close a session'));
132
+ console.log(chalk.cyan(' list') + chalk.gray(' List sessions'));
133
+ console.log(chalk.gray('\n Examples:'));
134
+ console.log(chalk.gray(' natureco terminal exec "dir"'));
135
+ console.log(chalk.gray(' natureco terminal connect local'));
136
+ console.log(chalk.gray(' natureco terminal list\n'));
137
+ }
138
+
21
139
  module.exports = terminal;
@@ -8,9 +8,10 @@ function transcripts(args) {
8
8
 
9
9
  if (!action || action === 'list') return listTranscripts();
10
10
  if (action === 'show') return showTranscript(params[0]);
11
+ if (action === 'delete') return deleteTranscript(params[0]);
11
12
 
12
13
  console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
13
- console.log(chalk.gray(' Kullanım: natureco transcripts [list|show]\n'));
14
+ console.log(chalk.gray(' Kullanım: natureco transcripts [list|show|delete]\n'));
14
15
  process.exit(1);
15
16
  }
16
17
 
@@ -69,4 +70,26 @@ function showTranscript(id) {
69
70
  console.log();
70
71
  }
71
72
 
73
+ function deleteTranscript(id) {
74
+ if (!id) {
75
+ console.log(chalk.red('\n ❌ Transcript ID gerekli\n'));
76
+ process.exit(1);
77
+ }
78
+
79
+ const sessionsDir = path.join(os.homedir(), '.natureco', 'sessions');
80
+ const file = path.join(sessionsDir, `${id}.json`);
81
+
82
+ let target = file;
83
+ if (!fs.existsSync(target)) {
84
+ target = path.join(sessionsDir, id);
85
+ if (!fs.existsSync(target)) {
86
+ console.log(chalk.red(`\n ❌ Transcript bulunamadı: ${id}\n`));
87
+ process.exit(1);
88
+ }
89
+ }
90
+
91
+ fs.unlinkSync(target);
92
+ console.log(chalk.green(`\n 🗑️ Transcript silindi: ${id}\n`));
93
+ }
94
+
72
95
  module.exports = transcripts;
@@ -0,0 +1,41 @@
1
+ const chalk = require('chalk');
2
+
3
+ function tui(args) {
4
+ const [action, ...params] = args || [];
5
+
6
+ if (!action || action === 'start') return cmdStart();
7
+ if (action === 'local') return cmdLocal();
8
+ if (action === 'status') return cmdStatus();
9
+
10
+ console.log(chalk.red(`\n Unknown tui action: ${action}\n`));
11
+ console.log(chalk.gray(' Usage: natureco tui <action>'));
12
+ console.log(chalk.gray(' Actions: start, local, status\n'));
13
+ process.exit(1);
14
+ }
15
+
16
+ function cmdStart() {
17
+ console.log(chalk.cyan('\n TUI Launcher\n'));
18
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
19
+ console.log(chalk.gray(' TUI would launch here.'));
20
+ console.log(chalk.gray(' This is a stub — no real TUI implementation.\n'));
21
+ }
22
+
23
+ function cmdLocal() {
24
+ console.log(chalk.cyan('\n Local TUI\n'));
25
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
26
+ console.log(chalk.gray(' Local TUI would launch here.'));
27
+ console.log(chalk.gray(' This is a stub — no real TUI implementation.\n'));
28
+ }
29
+
30
+ function cmdStatus() {
31
+ console.log(chalk.cyan('\n TUI Status\n'));
32
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
33
+ console.log(` ${chalk.white('Status:')} ${chalk.gray('Not running')}`);
34
+ console.log(` ${chalk.white('Type:')} ${chalk.gray('Terminal UI')}`);
35
+ console.log('');
36
+ console.log(chalk.gray(' Start with: ') + chalk.cyan('natureco tui start'));
37
+ console.log(chalk.gray(' Local: ') + chalk.cyan('natureco tui local'));
38
+ console.log('');
39
+ }
40
+
41
+ module.exports = tui;