natureco-cli 2.23.30 → 2.23.32

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 (69) hide show
  1. package/bin/natureco.js +178 -167
  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/ask.js +1 -1
  9. package/src/commands/browser.js +815 -0
  10. package/src/commands/capability.js +195 -22
  11. package/src/commands/channels.js +422 -267
  12. package/src/commands/chat.js +5 -8
  13. package/src/commands/clawbot.js +19 -0
  14. package/src/commands/code.js +3 -2
  15. package/src/commands/commitments.js +125 -9
  16. package/src/commands/completion.js +40 -32
  17. package/src/commands/config.js +228 -30
  18. package/src/commands/configure.js +84 -67
  19. package/src/commands/cron.js +239 -19
  20. package/src/commands/daemon.js +34 -4
  21. package/src/commands/dashboard.js +47 -374
  22. package/src/commands/devices.js +53 -26
  23. package/src/commands/directory.js +146 -14
  24. package/src/commands/dns.js +148 -10
  25. package/src/commands/docs.js +119 -26
  26. package/src/commands/doctor.js +143 -492
  27. package/src/commands/exec-policy.js +57 -48
  28. package/src/commands/gateway.js +492 -249
  29. package/src/commands/health.js +141 -11
  30. package/src/commands/help.js +24 -25
  31. package/src/commands/hooks.js +141 -87
  32. package/src/commands/infer.js +1442 -41
  33. package/src/commands/logs.js +122 -99
  34. package/src/commands/mcp.js +121 -309
  35. package/src/commands/memory.js +128 -0
  36. package/src/commands/message.js +720 -140
  37. package/src/commands/models.js +39 -1
  38. package/src/commands/node.js +77 -77
  39. package/src/commands/nodes.js +278 -22
  40. package/src/commands/onboard.js +115 -56
  41. package/src/commands/pairing.js +108 -107
  42. package/src/commands/path.js +206 -0
  43. package/src/commands/plugins.js +35 -1
  44. package/src/commands/proxy.js +159 -8
  45. package/src/commands/qr.js +55 -13
  46. package/src/commands/reset.js +101 -94
  47. package/src/commands/secrets.js +104 -21
  48. package/src/commands/sessions.js +110 -51
  49. package/src/commands/setup.js +229 -649
  50. package/src/commands/skills.js +67 -1
  51. package/src/commands/status.js +101 -127
  52. package/src/commands/tasks.js +208 -100
  53. package/src/commands/terminal.js +130 -12
  54. package/src/commands/transcripts.js +24 -1
  55. package/src/commands/tui.js +41 -0
  56. package/src/commands/uninstall.js +73 -92
  57. package/src/commands/update.js +146 -91
  58. package/src/commands/web-fetch.js +34 -0
  59. package/src/commands/webhooks.js +58 -66
  60. package/src/commands/wiki.js +783 -0
  61. package/src/utils/agents-md.js +85 -0
  62. package/src/utils/api.js +40 -41
  63. package/src/utils/format.js +144 -0
  64. package/src/utils/headless.js +2 -1
  65. package/src/utils/parallel-tools.js +106 -0
  66. package/src/utils/sub-agent.js +148 -0
  67. package/src/utils/token-budget.js +304 -0
  68. package/src/utils/tool-runner.js +7 -5
  69. package/src/utils/web-fetch.js +107 -0
@@ -0,0 +1,39 @@
1
+ const chalk = require('chalk');
2
+
3
+ function acp(args) {
4
+ const [action, ...params] = args || [];
5
+
6
+ if (!action || action === 'status') return cmdStatus();
7
+ if (action === 'info') return cmdInfo();
8
+
9
+ console.log(chalk.red(`\n Unknown acp action: ${action}\n`));
10
+ console.log(chalk.gray(' Usage: natureco acp <action>'));
11
+ console.log(chalk.gray(' Actions: status, info\n'));
12
+ process.exit(1);
13
+ }
14
+
15
+ function cmdStatus() {
16
+ console.log(chalk.cyan('\n ACP (Agent Communication Protocol) Status\n'));
17
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
18
+ console.log(` ${chalk.white('Endpoint:')} ${chalk.green('http://127.0.0.1:3847/acp')}`);
19
+ console.log(` ${chalk.white('Status:')} ${chalk.gray('Stub — no real implementation')}`);
20
+ console.log('');
21
+ console.log(chalk.gray(' Available endpoints:'));
22
+ console.log(chalk.gray(' GET /acp — Protocol root'));
23
+ console.log(chalk.gray(' GET /acp/health — Health check'));
24
+ console.log(chalk.gray(' POST /acp/message — Send agent message'));
25
+ console.log(chalk.gray(' GET /acp/agents — List agents'));
26
+ console.log('');
27
+ }
28
+
29
+ function cmdInfo() {
30
+ console.log(chalk.cyan('\n ACP Protocol Info\n'));
31
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
32
+ console.log(` ${chalk.white('Protocol:')} ${chalk.cyan('Agent Communication Protocol')}`);
33
+ console.log(` ${chalk.white('Version:')} ${chalk.cyan('1.0.0')}`);
34
+ console.log(` ${chalk.white('Port:')} ${chalk.cyan('3847')}`);
35
+ console.log(` ${chalk.white('Transport:')} ${chalk.cyan('HTTP/JSON')}`);
36
+ console.log('');
37
+ }
38
+
39
+ module.exports = acp;
@@ -126,6 +126,75 @@ async function callMethod(method, jsonParams) {
126
126
  return;
127
127
  }
128
128
 
129
+ if (method === 'config.set') {
130
+ const { setConfigValue } = require('../utils/config');
131
+ if (!params.key) { console.log(chalk.red('\n ❌ params.key gerekli\n')); process.exit(1); }
132
+ setConfigValue(params.key, params.value);
133
+ console.log(chalk.green(`\n ✅ config.${params.key} = ${JSON.stringify(params.value)}\n`));
134
+ return;
135
+ }
136
+
137
+ if (method === 'channels.status' || method === 'channels.start' || method === 'channels.stop') {
138
+ const { getAllConfig } = require('../utils/config');
139
+ const cfg = getAllConfig();
140
+ const channels = ['telegram', 'discord', 'slack', 'whatsapp'];
141
+ console.log(chalk.cyan(`\n 📡 Channel: ${method}\n`));
142
+ if (method === 'channels.status') {
143
+ for (const ch of channels) {
144
+ const token = cfg[`${ch}Token`];
145
+ console.log(` ${token ? chalk.green('●') : chalk.gray('○')} ${ch} ${token ? chalk.gray('(configured)') : chalk.gray('(not set)')}`);
146
+ }
147
+ } else {
148
+ const ch = params.name || 'all';
149
+ console.log(chalk.gray(` ${method.split('.')[1]} ${ch} (simulated)\n`));
150
+ }
151
+ console.log();
152
+ return;
153
+ }
154
+
155
+ if (method === 'agents.list') {
156
+ const { listTasks, getTaskSummary } = require('../utils/background');
157
+ const tasks = listTasks({ limit: 20 });
158
+ const summary = getTaskSummary();
159
+ console.log(chalk.cyan(`\n 👤 Agents (${summary.active} active, ${summary.total} total)\n`));
160
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
161
+ for (const t of tasks.slice(0, 10)) {
162
+ const icon = t.status === 'succeeded' ? chalk.green('✓') : t.status === 'running' ? chalk.yellow('●') : chalk.gray('○');
163
+ console.log(` ${icon} ${chalk.white(t.message || '(no message)')}`);
164
+ console.log(chalk.gray(` [${t.id}] ${t.runtime} — ${t.status}`));
165
+ }
166
+ console.log();
167
+ return;
168
+ }
169
+
170
+ if (method === 'cron.list' || method === 'cron.status') {
171
+ const { getConfig } = require('../utils/config');
172
+ const config = getConfig();
173
+ const jobs = config.cronJobs || [];
174
+ console.log(chalk.cyan(`\n ⏰ ${method} (${jobs.length} jobs)\n`));
175
+ if (jobs.length === 0) {
176
+ console.log(chalk.gray(' Cron job yapılandırılmamış.\n'));
177
+ return;
178
+ }
179
+ for (const j of jobs) {
180
+ console.log(` ${chalk.white(j.name || '(unnamed)')} — ${chalk.gray(j.schedule || j.interval)}`);
181
+ }
182
+ console.log();
183
+ return;
184
+ }
185
+
186
+ if (method === 'tasks.list') {
187
+ const { listTasks, getTaskSummary } = require('../utils/background');
188
+ const tasks = listTasks({ limit: 20 });
189
+ const summary = getTaskSummary();
190
+ console.log(chalk.cyan(`\n 📋 Tasks (${summary.active} active, ${summary.total} total)\n`));
191
+ for (const t of tasks.slice(0, 15)) {
192
+ console.log(` ${chalk.white(t.id)} — ${chalk.cyan(t.status)} — ${chalk.gray(t.message?.substring(0, 50) || '')}`);
193
+ }
194
+ console.log();
195
+ return;
196
+ }
197
+
129
198
  console.log(chalk.yellow(` ⚠️ Method "${method}" henüz implemente edilmedi\n`));
130
199
  }
131
200
 
@@ -174,6 +243,20 @@ function startAdmin(portStr) {
174
243
  } else if (rpc.method === 'plugins.list') {
175
244
  const { loadTools } = require('../utils/tool-runner');
176
245
  payload = { tools: Object.keys(loadTools()) };
246
+ } else if (rpc.method === 'config.set') {
247
+ const { setConfigValue } = require('../utils/config');
248
+ setConfigValue(rpc.params.key, rpc.params.value);
249
+ payload = { ok: true, key: rpc.params.key, value: rpc.params.value };
250
+ } else if (rpc.method === 'channels.status' || rpc.method === 'channels.start' || rpc.method === 'channels.stop') {
251
+ const channels = ['telegram', 'discord', 'slack', 'whatsapp'];
252
+ const status = {};
253
+ for (const ch of channels) status[ch] = !!config[`${ch}Token`];
254
+ payload = { action: rpc.method, channels: status };
255
+ } else if (rpc.method === 'agents.list' || rpc.method === 'tasks.list') {
256
+ const { listTasks, getTaskSummary } = require('../utils/background');
257
+ payload = { summary: getTaskSummary(), tasks: listTasks({ limit: 20 }) };
258
+ } else if (rpc.method === 'cron.list' || rpc.method === 'cron.status') {
259
+ payload = { jobs: config.cronJobs || [] };
177
260
  } else {
178
261
  payload = { message: `Method "${rpc.method}" called`, params: rpc.params };
179
262
  }
@@ -1,4 +1,10 @@
1
1
  const chalk = require('chalk');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+
6
+ const BINDINGS_FILE = path.join(os.homedir(), '.natureco', 'agent-bindings.json');
7
+ const IDENTITIES_FILE = path.join(os.homedir(), '.natureco', 'agent-identities.json');
2
8
 
3
9
  async function agent(args) {
4
10
  const opts = {};
@@ -10,10 +16,18 @@ async function agent(args) {
10
16
  else if (args[i] === '--model') opts.model = args[++i];
11
17
  else if (args[i] === '--provider') opts.provider = args[++i];
12
18
  else if (!opts.action) opts.action = args[i];
19
+ else (opts._positional = opts._positional || []).push(args[i]);
13
20
  }
14
21
 
15
22
  if (!opts.action || opts.action === 'help') return showHelp();
16
23
  if (opts.action === 'run') return runAgent(opts);
24
+ if (opts.action === 'abort') return abortAgent(opts.message);
25
+ if (opts.action === 'tail') return tailAgent(opts.message);
26
+ if (opts.action === 'logs') return logsAgent(opts.message);
27
+ if (opts.action === 'bindings') return listBindings();
28
+ if (opts.action === 'bind') return bindAgent(opts);
29
+ if (opts.action === 'unbind') return unbindAgent(opts);
30
+ if (opts.action === 'set-identity') return setIdentity(opts);
17
31
 
18
32
  console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${opts.action}\n`));
19
33
  process.exit(1);
@@ -21,13 +35,28 @@ async function agent(args) {
21
35
 
22
36
  async function runAgent(opts) {
23
37
  const { getConfig } = require('../utils/config');
38
+ const { createTask } = require('../utils/background');
39
+ const { getProviderConfig } = require('../utils/api');
24
40
  const config = getConfig();
41
+ const pc = getProviderConfig();
25
42
 
26
- const provider = opts.provider || config.provider || 'openai';
27
- const model = opts.model || config.model || 'gpt-4o';
43
+ const provider = opts.provider || (pc?.url?.includes('groq') ? 'groq' : config.provider || 'openai');
44
+ const model = opts.model || config.providerModel || config.model || 'llama-3.3-70b-versatile';
28
45
  const message = opts.message || 'Hello';
46
+ const apiKey = pc?.apiKey || config[`${provider}ApiKey`] || process.env[`${provider.toUpperCase()}_API_KEY`];
47
+
48
+ if (!apiKey) {
49
+ console.log(chalk.red(`\n ❌ ${provider} API key gerekli\n`));
50
+ process.exit(1);
51
+ }
29
52
 
30
- console.log(chalk.cyan(`\n 🤖 Agent Turn\n`));
53
+ const task = createTask({
54
+ runtime: 'cli',
55
+ message: message.substring(0, 80),
56
+ botName: opts.to || 'default',
57
+ });
58
+
59
+ console.log(chalk.cyan(`\n 🤖 Agent Turn [${task.id}]\n`));
31
60
  console.log(chalk.gray(' ' + '─'.repeat(48)));
32
61
  console.log(` ${chalk.white('Message:')} ${message}`);
33
62
  if (opts.to) console.log(` ${chalk.white('To:')} ${opts.to}`);
@@ -37,24 +66,26 @@ async function runAgent(opts) {
37
66
  console.log(chalk.gray('\n Running...\n'));
38
67
 
39
68
  try {
40
- const apiKey = config[`${provider}ApiKey`] || process.env[`${provider.toUpperCase()}_API_KEY`];
41
- if (!apiKey) {
42
- console.log(chalk.red(` ❌ ${provider} API key gerekli\n`));
43
- process.exit(1);
44
- }
69
+ const { updateTask } = require('../utils/background');
70
+ updateTask(task.id, { status: 'running' });
45
71
 
46
- const baseUrl = provider === 'openai' ? 'https://api.openai.com/v1' : `https://api.${provider}.com/v1`;
47
- const response = await fetch(`${baseUrl}/chat/completions`, {
72
+ const apiUrl = pc?.url || `https://api.${provider}.com/v1`;
73
+ const response = await fetch(`${apiUrl}/chat/completions`, {
48
74
  method: 'POST',
49
75
  headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
50
76
  body: JSON.stringify({ model, messages: [{ role: 'user', content: message }], max_tokens: 2048 })
51
77
  });
52
78
 
53
- if (!response.ok) throw new Error(`API error ${response.status}`);
79
+ if (!response.ok) {
80
+ updateTask(task.id, { status: 'failed', error: `API error ${response.status}` });
81
+ throw new Error(`API error ${response.status}`);
82
+ }
54
83
 
55
84
  const data = await response.json();
56
85
  const reply = data.choices?.[0]?.message?.content || 'No response';
57
86
 
87
+ updateTask(task.id, { status: 'succeeded', result: reply.substring(0, 500) });
88
+
58
89
  console.log(chalk.white(' Response:'));
59
90
  console.log(chalk.gray(` ${reply.substring(0, 500)}`));
60
91
 
@@ -69,21 +100,181 @@ async function runAgent(opts) {
69
100
  }
70
101
  }
71
102
 
103
+ function abortAgent(taskId) {
104
+ const { cancelTask, listTasks } = require('../utils/background');
105
+ if (taskId) {
106
+ const t = cancelTask(taskId);
107
+ if (!t) { console.log(chalk.red(`\n ❌ Task bulunamadı: ${taskId}\n`)); process.exit(1); }
108
+ console.log(chalk.yellow(`\n 🛑 Task iptal edildi: ${taskId}\n`));
109
+ return;
110
+ }
111
+ const running = listTasks({ status: 'running' });
112
+ if (running.length === 0) {
113
+ console.log(chalk.gray('\n Çalışan task yok\n'));
114
+ return;
115
+ }
116
+ for (const t of running) {
117
+ cancelTask(t.id);
118
+ console.log(chalk.yellow(` 🛑 Task iptal edildi: ${t.id} — ${t.message}`));
119
+ }
120
+ console.log();
121
+ }
122
+
123
+ function tailAgent(taskId) {
124
+ const { getTask } = require('../utils/background');
125
+ if (!taskId) {
126
+ console.log(chalk.red('\n ❌ Task ID gerekli. Kullanım: natureco agent tail <id>\n'));
127
+ process.exit(1);
128
+ }
129
+ const task = getTask(taskId);
130
+ if (!task) { console.log(chalk.red(`\n ❌ Task bulunamadı: ${taskId}\n`)); process.exit(1); }
131
+ console.log(chalk.cyan(`\n 📋 Task: ${task.id}\n`));
132
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
133
+ console.log(` ${chalk.white('Message:')} ${task.message}`);
134
+ console.log(` ${chalk.white('Status:')} ${statusColor(task.status)}`);
135
+ if (task.result) console.log(` ${chalk.white('Result:')} ${chalk.gray(task.result.substring(0, 300))}`);
136
+ if (task.error) console.log(` ${chalk.white('Error:')} ${chalk.red(task.error)}`);
137
+ if (task.createdAt) console.log(` ${chalk.white('Created:')} ${chalk.gray(task.createdAt)}`);
138
+ if (task.endedAt) console.log(` ${chalk.white('Ended:')} ${chalk.gray(task.endedAt)}`);
139
+ console.log();
140
+ }
141
+
142
+ function logsAgent(statusFilter) {
143
+ const { listTasks } = require('../utils/background');
144
+ const tasks = listTasks(statusFilter ? { status: statusFilter } : {});
145
+ console.log(chalk.cyan(`\n 📜 Agent Logs${statusFilter ? ` (${statusFilter})` : ''}\n`));
146
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
147
+ if (tasks.length === 0) {
148
+ console.log(chalk.gray(' Task bulunamadı.\n'));
149
+ return;
150
+ }
151
+ for (const t of tasks.slice(0, 20)) {
152
+ console.log(` ${statusColor(t.status)} ${chalk.white(t.message || '(boş)')}`);
153
+ console.log(chalk.gray(` [${t.id}] ${t.createdAt?.slice(0, 16) || ''} — ${t.runtime}`));
154
+ }
155
+ console.log();
156
+ }
157
+
158
+ // ── bindings ──────────────────────────────────────────────────────────
159
+ function listBindings() {
160
+ const bindings = loadBindings();
161
+ const ids = loadIdentities();
162
+ console.log(chalk.cyan('\n Agent Bindings\n'));
163
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
164
+ const entries = Object.entries(bindings);
165
+ if (entries.length === 0) {
166
+ console.log(chalk.gray(' No agents bound to any channels.\n'));
167
+ return;
168
+ }
169
+ for (const [agentId, channels] of entries) {
170
+ const identity = ids[agentId];
171
+ console.log(` ${chalk.white(agentId)}${identity ? chalk.gray(' (' + identity + ')') : ''}`);
172
+ for (const ch of channels) {
173
+ console.log(chalk.gray(' └─ ') + chalk.cyan(ch));
174
+ }
175
+ }
176
+ console.log('');
177
+ }
178
+
179
+ function loadBindings() {
180
+ if (!fs.existsSync(BINDINGS_FILE)) return {};
181
+ try { return JSON.parse(fs.readFileSync(BINDINGS_FILE, 'utf8')); } catch { return {}; }
182
+ }
183
+
184
+ function saveBindings(data) {
185
+ const dir = path.dirname(BINDINGS_FILE);
186
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
187
+ fs.writeFileSync(BINDINGS_FILE, JSON.stringify(data, null, 2), 'utf8');
188
+ }
189
+
190
+ function bindAgent(opts) {
191
+ const pos = opts._positional || [];
192
+ const agentId = pos[0];
193
+ const channel = pos[1] || opts.channel;
194
+ if (!agentId || !channel) {
195
+ console.log(chalk.red('\nUsage: natureco agents bind <agentId> <channel>\n'));
196
+ process.exit(1);
197
+ }
198
+ const bindings = loadBindings();
199
+ if (!bindings[agentId]) bindings[agentId] = [];
200
+ if (!bindings[agentId].includes(channel)) bindings[agentId].push(channel);
201
+ saveBindings(bindings);
202
+ console.log(chalk.green('\nAgent "' + agentId + '" bound to ' + channel + '\n'));
203
+ }
204
+
205
+ function unbindAgent(opts) {
206
+ const pos = opts._positional || [];
207
+ const agentId = pos[0];
208
+ const channel = pos[1] || opts.channel;
209
+ if (!agentId || !channel) {
210
+ console.log(chalk.red('\nUsage: natureco agents unbind <agentId> <channel>\n'));
211
+ process.exit(1);
212
+ }
213
+ const bindings = loadBindings();
214
+ if (bindings[agentId]) {
215
+ bindings[agentId] = bindings[agentId].filter(c => c !== channel);
216
+ if (bindings[agentId].length === 0) delete bindings[agentId];
217
+ }
218
+ saveBindings(bindings);
219
+ console.log(chalk.green('\nAgent "' + agentId + '" unbound from ' + channel + '\n'));
220
+ }
221
+
222
+ // ── identities ────────────────────────────────────────────────────────
223
+ function loadIdentities() {
224
+ if (!fs.existsSync(IDENTITIES_FILE)) return {};
225
+ try { return JSON.parse(fs.readFileSync(IDENTITIES_FILE, 'utf8')); } catch { return {}; }
226
+ }
227
+
228
+ function saveIdentities(data) {
229
+ const dir = path.dirname(IDENTITIES_FILE);
230
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
231
+ fs.writeFileSync(IDENTITIES_FILE, JSON.stringify(data, null, 2), 'utf8');
232
+ }
233
+
234
+ function setIdentity(opts) {
235
+ const pos = opts._positional || [];
236
+ const agentId = pos[0];
237
+ const identity = pos.slice(1).join(' ') || opts.message;
238
+ if (!agentId || !identity) {
239
+ console.log(chalk.red('\nUsage: natureco agents set-identity <agentId> <identity>\n'));
240
+ process.exit(1);
241
+ }
242
+ const ids = loadIdentities();
243
+ ids[agentId] = identity;
244
+ saveIdentities(ids);
245
+ console.log(chalk.green('\nIdentity set for agent "' + agentId + '": ' + identity + '\n'));
246
+ }
247
+
248
+ function statusColor(s) {
249
+ const m = { succeeded: chalk.green('✓'), failed: chalk.red('✗'), running: chalk.yellow('●'), queued: chalk.cyan('○'), cancelled: chalk.gray('−'), timed_out: chalk.red('⚠'), lost: chalk.magenta('?') };
250
+ return m[s] || chalk.gray('○');
251
+ }
252
+
72
253
  function showHelp() {
73
254
  console.log(chalk.cyan('\n 🤖 Agent\n'));
74
- console.log(chalk.gray(' Run one agent turn via the Gateway'));
75
- console.log(chalk.gray('\n Usage: natureco agent [options]'));
76
- console.log(chalk.gray('\n Options:'));
77
- console.log(chalk.cyan(' run') + chalk.gray(' Run an agent turn'));
78
- console.log(chalk.cyan(' --message, -m <text>') + chalk.gray(' Message to send'));
79
- console.log(chalk.cyan(' --to, -t <target>') + chalk.gray(' Target channel/contact'));
80
- console.log(chalk.cyan(' --channel, -c <name>') + chalk.gray(' Channel to use'));
81
- console.log(chalk.cyan(' --deliver') + chalk.gray(' Deliver reply via channel'));
82
- console.log(chalk.cyan(' --model <model>') + chalk.gray(' Model override'));
83
- console.log(chalk.cyan(' --provider <name>') + chalk.gray(' Provider override'));
255
+ console.log(chalk.gray(' Run, manage, and monitor agent tasks.\n'));
256
+ console.log(chalk.gray(' Usage: natureco agent <action> [options]'));
257
+ console.log(chalk.gray('\n Actions:'));
258
+ console.log(chalk.cyan(' run') + chalk.gray(' Run an agent turn'));
259
+ console.log(chalk.cyan(' abort [id]') + chalk.gray(' Cancel a running task'));
260
+ console.log(chalk.cyan(' tail <id>') + chalk.gray(' Show task details'));
261
+ console.log(chalk.cyan(' logs [status]') + chalk.gray(' List recent tasks'));
262
+ console.log(chalk.cyan(' bindings') + chalk.gray(' List agent bindings'));
263
+ console.log(chalk.cyan(' bind <id> <ch>') + chalk.gray(' Bind agent to channel'));
264
+ console.log(chalk.cyan(' unbind <id> <ch>') + chalk.gray(' Unbind agent from channel'));
265
+ console.log(chalk.cyan(' set-identity <id> <persona>') + chalk.gray(' Set agent identity'));
266
+ console.log(chalk.gray('\n Options for run:'));
267
+ console.log(chalk.cyan(' --message, -m <text>') + chalk.gray(' Message to send'));
268
+ console.log(chalk.cyan(' --to, -t <target>') + chalk.gray(' Target channel/contact'));
269
+ console.log(chalk.cyan(' --channel, -c <name>') + chalk.gray(' Channel to use'));
270
+ console.log(chalk.cyan(' --deliver') + chalk.gray(' Deliver reply via channel'));
271
+ console.log(chalk.cyan(' --model <model>') + chalk.gray(' Model override'));
272
+ console.log(chalk.cyan(' --provider <name>') + chalk.gray(' Provider override'));
84
273
  console.log(chalk.gray('\n Examples:'));
85
- console.log(chalk.gray(' natureco agent run --message "Summarize this"'));
86
- console.log(chalk.gray(' natureco agent run --to +1234 --message "Hi" --deliver\n'));
274
+ console.log(chalk.gray(' natureco agent run --message "Merhaba"'));
275
+ console.log(chalk.gray(' natureco agent abort'));
276
+ console.log(chalk.gray(' natureco agent tail <id>'));
277
+ console.log(chalk.gray(' natureco agent logs running\n'));
87
278
  }
88
279
 
89
280
  module.exports = agent;
@@ -1,8 +1,39 @@
1
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');
2
6
  const inquirer = require('../utils/inquirer-wrapper');
3
7
  const { getConfig, saveConfig } = require('../utils/config');
4
8
  const { getBots } = require('../utils/api');
5
9
 
10
+ const BINDINGS_FILE = path.join(os.homedir(), '.natureco', 'agent-bindings.json');
11
+ const IDENTITIES_FILE = path.join(os.homedir(), '.natureco', 'agent-identities.json');
12
+
13
+ function loadBindings() {
14
+ try {
15
+ if (fs.existsSync(BINDINGS_FILE)) return JSON.parse(fs.readFileSync(BINDINGS_FILE, 'utf8'));
16
+ } catch {}
17
+ return {};
18
+ }
19
+
20
+ function saveBindings(data) {
21
+ fs.mkdirSync(path.dirname(BINDINGS_FILE), { recursive: true });
22
+ fs.writeFileSync(BINDINGS_FILE, JSON.stringify(data, null, 2));
23
+ }
24
+
25
+ function loadIdentities() {
26
+ try {
27
+ if (fs.existsSync(IDENTITIES_FILE)) return JSON.parse(fs.readFileSync(IDENTITIES_FILE, 'utf8'));
28
+ } catch {}
29
+ return {};
30
+ }
31
+
32
+ function saveIdentities(data) {
33
+ fs.mkdirSync(path.dirname(IDENTITIES_FILE), { recursive: true });
34
+ fs.writeFileSync(IDENTITIES_FILE, JSON.stringify(data, null, 2));
35
+ }
36
+
6
37
  async function agents(args) {
7
38
  const [action, ...params] = (args || []);
8
39
 
@@ -10,9 +41,13 @@ async function agents(args) {
10
41
  if (action === 'set') return setActiveAgent(params[0]);
11
42
  if (action === 'info') return agentInfo(params[0]);
12
43
  if (action === 'add') return addAgent();
44
+ if (action === 'bindings') return listBindings();
45
+ if (action === 'bind') return bindAgent(params[0], params[1]);
46
+ if (action === 'unbind') return unbindAgent(params[0], params[1]);
47
+ if (action === 'set-identity') return setIdentity(params[0], params.slice(1).join(' '));
13
48
 
14
49
  console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
15
- console.log(chalk.gray(' Kullanım: natureco agents [list|set|info|add]\n'));
50
+ console.log(chalk.gray(' Kullanım: natureco agents [list|set|info|add|bindings|bind|unbind|set-identity]\n'));
16
51
  process.exit(1);
17
52
  }
18
53
 
@@ -20,32 +55,28 @@ async function listAgents() {
20
55
  const config = getConfig();
21
56
  const apiKey = config.providerApiKey || config.apiKey || '';
22
57
 
23
- console.log(chalk.gray('\n Agentlar yükleniyor...\n'));
58
+ F.info('Agentlar yükleniyor...');
24
59
 
25
60
  let botList = { bots: [] };
26
61
  try {
27
62
  botList = await getBots(apiKey);
28
63
  } catch {}
29
64
 
30
- console.log(chalk.gray(' ' + '─'.repeat(48)));
31
- console.log(chalk.cyan.bold('\n Agentlar (Botlar)\n'));
65
+ F.header('Agents');
32
66
 
33
67
  if (!botList.bots?.length) {
34
- console.log(chalk.gray(' Agent bulunamadı.'));
35
- console.log(chalk.gray(' Oluşturmak için: ') + chalk.cyan('developers.natureco.me\n'));
68
+ F.list(['Agent bulunamadı.', 'Oluşturmak için: developers.natureco.me']);
36
69
  return;
37
70
  }
38
71
 
39
- botList.bots.forEach((bot, i) => {
40
- const active = config.botName === bot.name ? chalk.green(' ← aktif') : '';
41
- console.log(chalk.white(` ${i + 1}. ${bot.name}`) + active);
42
- console.log(chalk.gray(` ID : ${bot.id}`));
43
- console.log(chalk.gray(` Provider: ${bot.ai_provider || 'groq'}`));
44
- if (bot.model) console.log(chalk.gray(` Model : ${bot.model}`));
45
- console.log('');
46
- });
72
+ const rows = botList.bots.map(bot => [
73
+ bot.name + (config.botName === bot.name ? ' ← aktif' : ''),
74
+ bot.id,
75
+ bot.ai_provider || 'groq',
76
+ bot.model || ''
77
+ ]);
78
+ F.table(['Name', 'ID', 'Provider', 'Model'], rows);
47
79
 
48
- console.log(chalk.gray(' ' + '─'.repeat(48)));
49
80
  console.log(chalk.gray(' Değiştirmek için: ') + chalk.cyan('natureco agents set <bot-adı>\n'));
50
81
  }
51
82
 
@@ -91,7 +122,7 @@ async function agentInfo(botName) {
91
122
  const name = botName || config.botName;
92
123
 
93
124
  if (!name) {
94
- console.log(chalk.gray('\n Agent adı belirtin: natureco agents info <bot-adı>\n'));
125
+ F.error('Agent adı belirtin: natureco agents info <bot-adı>');
95
126
  return;
96
127
  }
97
128
 
@@ -102,33 +133,27 @@ async function agentInfo(botName) {
102
133
 
103
134
  const bot = botList.bots?.find(b => b.name === name || b.id === name);
104
135
 
105
- console.log('');
106
- console.log(chalk.gray(' ' + '─'.repeat(48)));
107
- console.log(chalk.cyan.bold(`\n Agent: ${name}\n`));
136
+ F.header('Agent: ' + name);
108
137
 
109
138
  if (bot) {
110
- console.log(chalk.gray(' ID : ') + chalk.white(bot.id));
111
- console.log(chalk.gray(' Provider: ') + chalk.white(bot.ai_provider || 'groq'));
112
- if (bot.model) console.log(chalk.gray(' Model : ') + chalk.white(bot.model));
139
+ F.kv('ID', bot.id);
140
+ F.kv('Provider', bot.ai_provider || 'groq');
141
+ if (bot.model) F.kv('Model', bot.model);
113
142
  if (bot.system_prompt) {
114
- console.log(chalk.gray(' Prompt : ') + chalk.white(bot.system_prompt.slice(0, 80) + (bot.system_prompt.length > 80 ? '...' : '')));
143
+ F.kv('Prompt', bot.system_prompt.slice(0, 80) + (bot.system_prompt.length > 80 ? '...' : ''));
115
144
  }
116
145
  } else {
117
- console.log(chalk.gray(' (Detay alınamadı)'));
146
+ F.meta('(Detay alınamadı)');
118
147
  }
119
148
 
120
- // Hafıza bilgisi
121
149
  try {
122
150
  const { loadMemory } = require('../utils/memory');
123
151
  const mem = loadMemory(bot?.id || 'universal-provider');
124
152
  if (mem.name || mem.facts?.length) {
125
- console.log('');
126
- if (mem.name) console.log(chalk.gray(' Kullanıcı: ') + chalk.white(mem.name));
127
- console.log(chalk.gray(' Hafıza : ') + chalk.white(`${(mem.facts || []).length} bilgi`));
153
+ if (mem.name) F.kv('Kullanıcı', mem.name);
154
+ F.kv('Hafıza', (mem.facts || []).length + ' bilgi');
128
155
  }
129
156
  } catch {}
130
-
131
- console.log('');
132
157
  }
133
158
 
134
159
  async function addAgent() {
@@ -138,4 +163,63 @@ async function addAgent() {
138
163
  console.log(chalk.gray(' Oluşturduktan sonra: ') + chalk.cyan('natureco agents list\n'));
139
164
  }
140
165
 
166
+ // ── Bindings ──────────────────────────────────────────────────────────────────
167
+
168
+ function listBindings() {
169
+ const bindings = loadBindings();
170
+ const keys = Object.keys(bindings);
171
+
172
+ F.section('Bindings (' + keys.length + ')');
173
+
174
+ if (keys.length === 0) {
175
+ F.meta('Henüz binding yok.');
176
+ return;
177
+ }
178
+
179
+ const items = [];
180
+ keys.forEach(agentId => {
181
+ bindings[agentId].forEach(ch => items.push(agentId + ' → ' + ch));
182
+ });
183
+ F.list(items);
184
+ }
185
+
186
+ function bindAgent(agentId, channel) {
187
+ if (!agentId || !channel) {
188
+ F.error('Kullanım: natureco agents bind <agentId> <channel>');
189
+ return;
190
+ }
191
+ const bindings = loadBindings();
192
+ if (!bindings[agentId]) bindings[agentId] = [];
193
+ if (!bindings[agentId].includes(channel)) bindings[agentId].push(channel);
194
+ saveBindings(bindings);
195
+ F.success('Agent ' + agentId + ' → ' + channel + ' bağlandı');
196
+ }
197
+
198
+ function unbindAgent(agentId, channel) {
199
+ if (!agentId || !channel) {
200
+ F.error('Kullanım: natureco agents unbind <agentId> <channel>');
201
+ return;
202
+ }
203
+ const bindings = loadBindings();
204
+ if (!bindings[agentId]) {
205
+ F.warning('Agent ' + agentId + ' için binding bulunamadı');
206
+ return;
207
+ }
208
+ bindings[agentId] = bindings[agentId].filter(ch => ch !== channel);
209
+ if (bindings[agentId].length === 0) delete bindings[agentId];
210
+ saveBindings(bindings);
211
+ F.success('Agent ' + agentId + ' → ' + channel + ' bağlantısı kaldırıldı');
212
+ }
213
+
214
+ function setIdentity(agentId, identity) {
215
+ if (!agentId) {
216
+ F.error('Kullanım: natureco agents set-identity <agentId> <identity>');
217
+ return;
218
+ }
219
+ const identities = loadIdentities();
220
+ identities[agentId] = identity || 'default';
221
+ saveIdentities(identities);
222
+ F.success('Agent ' + agentId + ' identity: ' + (identity || 'default'));
223
+ }
224
+
141
225
  module.exports = agents;