natureco-cli 2.12.0 → 2.12.1
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 +10 -0
- package/package.json +1 -1
- package/src/commands/dashboard.js +2 -2
- package/src/commands/migrate.js +223 -0
package/bin/natureco.js
CHANGED
|
@@ -97,6 +97,16 @@ program
|
|
|
97
97
|
updateCmd();
|
|
98
98
|
});
|
|
99
99
|
|
|
100
|
+
program
|
|
101
|
+
.command('migrate')
|
|
102
|
+
.description('Migrate from other CLI tools')
|
|
103
|
+
.option('--from <source>', 'Source CLI (openclaw)')
|
|
104
|
+
.option('--openclaw-dir <path>', 'OpenClaw directory path (default: ~/.openclaw)')
|
|
105
|
+
.action((options) => {
|
|
106
|
+
const migrateCmd = require('../src/commands/migrate');
|
|
107
|
+
migrateCmd(options);
|
|
108
|
+
});
|
|
109
|
+
|
|
100
110
|
program
|
|
101
111
|
.command('commands [action] [params...]')
|
|
102
112
|
.description('Manage custom commands (list|create)')
|
package/package.json
CHANGED
|
@@ -211,7 +211,7 @@ body::before{
|
|
|
211
211
|
<div class="header-bot-name" id="header-bot-name">Nature Bot</div>
|
|
212
212
|
<div class="header-bot-model" id="header-bot-model">NatureCo</div>
|
|
213
213
|
</div>
|
|
214
|
-
<div class="version-badge" id="version-badge">v2.12.
|
|
214
|
+
<div class="version-badge" id="version-badge">v2.12.1</div>
|
|
215
215
|
</div>
|
|
216
216
|
<div class="messages" id="messages"></div>
|
|
217
217
|
<div class="input-area">
|
|
@@ -341,7 +341,7 @@ function dashboard(action) {
|
|
|
341
341
|
apiKey: cfg.apiKey,
|
|
342
342
|
defaultBot: cfg.defaultBot,
|
|
343
343
|
defaultBotId: cfg.defaultBotId,
|
|
344
|
-
version: 'v2.12.
|
|
344
|
+
version: 'v2.12.1',
|
|
345
345
|
bots: cfg.bots || [],
|
|
346
346
|
telegramToken: cfg.telegramToken || null,
|
|
347
347
|
whatsappConnected: cfg.whatsappConnected || false,
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const { getConfig, setConfig } = require('../utils/config');
|
|
6
|
+
|
|
7
|
+
async function migrate(options) {
|
|
8
|
+
const from = options.from || 'openclaw';
|
|
9
|
+
|
|
10
|
+
if (from !== 'openclaw') {
|
|
11
|
+
console.log(chalk.red('\n❌ Sadece OpenClaw migration destekleniyor.\n'));
|
|
12
|
+
console.log(chalk.gray('Kullanım: natureco migrate --from openclaw\n'));
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
console.log(chalk.yellow('\n⏳ OpenClaw → NatureCo migration başlıyor...\n'));
|
|
17
|
+
|
|
18
|
+
// OpenClaw directory
|
|
19
|
+
const openclawDir = options.openclawDir || path.join(os.homedir(), '.openclaw');
|
|
20
|
+
|
|
21
|
+
if (!fs.existsSync(openclawDir)) {
|
|
22
|
+
console.log(chalk.red(`❌ OpenClaw dizini bulunamadı: ${openclawDir}\n`));
|
|
23
|
+
console.log(chalk.gray('--openclaw-dir ile farklı bir dizin belirtin.\n'));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
console.log(chalk.cyan('OpenClaw dizini:'), chalk.white(openclawDir));
|
|
28
|
+
console.log('');
|
|
29
|
+
|
|
30
|
+
const report = {
|
|
31
|
+
memory: null,
|
|
32
|
+
crons: { total: 0, active: 0, inactive: 0 },
|
|
33
|
+
telegram: null,
|
|
34
|
+
whatsapp: false,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// 1. Memory migration
|
|
38
|
+
try {
|
|
39
|
+
const userMdPath = path.join(openclawDir, 'workspace', 'USER.md');
|
|
40
|
+
|
|
41
|
+
if (fs.existsSync(userMdPath)) {
|
|
42
|
+
const userMd = fs.readFileSync(userMdPath, 'utf8');
|
|
43
|
+
|
|
44
|
+
// Parse USER.md
|
|
45
|
+
const nameMatch = userMd.match(/Name:\s*(.+)/i);
|
|
46
|
+
const timezoneMatch = userMd.match(/Timezone:\s*(.+)/i);
|
|
47
|
+
const notesMatch = userMd.match(/Notes:\s*(.+)/i);
|
|
48
|
+
|
|
49
|
+
const memory = {
|
|
50
|
+
name: nameMatch ? nameMatch[1].trim() : null,
|
|
51
|
+
facts: []
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
if (timezoneMatch) {
|
|
55
|
+
memory.facts.push(`Timezone: ${timezoneMatch[1].trim()}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (notesMatch) {
|
|
59
|
+
memory.facts.push(notesMatch[1].trim());
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Save to NatureCo memory
|
|
63
|
+
const memoryDir = path.join(os.homedir(), '.natureco', 'memory');
|
|
64
|
+
fs.mkdirSync(memoryDir, { recursive: true });
|
|
65
|
+
|
|
66
|
+
const memoryFile = path.join(memoryDir, 'universal-provider.json');
|
|
67
|
+
fs.writeFileSync(memoryFile, JSON.stringify(memory, null, 2));
|
|
68
|
+
|
|
69
|
+
report.memory = memory;
|
|
70
|
+
}
|
|
71
|
+
} catch (err) {
|
|
72
|
+
console.log(chalk.gray('⚠️ Memory migration atlandı:', err.message));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 2. Cron jobs migration
|
|
76
|
+
try {
|
|
77
|
+
const cronJobsPath = path.join(openclawDir, 'cron', 'jobs.json');
|
|
78
|
+
|
|
79
|
+
if (fs.existsSync(cronJobsPath)) {
|
|
80
|
+
const openclawCrons = JSON.parse(fs.readFileSync(cronJobsPath, 'utf8'));
|
|
81
|
+
|
|
82
|
+
const naturecoCrons = [];
|
|
83
|
+
|
|
84
|
+
for (const job of openclawCrons) {
|
|
85
|
+
report.crons.total++;
|
|
86
|
+
|
|
87
|
+
if (!job.enabled) {
|
|
88
|
+
report.crons.inactive++;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
report.crons.active++;
|
|
93
|
+
|
|
94
|
+
// Only migrate cron schedule (not interval)
|
|
95
|
+
if (job.schedule?.kind !== 'cron') {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Determine action based on delivery channel
|
|
100
|
+
let action = 'whatsapp'; // default
|
|
101
|
+
if (job.delivery?.channel === 'telegram') {
|
|
102
|
+
action = 'telegram';
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Get prompt (first 200 chars)
|
|
106
|
+
let prompt = job.payload?.message || '';
|
|
107
|
+
if (prompt.length > 200) {
|
|
108
|
+
prompt = prompt.slice(0, 200) + '...';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
naturecoCrons.push({
|
|
112
|
+
name: job.name || 'Unnamed Job',
|
|
113
|
+
schedule: job.schedule.expr,
|
|
114
|
+
action: action,
|
|
115
|
+
prompt: prompt,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Save to NatureCo crons
|
|
120
|
+
const cronsFile = path.join(os.homedir(), '.natureco', 'crons.json');
|
|
121
|
+
|
|
122
|
+
// Merge with existing crons if any
|
|
123
|
+
let existingCrons = [];
|
|
124
|
+
if (fs.existsSync(cronsFile)) {
|
|
125
|
+
existingCrons = JSON.parse(fs.readFileSync(cronsFile, 'utf8'));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const mergedCrons = [...existingCrons, ...naturecoCrons];
|
|
129
|
+
fs.writeFileSync(cronsFile, JSON.stringify(mergedCrons, null, 2));
|
|
130
|
+
}
|
|
131
|
+
} catch (err) {
|
|
132
|
+
console.log(chalk.gray('⚠️ Cron migration atlandı:', err.message));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 3. Telegram allowFrom migration
|
|
136
|
+
try {
|
|
137
|
+
const telegramAllowPath = path.join(openclawDir, 'credentials', 'telegram-default-allowFrom.json');
|
|
138
|
+
|
|
139
|
+
if (fs.existsSync(telegramAllowPath)) {
|
|
140
|
+
const allowFrom = JSON.parse(fs.readFileSync(telegramAllowPath, 'utf8'));
|
|
141
|
+
|
|
142
|
+
if (Array.isArray(allowFrom) && allowFrom.length > 0) {
|
|
143
|
+
// Save to NatureCo config
|
|
144
|
+
setConfig('telegramAllowedChats', allowFrom);
|
|
145
|
+
report.telegram = allowFrom;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
} catch (err) {
|
|
149
|
+
console.log(chalk.gray('⚠️ Telegram allowFrom migration atlandı:', err.message));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 4. WhatsApp session migration
|
|
153
|
+
try {
|
|
154
|
+
const whatsappSessionPath = path.join(openclawDir, 'credentials', 'whatsapp', 'default');
|
|
155
|
+
|
|
156
|
+
if (fs.existsSync(whatsappSessionPath)) {
|
|
157
|
+
const config = getConfig();
|
|
158
|
+
const botId = config.defaultBotId || 'whatsapp_default';
|
|
159
|
+
|
|
160
|
+
const naturecoSessionPath = path.join(os.homedir(), '.natureco', 'whatsapp-sessions', `whatsapp_${botId}`);
|
|
161
|
+
|
|
162
|
+
// Copy directory recursively
|
|
163
|
+
fs.mkdirSync(naturecoSessionPath, { recursive: true });
|
|
164
|
+
copyDirRecursive(whatsappSessionPath, naturecoSessionPath);
|
|
165
|
+
|
|
166
|
+
report.whatsapp = true;
|
|
167
|
+
}
|
|
168
|
+
} catch (err) {
|
|
169
|
+
console.log(chalk.gray('⚠️ WhatsApp session migration atlandı:', err.message));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Print migration report
|
|
173
|
+
console.log(chalk.green('✅ Migration tamamlandı!\n'));
|
|
174
|
+
|
|
175
|
+
if (report.memory) {
|
|
176
|
+
const facts = report.memory.facts.join(', ');
|
|
177
|
+
console.log(chalk.green('✅ Memory:'), chalk.white(`${report.memory.name || 'N/A'}${facts ? ', ' + facts : ''}`));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (report.crons.total > 0) {
|
|
181
|
+
console.log(chalk.green('✅ Cron jobs:'), chalk.white(`${report.crons.total} job migrate edildi (${report.crons.active} aktif, ${report.crons.inactive} pasif)`));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (report.telegram && report.telegram.length > 0) {
|
|
185
|
+
console.log(chalk.green('✅ Telegram allowFrom:'), chalk.white(report.telegram.join(', ')));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (report.whatsapp) {
|
|
189
|
+
console.log(chalk.green('✅ WhatsApp session kopyalandı'));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
console.log('');
|
|
193
|
+
console.log(chalk.yellow('⚠️ Manuel kurulum gerekli:'));
|
|
194
|
+
console.log(chalk.gray(' - Provider URL ve API key ayarlayın:'));
|
|
195
|
+
console.log(chalk.cyan(' natureco config set providerUrl https://api.groq.com/openai/v1'));
|
|
196
|
+
console.log(chalk.cyan(' natureco config set providerApiKey gsk_xxx'));
|
|
197
|
+
console.log(chalk.cyan(' natureco config set providerModel llama-3.1-8b-instant'));
|
|
198
|
+
console.log('');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Copy directory recursively
|
|
203
|
+
*/
|
|
204
|
+
function copyDirRecursive(src, dest) {
|
|
205
|
+
if (!fs.existsSync(src)) return;
|
|
206
|
+
|
|
207
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
208
|
+
|
|
209
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
210
|
+
|
|
211
|
+
for (const entry of entries) {
|
|
212
|
+
const srcPath = path.join(src, entry.name);
|
|
213
|
+
const destPath = path.join(dest, entry.name);
|
|
214
|
+
|
|
215
|
+
if (entry.isDirectory()) {
|
|
216
|
+
copyDirRecursive(srcPath, destPath);
|
|
217
|
+
} else {
|
|
218
|
+
fs.copyFileSync(srcPath, destPath);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
module.exports = migrate;
|