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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "natureco-cli",
3
- "version": "2.23.31",
3
+ "version": "2.23.32",
4
4
  "description": "NatureCo AI Bot Terminal Interface",
5
5
  "bin": {
6
6
  "natureco": "bin/natureco.js"
@@ -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');
@@ -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
  }
@@ -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.31 (mock)'],
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)'],
@@ -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
- function setup(params) {
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 === 'status') return cmdStatus();
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.red(`\n Unknown setup action: ${action}\n`));
21
- console.log(chalk.gray(' Usage: natureco setup [config|workspace|dirs|status]\n'));
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
- const messages = [];
561
+ let messages = [];
562
562
  if (augmentedPrompt) {
563
563
  messages.push({ role: 'system', content: augmentedPrompt });
564
564
  }