natureco-cli 1.0.6 → 1.0.8
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/package.json +1 -1
- package/src/commands/setup.js +252 -67
- package/src/commands/skills.js +47 -18
- package/src/utils/skills.js +2 -1
package/package.json
CHANGED
package/src/commands/setup.js
CHANGED
|
@@ -34,6 +34,17 @@ async function setup() {
|
|
|
34
34
|
console.log(chalk.cyan('✦ Varsayılan ayarlar yükleniyor...'));
|
|
35
35
|
console.log(chalk.green(' ✓ Ayarlar hazır\n'));
|
|
36
36
|
|
|
37
|
+
// Mevcut config'i kontrol et
|
|
38
|
+
let existingConfig = {};
|
|
39
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
40
|
+
try {
|
|
41
|
+
const data = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
42
|
+
existingConfig = JSON.parse(data);
|
|
43
|
+
} catch {
|
|
44
|
+
existingConfig = {};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
37
48
|
// AI sağlayıcı seç
|
|
38
49
|
process.stdin.resume();
|
|
39
50
|
const { aiProvider } = await inquirer.prompt([
|
|
@@ -98,72 +109,136 @@ async function setup() {
|
|
|
98
109
|
]);
|
|
99
110
|
|
|
100
111
|
if (wantNaturecoKey) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return 'API key nc_ veya nco_ ile başlamalı';
|
|
112
|
-
}
|
|
113
|
-
return true;
|
|
112
|
+
// Kayıtlı NatureCo key varsa hatırlat
|
|
113
|
+
if (existingConfig.apiKey) {
|
|
114
|
+
const maskedKey = existingConfig.apiKey.slice(0, 6) + '...';
|
|
115
|
+
process.stdin.resume();
|
|
116
|
+
const { useExistingNcKey } = await inquirer.prompt([
|
|
117
|
+
{
|
|
118
|
+
type: 'confirm',
|
|
119
|
+
name: 'useExistingNcKey',
|
|
120
|
+
message: `Kayıtlı NatureCo API key bulundu: ${maskedKey}. Bunu kullanmak ister misiniz?`,
|
|
121
|
+
default: true,
|
|
114
122
|
},
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
123
|
+
]);
|
|
124
|
+
|
|
125
|
+
if (useExistingNcKey) {
|
|
126
|
+
naturecoApiKey = existingConfig.apiKey;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!naturecoApiKey) {
|
|
131
|
+
process.stdin.resume();
|
|
132
|
+
const { ncKey } = await inquirer.prompt([
|
|
133
|
+
{
|
|
134
|
+
type: 'input',
|
|
135
|
+
name: 'ncKey',
|
|
136
|
+
message: 'NatureCo API key:',
|
|
137
|
+
validate: (input) => {
|
|
138
|
+
const trimmed = input.trim();
|
|
139
|
+
if (trimmed.length === 0) return true; // Opsiyonel
|
|
140
|
+
if (!trimmed.startsWith('nc_') && !trimmed.startsWith('nco_')) {
|
|
141
|
+
return 'API key nc_ veya nco_ ile başlamalı';
|
|
142
|
+
}
|
|
143
|
+
return true;
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
]);
|
|
147
|
+
if (ncKey.trim().length > 0) {
|
|
148
|
+
naturecoApiKey = ncKey.trim();
|
|
149
|
+
}
|
|
119
150
|
}
|
|
120
151
|
}
|
|
121
152
|
} else {
|
|
122
|
-
// NatureCo seçildiyse
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
153
|
+
// NatureCo seçildiyse
|
|
154
|
+
// Kayıtlı API key varsa hatırlat
|
|
155
|
+
if (existingConfig.apiKey) {
|
|
156
|
+
const maskedKey = existingConfig.apiKey.slice(0, 6) + '...';
|
|
157
|
+
process.stdin.resume();
|
|
158
|
+
const { useExistingKey } = await inquirer.prompt([
|
|
159
|
+
{
|
|
160
|
+
type: 'confirm',
|
|
161
|
+
name: 'useExistingKey',
|
|
162
|
+
message: `Kayıtlı API key bulundu: ${maskedKey}. Bunu kullanmak ister misiniz?`,
|
|
163
|
+
default: true,
|
|
164
|
+
},
|
|
165
|
+
]);
|
|
166
|
+
|
|
167
|
+
if (useExistingKey) {
|
|
168
|
+
// Mevcut key'i doğrula
|
|
169
|
+
console.log(chalk.yellow('\n ⏳ API key doğrulanıyor...'));
|
|
170
|
+
try {
|
|
171
|
+
const response = await fetch('https://api.natureco.me/api/v1/bots', {
|
|
172
|
+
headers: {
|
|
173
|
+
'Authorization': `Bearer ${existingConfig.apiKey}`,
|
|
174
|
+
'Content-Type': 'application/json',
|
|
175
|
+
},
|
|
176
|
+
});
|
|
133
177
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
178
|
+
if (response.ok) {
|
|
179
|
+
const data = await response.json();
|
|
180
|
+
if (data.bots && data.bots.length > 0) {
|
|
181
|
+
console.log(chalk.green(' ✓ API key doğrulandı\n'));
|
|
182
|
+
naturecoApiKey = existingConfig.apiKey;
|
|
183
|
+
} else {
|
|
184
|
+
console.log(chalk.red(' ✗ Bu API key ile bot bulunamadı\n'));
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
console.log(chalk.red(' ✗ Geçersiz API key\n'));
|
|
137
188
|
}
|
|
189
|
+
} catch (err) {
|
|
190
|
+
console.log(chalk.red(` ✗ API hatası: ${err.message}\n`));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
138
194
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (!
|
|
149
|
-
return '
|
|
195
|
+
// Yeni key sor
|
|
196
|
+
if (!naturecoApiKey) {
|
|
197
|
+
process.stdin.resume();
|
|
198
|
+
const { apiKey } = await inquirer.prompt([
|
|
199
|
+
{
|
|
200
|
+
type: 'input',
|
|
201
|
+
name: 'apiKey',
|
|
202
|
+
message: 'NatureCo API key girin:',
|
|
203
|
+
validate: async (input) => {
|
|
204
|
+
if (!input || input.trim().length === 0) {
|
|
205
|
+
return 'API key gerekli';
|
|
150
206
|
}
|
|
151
207
|
|
|
152
|
-
const
|
|
153
|
-
if (!
|
|
154
|
-
return '
|
|
208
|
+
const trimmed = input.trim();
|
|
209
|
+
if (!trimmed.startsWith('nc_') && !trimmed.startsWith('nco_')) {
|
|
210
|
+
return 'API key nc_ veya nco_ ile başlamalı';
|
|
155
211
|
}
|
|
156
212
|
|
|
157
|
-
console.log(chalk.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
213
|
+
console.log(chalk.yellow('\n ⏳ API key doğrulanıyor...'));
|
|
214
|
+
try {
|
|
215
|
+
const response = await fetch('https://api.natureco.me/api/v1/bots', {
|
|
216
|
+
headers: {
|
|
217
|
+
'Authorization': `Bearer ${trimmed}`,
|
|
218
|
+
'Content-Type': 'application/json',
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
if (!response.ok) {
|
|
223
|
+
return 'Geçersiz API key';
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const data = await response.json();
|
|
227
|
+
if (!data.bots || data.bots.length === 0) {
|
|
228
|
+
return 'Bu API key ile bot bulunamadı';
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
console.log(chalk.green(' ✓ API key doğrulandı\n'));
|
|
232
|
+
return true;
|
|
233
|
+
} catch (err) {
|
|
234
|
+
return `API hatası: ${err.message}`;
|
|
235
|
+
}
|
|
236
|
+
},
|
|
162
237
|
},
|
|
163
|
-
|
|
164
|
-
]);
|
|
238
|
+
]);
|
|
165
239
|
|
|
166
|
-
|
|
240
|
+
naturecoApiKey = apiKey.trim();
|
|
241
|
+
}
|
|
167
242
|
}
|
|
168
243
|
|
|
169
244
|
// Bot seçimi (sadece NatureCo key varsa)
|
|
@@ -171,26 +246,127 @@ async function setup() {
|
|
|
171
246
|
let selectedBotId = null;
|
|
172
247
|
|
|
173
248
|
if (naturecoApiKey) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
249
|
+
// Kayıtlı bot varsa hatırlat
|
|
250
|
+
if (existingConfig.defaultBot && existingConfig.defaultBotId) {
|
|
251
|
+
process.stdin.resume();
|
|
252
|
+
const { useExistingBot } = await inquirer.prompt([
|
|
253
|
+
{
|
|
254
|
+
type: 'confirm',
|
|
255
|
+
name: 'useExistingBot',
|
|
256
|
+
message: `Kayıtlı bot bulundu: ${existingConfig.defaultBot}. Bunu kullanmak ister misiniz?`,
|
|
257
|
+
default: true,
|
|
258
|
+
},
|
|
259
|
+
]);
|
|
260
|
+
|
|
261
|
+
if (useExistingBot) {
|
|
262
|
+
selectedBot = { name: existingConfig.defaultBot };
|
|
263
|
+
selectedBotId = existingConfig.defaultBotId;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (!selectedBot) {
|
|
268
|
+
console.log(chalk.yellow('⏳ Botlar yükleniyor...\n'));
|
|
269
|
+
try {
|
|
270
|
+
const botList = await getBots(naturecoApiKey);
|
|
271
|
+
|
|
272
|
+
if (botList && botList.bots && botList.bots.length > 0) {
|
|
273
|
+
process.stdin.resume();
|
|
274
|
+
const { botId } = await inquirer.prompt([
|
|
275
|
+
{
|
|
276
|
+
type: 'list',
|
|
277
|
+
name: 'botId',
|
|
278
|
+
message: 'Varsayılan bot seçin:',
|
|
279
|
+
choices: botList.bots.map(b => ({ name: b.name, value: b.id })),
|
|
280
|
+
},
|
|
281
|
+
]);
|
|
282
|
+
|
|
283
|
+
selectedBotId = botId;
|
|
284
|
+
selectedBot = botList.bots.find(b => b.id === botId);
|
|
285
|
+
}
|
|
286
|
+
} catch (err) {
|
|
287
|
+
console.log(chalk.yellow(`⚠️ Bot listesi alınamadı: ${err.message}\n`));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Telegram entegrasyonu (NatureCo seçildiyse veya NatureCo key varsa)
|
|
293
|
+
let telegramToken = null;
|
|
294
|
+
let telegramUserId = null;
|
|
295
|
+
|
|
296
|
+
if (naturecoApiKey && selectedBotId) {
|
|
297
|
+
// Kayıtlı Telegram botu varsa hatırlat
|
|
298
|
+
if (existingConfig.telegramToken) {
|
|
299
|
+
process.stdin.resume();
|
|
300
|
+
const { useExistingTelegram } = await inquirer.prompt([
|
|
301
|
+
{
|
|
302
|
+
type: 'confirm',
|
|
303
|
+
name: 'useExistingTelegram',
|
|
304
|
+
message: 'Kayıtlı Telegram botu bulundu. Bunu kullanmak ister misiniz?',
|
|
305
|
+
default: true,
|
|
306
|
+
},
|
|
307
|
+
]);
|
|
308
|
+
|
|
309
|
+
if (useExistingTelegram) {
|
|
310
|
+
telegramToken = existingConfig.telegramToken;
|
|
311
|
+
telegramUserId = existingConfig.telegramUserId;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (!telegramToken) {
|
|
316
|
+
process.stdin.resume();
|
|
317
|
+
const { wantTelegram } = await inquirer.prompt([
|
|
318
|
+
{
|
|
319
|
+
type: 'confirm',
|
|
320
|
+
name: 'wantTelegram',
|
|
321
|
+
message: 'Telegram entegrasyonu eklemek ister misiniz?',
|
|
322
|
+
default: false,
|
|
323
|
+
},
|
|
324
|
+
]);
|
|
325
|
+
|
|
326
|
+
if (wantTelegram) {
|
|
179
327
|
process.stdin.resume();
|
|
180
|
-
const
|
|
328
|
+
const telegramAnswers = await inquirer.prompt([
|
|
329
|
+
{
|
|
330
|
+
type: 'input',
|
|
331
|
+
name: 'token',
|
|
332
|
+
message: 'Telegram bot token:',
|
|
333
|
+
validate: (val) => val.trim() !== '' || 'Token boş olamaz',
|
|
334
|
+
},
|
|
181
335
|
{
|
|
182
|
-
type: '
|
|
183
|
-
name: '
|
|
184
|
-
message: '
|
|
185
|
-
|
|
336
|
+
type: 'input',
|
|
337
|
+
name: 'userId',
|
|
338
|
+
message: 'Telegram kullanıcı ID\'niz (t.me/userinfobot ile öğrenebilirsiniz):',
|
|
339
|
+
validate: (val) => val.trim() !== '' || 'Kullanıcı ID boş olamaz',
|
|
186
340
|
},
|
|
187
341
|
]);
|
|
188
342
|
|
|
189
|
-
|
|
190
|
-
|
|
343
|
+
telegramToken = telegramAnswers.token.trim();
|
|
344
|
+
telegramUserId = telegramAnswers.userId.trim();
|
|
345
|
+
|
|
346
|
+
// Telegram'ı bağla
|
|
347
|
+
try {
|
|
348
|
+
const response = await fetch('https://api.natureco.me/api/agent/telegram/connect', {
|
|
349
|
+
method: 'POST',
|
|
350
|
+
headers: {
|
|
351
|
+
'Content-Type': 'application/json',
|
|
352
|
+
'Authorization': `Bearer ${naturecoApiKey}`,
|
|
353
|
+
},
|
|
354
|
+
body: JSON.stringify({
|
|
355
|
+
agent_id: selectedBotId,
|
|
356
|
+
telegram_bot_token: telegramToken,
|
|
357
|
+
telegram_user_id: telegramUserId,
|
|
358
|
+
}),
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
if (response.ok) {
|
|
362
|
+
console.log(chalk.green('\n✅ Telegram bağlantısı başarılı!\n'));
|
|
363
|
+
} else {
|
|
364
|
+
console.log(chalk.yellow('\n⚠️ Telegram bağlantısı kurulamadı\n'));
|
|
365
|
+
}
|
|
366
|
+
} catch (err) {
|
|
367
|
+
console.log(chalk.yellow(`\n⚠️ Telegram bağlantı hatası: ${err.message}\n`));
|
|
368
|
+
}
|
|
191
369
|
}
|
|
192
|
-
} catch (err) {
|
|
193
|
-
console.log(chalk.yellow(`⚠️ Bot listesi alınamadı: ${err.message}\n`));
|
|
194
370
|
}
|
|
195
371
|
}
|
|
196
372
|
|
|
@@ -216,6 +392,11 @@ async function setup() {
|
|
|
216
392
|
config.defaultBotId = selectedBotId;
|
|
217
393
|
}
|
|
218
394
|
|
|
395
|
+
if (telegramToken) {
|
|
396
|
+
config.telegramToken = telegramToken;
|
|
397
|
+
config.telegramUserId = telegramUserId;
|
|
398
|
+
}
|
|
399
|
+
|
|
219
400
|
saveConfig(config);
|
|
220
401
|
|
|
221
402
|
// Kurulum tamamlandı
|
|
@@ -228,6 +409,10 @@ async function setup() {
|
|
|
228
409
|
if (selectedBot) {
|
|
229
410
|
console.log(chalk.cyan('Varsayılan Bot:'), chalk.white(selectedBot.name));
|
|
230
411
|
}
|
|
412
|
+
|
|
413
|
+
if (telegramToken) {
|
|
414
|
+
console.log(chalk.cyan('Telegram:'), chalk.green('✓ Bağlı'));
|
|
415
|
+
}
|
|
231
416
|
|
|
232
417
|
console.log(chalk.cyan('Config:'), chalk.white(CONFIG_FILE));
|
|
233
418
|
console.log('');
|
package/src/commands/skills.js
CHANGED
|
@@ -170,9 +170,8 @@ async function createSkillCommand(name) {
|
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
async function searchSkillsCommand(query) {
|
|
173
|
-
const popularSkills = getPopularSkills();
|
|
174
|
-
|
|
175
173
|
if (!query || query.trim().length === 0) {
|
|
174
|
+
const popularSkills = getPopularSkills();
|
|
176
175
|
console.log(chalk.yellow('\nPopüler Skill\'ler:\n'));
|
|
177
176
|
popularSkills.forEach(skill => {
|
|
178
177
|
console.log(chalk.cyan(` ${skill.name.padEnd(15)}`), chalk.gray(skill.description));
|
|
@@ -185,24 +184,54 @@ async function searchSkillsCommand(query) {
|
|
|
185
184
|
return;
|
|
186
185
|
}
|
|
187
186
|
|
|
188
|
-
|
|
189
|
-
const results = popularSkills.filter(skill =>
|
|
190
|
-
skill.name.toLowerCase().includes(query.toLowerCase()) ||
|
|
191
|
-
skill.description.toLowerCase().includes(query.toLowerCase()) ||
|
|
192
|
-
skill.slug.toLowerCase().includes(query.toLowerCase())
|
|
193
|
-
);
|
|
187
|
+
console.log(chalk.yellow(`\n⏳ "${query}" aranıyor...\n`));
|
|
194
188
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
189
|
+
try {
|
|
190
|
+
// ClawHub search API
|
|
191
|
+
const searchUrl = `https://clawhub.ai/api/skills?q=${encodeURIComponent(query)}&limit=10`;
|
|
192
|
+
const response = await fetch(searchUrl);
|
|
193
|
+
|
|
194
|
+
if (!response.ok) {
|
|
195
|
+
throw new Error('ClawHub API\'ye erişilemedi');
|
|
196
|
+
}
|
|
199
197
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
198
|
+
const data = await response.json();
|
|
199
|
+
const results = data.skills || [];
|
|
200
|
+
|
|
201
|
+
if (results.length === 0) {
|
|
202
|
+
console.log(chalk.yellow(`"${query}" için sonuç bulunamadı.\n`));
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
console.log(chalk.yellow(`"${query}" için ${results.length} sonuç:\n`));
|
|
207
|
+
results.forEach(skill => {
|
|
208
|
+
console.log(chalk.cyan(` ${skill.name.padEnd(15)}`), chalk.gray(skill.description || 'Açıklama yok'));
|
|
209
|
+
console.log(chalk.gray(` Kurmak için: natureco skills install clawhub:${skill.slug}`));
|
|
210
|
+
});
|
|
211
|
+
console.log('');
|
|
212
|
+
} catch (err) {
|
|
213
|
+
// Fallback to local popular skills search
|
|
214
|
+
console.log(chalk.gray('ClawHub\'a bağlanılamadı, yerel aramada...\n'));
|
|
215
|
+
|
|
216
|
+
const popularSkills = getPopularSkills();
|
|
217
|
+
const results = popularSkills.filter(skill =>
|
|
218
|
+
skill.name.toLowerCase().includes(query.toLowerCase()) ||
|
|
219
|
+
skill.description.toLowerCase().includes(query.toLowerCase()) ||
|
|
220
|
+
skill.slug.toLowerCase().includes(query.toLowerCase())
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
if (results.length === 0) {
|
|
224
|
+
console.log(chalk.yellow(`"${query}" için sonuç bulunamadı.\n`));
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
console.log(chalk.yellow(`"${query}" için ${results.length} sonuç:\n`));
|
|
229
|
+
results.forEach(skill => {
|
|
230
|
+
console.log(chalk.cyan(` ${skill.name.padEnd(15)}`), chalk.gray(skill.description));
|
|
231
|
+
console.log(chalk.gray(` Kurmak için: natureco skills install ${skill.slug}`));
|
|
232
|
+
});
|
|
233
|
+
console.log('');
|
|
234
|
+
}
|
|
206
235
|
}
|
|
207
236
|
|
|
208
237
|
async function browseSkillsCommand() {
|
package/src/utils/skills.js
CHANGED
|
@@ -152,7 +152,7 @@ async function installSkill(slug) {
|
|
|
152
152
|
// ClawHub format: clawhub:github
|
|
153
153
|
if (slug.startsWith('clawhub:')) {
|
|
154
154
|
actualSlug = slug.replace('clawhub:', '');
|
|
155
|
-
url = `https://clawhub.ai/skills/${actualSlug}/SKILL.md`;
|
|
155
|
+
url = `https://clawhub.ai/api/v1/skills/${actualSlug}/file?path=SKILL.md`;
|
|
156
156
|
}
|
|
157
157
|
// Direct URL
|
|
158
158
|
else if (slug.startsWith('http://') || slug.startsWith('https://')) {
|
|
@@ -168,6 +168,7 @@ async function installSkill(slug) {
|
|
|
168
168
|
|
|
169
169
|
try {
|
|
170
170
|
const response = await fetch(url);
|
|
171
|
+
|
|
171
172
|
if (!response.ok) {
|
|
172
173
|
throw new Error(`Skill bulunamadı: ${actualSlug}`);
|
|
173
174
|
}
|