natureco-cli 2.23.31 → 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.
- package/bin/natureco.js +14 -6
- package/package.json +1 -1
- package/src/commands/ask.js +1 -1
- package/src/commands/config.js +11 -2
- package/src/commands/nodes.js +1 -1
- package/src/commands/setup.js +131 -4
- package/src/commands/web-fetch.js +34 -0
- package/src/utils/api.js +1 -1
package/bin/natureco.js
CHANGED
|
@@ -182,11 +182,11 @@ program
|
|
|
182
182
|
.action(login);
|
|
183
183
|
|
|
184
184
|
program
|
|
185
|
-
.command('setup')
|
|
186
|
-
.description('Run initial setup wizard')
|
|
187
|
-
.action(async () => {
|
|
185
|
+
.command('setup [action]')
|
|
186
|
+
.description('Run initial setup wizard (wizard|config|workspace|dirs|status)')
|
|
187
|
+
.action(async (action) => {
|
|
188
188
|
const setup = require('../src/commands/setup');
|
|
189
|
-
await setup();
|
|
189
|
+
await setup(action ? [action] : []);
|
|
190
190
|
});
|
|
191
191
|
|
|
192
192
|
program
|
|
@@ -877,17 +877,25 @@ program
|
|
|
877
877
|
// === OpenClaw uyumlu alias komutlar ===
|
|
878
878
|
|
|
879
879
|
program
|
|
880
|
-
.command('acp [file]')
|
|
880
|
+
.command('acp [file]')
|
|
881
881
|
.description('Alias for code command')
|
|
882
882
|
.action((file) => {
|
|
883
883
|
const codeCmd = require('../src/commands/code');
|
|
884
884
|
codeCmd(file, { dir: process.cwd() });
|
|
885
885
|
});
|
|
886
886
|
|
|
887
|
+
program
|
|
888
|
+
.command('web-fetch [url]')
|
|
889
|
+
.description('Fetch a URL and convert to markdown')
|
|
890
|
+
.action(async (url) => {
|
|
891
|
+
const webFetch = require('../src/commands/web-fetch');
|
|
892
|
+
await webFetch(url);
|
|
893
|
+
});
|
|
894
|
+
|
|
887
895
|
program
|
|
888
896
|
.command('help')
|
|
889
897
|
.description('Show help information')
|
|
890
|
-
.action(help);
|
|
898
|
+
.action(help);
|
|
891
899
|
|
|
892
900
|
// Komut verilmezse gateway göster
|
|
893
901
|
if (!process.argv.slice(2).length) {
|
package/package.json
CHANGED
package/src/commands/ask.js
CHANGED
|
@@ -41,7 +41,7 @@ async function ask(question) {
|
|
|
41
41
|
}, 80);
|
|
42
42
|
|
|
43
43
|
try {
|
|
44
|
-
const response = await sendMessage(apiKey, defaultBotId, question, null, systemPrompt);
|
|
44
|
+
const response = await sendMessage(apiKey, defaultBotId, question, null, systemPrompt, { stream: false });
|
|
45
45
|
|
|
46
46
|
clearInterval(loadingInterval);
|
|
47
47
|
process.stdout.write('\r');
|
package/src/commands/config.js
CHANGED
|
@@ -13,12 +13,21 @@ function config(args) {
|
|
|
13
13
|
process.exit(1);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
const SENSITIVE_KEYS = ['apiKey', 'providerApiKey', 'providerApiKey1', 'providerApiKey2', 'secret', 'token', 'password', 'webhookSecret'];
|
|
17
|
+
|
|
18
|
+
function maskSensitive(key, value) {
|
|
19
|
+
if (typeof value !== 'string' || value.length < 8) return value;
|
|
20
|
+
const lower = key.toLowerCase();
|
|
21
|
+
if (!SENSITIVE_KEYS.some(sk => lower.includes(sk.toLowerCase()))) return value;
|
|
22
|
+
return value.slice(0, 4) + '*'.repeat(Math.min(value.length - 8, 16)) + value.slice(-4);
|
|
23
|
+
}
|
|
24
|
+
|
|
16
25
|
if (action === 'list') {
|
|
17
26
|
const cfg = getAllConfig();
|
|
18
27
|
F.header('Configuration');
|
|
19
28
|
const rows = Object.entries(cfg).map(([k, v]) => [
|
|
20
29
|
k,
|
|
21
|
-
typeof v === 'string' ? v : JSON.stringify(v),
|
|
30
|
+
maskSensitive(k, typeof v === 'string' ? v : JSON.stringify(v)),
|
|
22
31
|
]);
|
|
23
32
|
F.table(['Key', 'Value'], rows);
|
|
24
33
|
return;
|
|
@@ -38,7 +47,7 @@ function config(args) {
|
|
|
38
47
|
if (value === undefined) {
|
|
39
48
|
F.info(`${key}: (tanımlı değil)`);
|
|
40
49
|
} else {
|
|
41
|
-
F.kv(key, JSON.stringify(value, null, 2));
|
|
50
|
+
F.kv(key, maskSensitive(key, JSON.stringify(value, null, 2)));
|
|
42
51
|
}
|
|
43
52
|
return;
|
|
44
53
|
}
|
package/src/commands/nodes.js
CHANGED
|
@@ -352,7 +352,7 @@ function nodeDescribe(nodeId) {
|
|
|
352
352
|
['Key', node.key ? node.key.substring(0, 8) + '...' : 'none'],
|
|
353
353
|
['Paired At', node.pairedAt ? new Date(node.pairedAt).toLocaleString() : 'unknown'],
|
|
354
354
|
['OS', 'linux (mock)'],
|
|
355
|
-
['Version', '2.23.
|
|
355
|
+
['Version', '2.23.32 (mock)'],
|
|
356
356
|
['CPU', '4 vCPU (mock)'],
|
|
357
357
|
['Memory', '8 GB (mock)'],
|
|
358
358
|
['Services', 'gateway, mcp, file-sync (mock)'],
|
package/src/commands/setup.js
CHANGED
|
@@ -2,28 +2,147 @@ const chalk = require('chalk');
|
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const os = require('os');
|
|
5
|
+
const readline = require('readline');
|
|
6
|
+
const inquirer = require('../utils/inquirer-wrapper');
|
|
5
7
|
|
|
6
8
|
const BASE_DIR = path.join(os.homedir(), '.natureco');
|
|
7
9
|
const CONFIG_FILE = path.join(BASE_DIR, 'config.json');
|
|
8
10
|
|
|
9
11
|
const DIRS = ['sources', 'concepts', 'cache', 'skills', 'memory', 'sessions', 'backups'];
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
const PROVIDER_PRESETS = {
|
|
14
|
+
groq: { url: 'https://api.groq.com/openai/v1', model: 'llama-3.3-70b-versatile' },
|
|
15
|
+
openai: { url: 'https://api.openai.com/v1', model: 'gpt-4o' },
|
|
16
|
+
anthropic:{ url: 'https://api.anthropic.com', model: 'claude-sonnet-4-6' },
|
|
17
|
+
deepseek: { url: 'https://api.deepseek.com/v1', model: 'deepseek-chat' },
|
|
18
|
+
ollama: { url: 'http://localhost:11434/v1', model: 'llama3.3' },
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function rlQuestion(query) {
|
|
22
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
23
|
+
return new Promise(resolve => {
|
|
24
|
+
rl.question(query, answer => { rl.close(); resolve(answer.trim()); });
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getConfig() {
|
|
29
|
+
if (!fs.existsSync(CONFIG_FILE)) return {};
|
|
30
|
+
try { return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); }
|
|
31
|
+
catch { return {}; }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function saveConfig(data) {
|
|
35
|
+
if (!fs.existsSync(BASE_DIR)) fs.mkdirSync(BASE_DIR, { recursive: true });
|
|
36
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(data, null, 2), 'utf8');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function setup(params) {
|
|
12
40
|
try {
|
|
13
41
|
const [action] = params || [];
|
|
14
42
|
|
|
15
|
-
if (!action || action === '
|
|
43
|
+
if (!action || action === 'wizard') return await cmdWizard();
|
|
44
|
+
if (action === 'status') return cmdStatus();
|
|
16
45
|
if (action === 'config') return cmdConfig();
|
|
17
46
|
if (action === 'workspace') return cmdWorkspace();
|
|
18
47
|
if (action === 'dirs') return cmdDirs();
|
|
19
48
|
|
|
20
|
-
console.log(chalk.
|
|
21
|
-
console.log(chalk.gray('
|
|
49
|
+
console.log(chalk.yellow('\n Usage:'));
|
|
50
|
+
console.log(chalk.gray(' natureco setup Interactive setup wizard'));
|
|
51
|
+
console.log(chalk.gray(' natureco setup config Create default config'));
|
|
52
|
+
console.log(chalk.gray(' natureco setup workspace Create workspace directories'));
|
|
53
|
+
console.log(chalk.gray(' natureco setup dirs Create data directories'));
|
|
54
|
+
console.log(chalk.gray(' natureco setup status Show setup status\n'));
|
|
22
55
|
} catch (err) {
|
|
23
56
|
console.log(chalk.red(`\n Setup error: ${err.message}\n`));
|
|
24
57
|
}
|
|
25
58
|
}
|
|
26
59
|
|
|
60
|
+
async function cmdWizard() {
|
|
61
|
+
console.clear();
|
|
62
|
+
console.log('');
|
|
63
|
+
console.log(chalk.green.bold(' (\\_/)'));
|
|
64
|
+
console.log(chalk.green.bold(' (•ᴥ•)'));
|
|
65
|
+
console.log(chalk.green(' />🌿'));
|
|
66
|
+
console.log('');
|
|
67
|
+
console.log(chalk.green.bold(' NatureCo CLI — Setup Wizard'));
|
|
68
|
+
console.log(chalk.gray(' Choose your AI provider and enter your API key.\n'));
|
|
69
|
+
|
|
70
|
+
// Ensure directories
|
|
71
|
+
if (!fs.existsSync(BASE_DIR)) fs.mkdirSync(BASE_DIR, { recursive: true });
|
|
72
|
+
for (const dir of DIRS) {
|
|
73
|
+
const p = path.join(BASE_DIR, dir);
|
|
74
|
+
if (!fs.existsSync(p)) fs.mkdirSync(p, { recursive: true });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const cfg = getConfig();
|
|
78
|
+
|
|
79
|
+
// Step 1: Provider selection
|
|
80
|
+
console.log(chalk.white(' Step 1: Provider'));
|
|
81
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
82
|
+
const providerKeys = Object.keys(PROVIDER_PRESETS);
|
|
83
|
+
const { provider } = await inquirer.prompt([{
|
|
84
|
+
type: 'list',
|
|
85
|
+
name: 'provider',
|
|
86
|
+
message: ' AI Provider:',
|
|
87
|
+
choices: [
|
|
88
|
+
...providerKeys.map(k => ({
|
|
89
|
+
name: `${k.charAt(0).toUpperCase() + k.slice(1)} (${PROVIDER_PRESETS[k].model})`,
|
|
90
|
+
value: k,
|
|
91
|
+
})),
|
|
92
|
+
{ name: 'Custom URL', value: 'custom' },
|
|
93
|
+
],
|
|
94
|
+
}]);
|
|
95
|
+
|
|
96
|
+
let providerUrl, providerModel;
|
|
97
|
+
if (provider === 'custom') {
|
|
98
|
+
providerUrl = await rlQuestion(` Provider URL (${cfg.providerUrl || 'https://api.openai.com/v1'}): `);
|
|
99
|
+
providerModel = await rlQuestion(` Model (${cfg.providerModel || 'gpt-4o'}): `);
|
|
100
|
+
providerUrl = providerUrl || cfg.providerUrl || 'https://api.openai.com/v1';
|
|
101
|
+
providerModel = providerModel || cfg.providerModel || 'gpt-4o';
|
|
102
|
+
} else {
|
|
103
|
+
const preset = PROVIDER_PRESETS[provider];
|
|
104
|
+
providerUrl = preset.url;
|
|
105
|
+
providerModel = preset.model;
|
|
106
|
+
console.log(chalk.gray(` URL: ${providerUrl}`));
|
|
107
|
+
console.log(chalk.gray(` Model: ${providerModel}`));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Step 2: API Key
|
|
111
|
+
console.log('');
|
|
112
|
+
console.log(chalk.white(' Step 2: API Key'));
|
|
113
|
+
console.log(chalk.gray(' ─────────────────────────────────────────────'));
|
|
114
|
+
console.log(chalk.gray(' Get a key from: ') + chalk.cyan('developers.natureco.me'));
|
|
115
|
+
console.log(chalk.gray(' Or use your own provider API key.\n'));
|
|
116
|
+
|
|
117
|
+
const currentKey = cfg.providerApiKey || '';
|
|
118
|
+
const apiKey = await rlQuestion(` API Key ${currentKey ? '(leave blank to keep current)' : ''}: `);
|
|
119
|
+
if (apiKey) {
|
|
120
|
+
cfg.providerApiKey = apiKey;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Step 3: Save
|
|
124
|
+
cfg.providerUrl = providerUrl;
|
|
125
|
+
cfg.providerModel = providerModel;
|
|
126
|
+
cfg.setupCompleted = true;
|
|
127
|
+
cfg.updated = new Date().toISOString();
|
|
128
|
+
if (!cfg.created) cfg.created = new Date().toISOString();
|
|
129
|
+
if (!cfg.version) cfg.version = 1;
|
|
130
|
+
if (cfg.skills === undefined) cfg.skills = { enabled: true, list: [] };
|
|
131
|
+
if (cfg.mcpServers === undefined) cfg.mcpServers = {};
|
|
132
|
+
|
|
133
|
+
saveConfig(cfg);
|
|
134
|
+
|
|
135
|
+
console.log('');
|
|
136
|
+
console.log(chalk.green(' ✓ Setup complete!\n'));
|
|
137
|
+
console.log(chalk.white(' Config saved to: ') + chalk.gray(CONFIG_FILE));
|
|
138
|
+
console.log('');
|
|
139
|
+
console.log(chalk.white(' Next steps:'));
|
|
140
|
+
console.log(chalk.cyan(' natureco chat Start chatting'));
|
|
141
|
+
console.log(chalk.cyan(' natureco login Login with API key'));
|
|
142
|
+
console.log(chalk.cyan(' natureco help View all commands'));
|
|
143
|
+
console.log('');
|
|
144
|
+
}
|
|
145
|
+
|
|
27
146
|
function cmdStatus() {
|
|
28
147
|
console.log(chalk.cyan('\n Setup Status\n'));
|
|
29
148
|
|
|
@@ -33,6 +152,14 @@ function cmdStatus() {
|
|
|
33
152
|
console.log(chalk.white(' Config: ') + (configExists ? chalk.green('exists') : chalk.yellow('missing')));
|
|
34
153
|
console.log(chalk.white(' Directory: ') + (dirExists ? chalk.green('exists') : chalk.yellow('missing')));
|
|
35
154
|
|
|
155
|
+
if (configExists) {
|
|
156
|
+
const cfg = getConfig();
|
|
157
|
+
console.log(chalk.white(' Provider: ') + chalk.gray(cfg.providerUrl || 'not set'));
|
|
158
|
+
console.log(chalk.white(' Model: ') + chalk.gray(cfg.providerModel || 'not set'));
|
|
159
|
+
console.log(chalk.white(' API Key: ') + (cfg.providerApiKey ? chalk.green('set') : chalk.yellow('not set')));
|
|
160
|
+
console.log(chalk.white(' Setup: ') + (cfg.setupCompleted ? chalk.green('completed') : chalk.yellow('incomplete')));
|
|
161
|
+
}
|
|
162
|
+
|
|
36
163
|
if (dirExists) {
|
|
37
164
|
const existing = fs.readdirSync(BASE_DIR).filter(f => fs.statSync(path.join(BASE_DIR, f)).isDirectory());
|
|
38
165
|
const present = DIRS.filter(d => existing.includes(d));
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const { fetchAsMarkdown } = require('../utils/web-fetch');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
|
|
4
|
+
async function webFetch(url) {
|
|
5
|
+
if (!url) {
|
|
6
|
+
console.log(chalk.yellow('\n Usage: natureco web-fetch <url>\n'));
|
|
7
|
+
console.log(chalk.gray(' Fetches a URL and converts it to clean markdown.\n'));
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
console.log(chalk.gray(` Fetching: ${url}\n`));
|
|
12
|
+
|
|
13
|
+
const result = await fetchAsMarkdown(url);
|
|
14
|
+
|
|
15
|
+
if (result.error) {
|
|
16
|
+
console.log(chalk.red(` ❌ ${result.error}\n`));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (result.title) {
|
|
21
|
+
console.log(chalk.white(' Title: ') + chalk.cyan(result.title));
|
|
22
|
+
}
|
|
23
|
+
console.log(chalk.gray(` Source: ${result.url}`));
|
|
24
|
+
console.log(chalk.gray(` Fetched: ${result.fetchedAt}`));
|
|
25
|
+
console.log('');
|
|
26
|
+
|
|
27
|
+
if (result.content) {
|
|
28
|
+
console.log(result.content);
|
|
29
|
+
} else {
|
|
30
|
+
console.log(chalk.yellow(' No content extracted.\n'));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = webFetch;
|
package/src/utils/api.js
CHANGED
|
@@ -558,7 +558,7 @@ async function sendMessageToProvider(apiKey, message, conversationId = null, sys
|
|
|
558
558
|
const augmentedPrompt = agentsMd.injectIntoPrompt(systemPrompt || '', options?.cwd || process.cwd());
|
|
559
559
|
|
|
560
560
|
// Build messages
|
|
561
|
-
|
|
561
|
+
let messages = [];
|
|
562
562
|
if (augmentedPrompt) {
|
|
563
563
|
messages.push({ role: 'system', content: augmentedPrompt });
|
|
564
564
|
}
|