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/agents.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
31
|
-
console.log(chalk.cyan.bold('\n Agentlar (Botlar)\n'));
|
|
65
|
+
F.header('Agents');
|
|
32
66
|
|
|
33
67
|
if (!botList.bots?.length) {
|
|
34
|
-
|
|
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.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
if (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
|
-
|
|
143
|
+
F.kv('Prompt', bot.system_prompt.slice(0, 80) + (bot.system_prompt.length > 80 ? '...' : ''));
|
|
115
144
|
}
|
|
116
145
|
} else {
|
|
117
|
-
|
|
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
|
-
|
|
126
|
-
|
|
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;
|
|
@@ -0,0 +1,214 @@
|
|
|
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
|
+
const { getConfig, saveConfig } = require('../utils/config');
|
|
7
|
+
|
|
8
|
+
const APPROVALS_FILE = path.join(os.homedir(), '.natureco', 'approvals.json');
|
|
9
|
+
const ALLOWLIST_FILE = path.join(os.homedir(), '.natureco', 'approval-allowlist.json');
|
|
10
|
+
|
|
11
|
+
function loadQueue() {
|
|
12
|
+
if (!fs.existsSync(APPROVALS_FILE)) return [];
|
|
13
|
+
try { return JSON.parse(fs.readFileSync(APPROVALS_FILE, 'utf-8')); }
|
|
14
|
+
catch { return []; }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function saveQueue(items) {
|
|
18
|
+
const dir = path.dirname(APPROVALS_FILE);
|
|
19
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
20
|
+
fs.writeFileSync(APPROVALS_FILE, JSON.stringify(items, null, 2), 'utf-8');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function genId() { return Date.now().toString(36) + Math.random().toString(36).slice(2, 6); }
|
|
24
|
+
|
|
25
|
+
function loadAllowlist() {
|
|
26
|
+
if (!fs.existsSync(ALLOWLIST_FILE)) return [];
|
|
27
|
+
try { return JSON.parse(fs.readFileSync(ALLOWLIST_FILE, 'utf-8')); }
|
|
28
|
+
catch { return []; }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function saveAllowlist(patterns) {
|
|
32
|
+
const dir = path.dirname(ALLOWLIST_FILE);
|
|
33
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
34
|
+
fs.writeFileSync(ALLOWLIST_FILE, JSON.stringify(patterns, null, 2), 'utf-8');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function approvals(args) {
|
|
38
|
+
const [action, ...params] = args || [];
|
|
39
|
+
|
|
40
|
+
if (!action || action === 'list') return listApprovals();
|
|
41
|
+
if (action === 'pending') return listPending();
|
|
42
|
+
if (action === 'approve') return approveReq(params[0]);
|
|
43
|
+
if (action === 'reject') return rejectReq(params[0]);
|
|
44
|
+
if (action === 'set-policy') return setPolicy(params[0]);
|
|
45
|
+
if (action === 'add') return addReq(params.join(' '));
|
|
46
|
+
if (action === 'get') return getReq(params[0]);
|
|
47
|
+
if (action === 'set') return setPolicy(params[0]);
|
|
48
|
+
if (action === 'allowlist' && params[0] === 'add') return allowlistAdd(params.slice(1).join(' '));
|
|
49
|
+
if (action === 'allowlist' && params[0] === 'remove') return allowlistRemove(params.slice(1).join(' '));
|
|
50
|
+
if (action === 'allowlist') return listAllowlist();
|
|
51
|
+
|
|
52
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
53
|
+
console.log(chalk.gray(' Kullanım: natureco approvals [list|pending|approve|reject|set-policy|set|add|get|allowlist]\n'));
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function listApprovals() {
|
|
58
|
+
const config = getConfig();
|
|
59
|
+
const policy = config.execApprovalPolicy || 'auto';
|
|
60
|
+
const queue = loadQueue();
|
|
61
|
+
|
|
62
|
+
F.header('Approvals');
|
|
63
|
+
F.kv('Policy', policy);
|
|
64
|
+
F.kv('Queue', `${queue.filter(r => r.status === 'pending').length} pending`);
|
|
65
|
+
|
|
66
|
+
const rows = queue.map(r => [
|
|
67
|
+
r.id,
|
|
68
|
+
r.source || 'cli',
|
|
69
|
+
r.text,
|
|
70
|
+
r.status,
|
|
71
|
+
]);
|
|
72
|
+
F.table(['ID', 'Requester', 'Command', 'Status'], rows);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function listPending() {
|
|
76
|
+
const queue = loadQueue().filter(r => r.status === 'pending');
|
|
77
|
+
if (queue.length === 0) {
|
|
78
|
+
F.info('No pending approvals.');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const rows = queue.map(r => [
|
|
83
|
+
r.id,
|
|
84
|
+
r.source || 'cli',
|
|
85
|
+
r.text,
|
|
86
|
+
r.status,
|
|
87
|
+
]);
|
|
88
|
+
F.table(['ID', 'Requester', 'Command', 'Status'], rows);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function addReq(text) {
|
|
92
|
+
if (!text) {
|
|
93
|
+
console.log(chalk.red('\n ❌ Request text gerekli\n'));
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
const queue = loadQueue();
|
|
97
|
+
const r = { id: genId(), text, status: 'pending', source: 'cli', createdAt: new Date().toISOString(), resolvedAt: null };
|
|
98
|
+
queue.push(r);
|
|
99
|
+
saveQueue(queue);
|
|
100
|
+
console.log(chalk.yellow(`\n ⏳ Onay beklemede: ${r.id}\n`));
|
|
101
|
+
console.log(` ${chalk.white(text)}`);
|
|
102
|
+
console.log(chalk.gray(` Onaylamak için: natureco approvals approve ${r.id}`));
|
|
103
|
+
console.log();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function approveReq(id) {
|
|
107
|
+
const queue = loadQueue();
|
|
108
|
+
if (id) {
|
|
109
|
+
const r = queue.find(x => x.id === id);
|
|
110
|
+
if (!r) { console.log(chalk.red(`\n ❌ Request bulunamadı: ${id}\n`)); process.exit(1); }
|
|
111
|
+
if (r.status !== 'pending') { console.log(chalk.yellow(`\n ⚠️ "${id}" zaten ${r.status}\n`)); return; }
|
|
112
|
+
r.status = 'approved';
|
|
113
|
+
r.resolvedAt = new Date().toISOString();
|
|
114
|
+
saveQueue(queue);
|
|
115
|
+
F.success(`Approved: ${r.text}`);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const pending = queue.filter(r => r.status === 'pending');
|
|
119
|
+
if (pending.length === 0) { console.log(chalk.gray('\n Bekleyen onay yok\n')); return; }
|
|
120
|
+
for (const r of pending) { r.status = 'approved'; r.resolvedAt = new Date().toISOString(); }
|
|
121
|
+
saveQueue(queue);
|
|
122
|
+
F.success(`${pending.length} requests approved`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function rejectReq(id) {
|
|
126
|
+
const queue = loadQueue();
|
|
127
|
+
if (id) {
|
|
128
|
+
const r = queue.find(x => x.id === id);
|
|
129
|
+
if (!r) { console.log(chalk.red(`\n ❌ Request bulunamadı: ${id}\n`)); process.exit(1); }
|
|
130
|
+
if (r.status !== 'pending') { console.log(chalk.yellow(`\n ⚠️ "${id}" zaten ${r.status}\n`)); return; }
|
|
131
|
+
r.status = 'rejected';
|
|
132
|
+
r.resolvedAt = new Date().toISOString();
|
|
133
|
+
saveQueue(queue);
|
|
134
|
+
F.error(`Rejected: ${r.text}`);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const pending = queue.filter(r => r.status === 'pending');
|
|
138
|
+
if (pending.length === 0) { console.log(chalk.gray('\n Bekleyen onay yok\n')); return; }
|
|
139
|
+
for (const r of pending) { r.status = 'rejected'; r.resolvedAt = new Date().toISOString(); }
|
|
140
|
+
saveQueue(queue);
|
|
141
|
+
F.error(`${pending.length} requests rejected`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function setPolicy(policy) {
|
|
145
|
+
if (!policy || !['auto', 'always-ask', 'trusted'].includes(policy)) {
|
|
146
|
+
console.log(chalk.red('\n ❌ Policy must be: auto, always-ask, or trusted\n'));
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
const config = getConfig();
|
|
150
|
+
config.execApprovalPolicy = policy;
|
|
151
|
+
saveConfig(config);
|
|
152
|
+
console.log(chalk.green(`\n ✅ Approval policy: ${policy}\n`));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function getReq(id) {
|
|
156
|
+
if (!id) {
|
|
157
|
+
console.log(chalk.red('\n ❌ Request ID gerekli\n'));
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
const queue = loadQueue();
|
|
161
|
+
const r = queue.find(x => x.id === id);
|
|
162
|
+
if (!r) {
|
|
163
|
+
console.log(chalk.red(`\n ❌ Request bulunamadı: ${id}\n`));
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
F.kv('ID', r.id);
|
|
167
|
+
F.kv('Text', r.text);
|
|
168
|
+
F.kv('Status', r.status);
|
|
169
|
+
F.kv('Source', r.source || 'cli');
|
|
170
|
+
F.kv('Created', r.createdAt ? new Date(r.createdAt).toLocaleString() : '-');
|
|
171
|
+
F.kv('Resolved', r.resolvedAt ? new Date(r.resolvedAt).toLocaleString() : '-');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function listAllowlist() {
|
|
175
|
+
const patterns = loadAllowlist();
|
|
176
|
+
if (patterns.length === 0) {
|
|
177
|
+
F.info('No patterns in allowlist.');
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
F.list(patterns);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function allowlistAdd(pattern) {
|
|
184
|
+
if (!pattern) {
|
|
185
|
+
console.log(chalk.red('\n ❌ Pattern gerekli\n'));
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
const patterns = loadAllowlist();
|
|
189
|
+
if (patterns.includes(pattern)) {
|
|
190
|
+
F.warning(`Pattern already in allowlist: ${pattern}`);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
patterns.push(pattern);
|
|
194
|
+
saveAllowlist(patterns);
|
|
195
|
+
F.success(`Added to allowlist: ${pattern}`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function allowlistRemove(pattern) {
|
|
199
|
+
if (!pattern) {
|
|
200
|
+
console.log(chalk.red('\n ❌ Pattern gerekli\n'));
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
let patterns = loadAllowlist();
|
|
204
|
+
const initial = patterns.length;
|
|
205
|
+
patterns = patterns.filter(p => p !== pattern);
|
|
206
|
+
if (patterns.length === initial) {
|
|
207
|
+
F.warning(`Pattern not found in allowlist: ${pattern}`);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
saveAllowlist(patterns);
|
|
211
|
+
F.success(`Removed from allowlist: ${pattern}`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
module.exports = approvals;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
const NATURECO_DIR = path.join(os.homedir(), '.natureco');
|
|
8
|
+
|
|
9
|
+
function backup(args) {
|
|
10
|
+
const [action, ...params] = args || [];
|
|
11
|
+
|
|
12
|
+
if (!action || action === 'create') return createBackup();
|
|
13
|
+
if (action === 'list') return listBackups();
|
|
14
|
+
if (action === 'restore') return restoreBackup(params.join(' '));
|
|
15
|
+
if (action === 'verify') return verifyBackup(params.join(' '));
|
|
16
|
+
|
|
17
|
+
console.log(chalk.red(`\n ❌ Bilinmeyen komut: ${action}\n`));
|
|
18
|
+
console.log(chalk.gray(' Kullanım: natureco backup [create|list|restore|verify]\n'));
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function createBackup() {
|
|
23
|
+
const backupDir = path.join(os.homedir(), '.natureco-backups');
|
|
24
|
+
if (!fs.existsSync(backupDir)) fs.mkdirSync(backupDir, { recursive: true });
|
|
25
|
+
|
|
26
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
27
|
+
const backupFile = path.join(backupDir, `natureco-backup-${timestamp}.tar.gz`);
|
|
28
|
+
|
|
29
|
+
console.log(chalk.cyan('\n 💾 Creating backup...\n'));
|
|
30
|
+
|
|
31
|
+
if (fs.existsSync(NATURECO_DIR)) {
|
|
32
|
+
try {
|
|
33
|
+
execSync(`tar -czf "${backupFile}" -C "${path.dirname(NATURECO_DIR)}" "${path.basename(NATURECO_DIR)}"`, {
|
|
34
|
+
stdio: 'pipe',
|
|
35
|
+
encoding: 'utf8',
|
|
36
|
+
timeout: 30000
|
|
37
|
+
});
|
|
38
|
+
const size = fs.statSync(backupFile).size;
|
|
39
|
+
console.log(chalk.green(` ✅ Backup created: ${backupFile}`));
|
|
40
|
+
console.log(chalk.gray(` Size: ${(size / 1024).toFixed(1)} KB`));
|
|
41
|
+
} catch (err) {
|
|
42
|
+
console.log(chalk.yellow(' ⚠️ tar backup failed, trying copy...'));
|
|
43
|
+
const fallbackFile = backupFile.replace('.tar.gz', '.json');
|
|
44
|
+
const config = require('../utils/config').getConfig();
|
|
45
|
+
fs.writeFileSync(fallbackFile, JSON.stringify(config, null, 2));
|
|
46
|
+
console.log(chalk.green(` ✅ Config backup: ${fallbackFile}`));
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
console.log(chalk.yellow(' ⚠️ No NatureCo directory found\n'));
|
|
50
|
+
}
|
|
51
|
+
console.log();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function listBackups() {
|
|
55
|
+
const backupDir = path.join(os.homedir(), '.natureco-backups');
|
|
56
|
+
console.log(chalk.cyan('\n 📋 Backups\n'));
|
|
57
|
+
console.log(chalk.gray(' ' + '─'.repeat(48)));
|
|
58
|
+
|
|
59
|
+
if (!fs.existsSync(backupDir)) {
|
|
60
|
+
console.log(chalk.gray(' No backups found.\n'));
|
|
61
|
+
console.log(chalk.gray(' Create one: ') + chalk.cyan('natureco backup create\n'));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const files = fs.readdirSync(backupDir).filter(f => f.startsWith('natureco-backup'));
|
|
66
|
+
if (files.length === 0) {
|
|
67
|
+
console.log(chalk.gray(' No backups found.\n'));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for (const f of files.sort().reverse()) {
|
|
72
|
+
const stat = fs.statSync(path.join(backupDir, f));
|
|
73
|
+
const size = (stat.size / 1024).toFixed(1);
|
|
74
|
+
const date = stat.birthtime.toLocaleString();
|
|
75
|
+
console.log(` ${chalk.cyan('●')} ${chalk.white(f)} ${chalk.gray(`(${size} KB, ${date})`)}`);
|
|
76
|
+
}
|
|
77
|
+
console.log();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function restoreBackup(file) {
|
|
81
|
+
if (!file) {
|
|
82
|
+
console.log(chalk.red('\n ❌ Backup file gerekli\n'));
|
|
83
|
+
console.log(chalk.cyan(' natureco backup list'));
|
|
84
|
+
console.log(chalk.cyan(' natureco backup restore <filename>\n'));
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const backupDir = path.join(os.homedir(), '.natureco-backups');
|
|
89
|
+
const backupFile = path.join(backupDir, file);
|
|
90
|
+
|
|
91
|
+
if (!fs.existsSync(backupFile)) {
|
|
92
|
+
console.log(chalk.red(`\n ❌ Backup bulunamadı: ${backupFile}\n`));
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
console.log(chalk.yellow(`\n ⚠️ Restoring ${file}...\n`));
|
|
97
|
+
try {
|
|
98
|
+
execSync(`tar -xzf "${backupFile}" -C "${os.homedir()}"`, { stdio: 'pipe', timeout: 15000 });
|
|
99
|
+
console.log(chalk.green(' ✅ Restore complete\n'));
|
|
100
|
+
} catch {
|
|
101
|
+
console.log(chalk.red(' ❌ Restore failed\n'));
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function verifyBackup(file) {
|
|
107
|
+
if (!file) {
|
|
108
|
+
console.log(chalk.red('\n ❌ Backup file gerekli\n'));
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const backupDir = path.join(os.homedir(), '.natureco-backups');
|
|
113
|
+
const backupFile = path.join(backupDir, file);
|
|
114
|
+
|
|
115
|
+
if (!fs.existsSync(backupFile)) {
|
|
116
|
+
console.log(chalk.red(`\n ❌ Backup bulunamadı: ${backupFile}\n`));
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const stat = fs.statSync(backupFile);
|
|
121
|
+
console.log(chalk.green(`\n ✅ Backup verified: ${file} (${(stat.size / 1024).toFixed(1)} KB)\n`));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
module.exports = backup;
|