natureco-cli 1.0.0
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/CHANGELOG.md +192 -0
- package/README.md +369 -0
- package/bin/natureco.js +109 -0
- package/package.json +33 -0
- package/skills/code-review/SKILL.md +48 -0
- package/skills/summarize/SKILL.md +46 -0
- package/skills/translate/SKILL.md +47 -0
- package/src/commands/ask.js +50 -0
- package/src/commands/bots.js +41 -0
- package/src/commands/chat.js +226 -0
- package/src/commands/config.js +68 -0
- package/src/commands/gateway.js +84 -0
- package/src/commands/help.js +55 -0
- package/src/commands/init.js +135 -0
- package/src/commands/login.js +45 -0
- package/src/commands/logout.js +13 -0
- package/src/commands/mcp.js +275 -0
- package/src/commands/run.js +69 -0
- package/src/commands/setup.js +222 -0
- package/src/commands/skills.js +161 -0
- package/src/commands/update.js +61 -0
- package/src/utils/agents.js +28 -0
- package/src/utils/api.js +64 -0
- package/src/utils/config.js +81 -0
- package/src/utils/history.js +87 -0
- package/src/utils/mcp.js +188 -0
- package/src/utils/skills.js +285 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const boxen = require('boxen');
|
|
3
|
+
const inquirer = require('inquirer');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const { saveConfig, CONFIG_DIR, CONFIG_FILE } = require('../utils/config');
|
|
6
|
+
const { getBots } = require('../utils/api');
|
|
7
|
+
|
|
8
|
+
async function setup() {
|
|
9
|
+
// Kurulum ekranı
|
|
10
|
+
const welcomeBox = boxen(
|
|
11
|
+
chalk.green.bold('🌿 NatureCo Terminal\n') +
|
|
12
|
+
chalk.green.bold(' İlk Kurulum\n'),
|
|
13
|
+
{
|
|
14
|
+
padding: 1,
|
|
15
|
+
margin: 1,
|
|
16
|
+
borderStyle: 'round',
|
|
17
|
+
borderColor: 'green',
|
|
18
|
+
align: 'center',
|
|
19
|
+
}
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
console.clear();
|
|
23
|
+
console.log(welcomeBox);
|
|
24
|
+
console.log(chalk.yellow('Hoş geldiniz! NatureCo CLI\'yi ilk kez'));
|
|
25
|
+
console.log(chalk.yellow('kullanıyorsunuz.\n'));
|
|
26
|
+
|
|
27
|
+
// Klasör oluştur
|
|
28
|
+
console.log(chalk.cyan('✦ ~/.natureco/ klasörü oluşturuluyor...'));
|
|
29
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
30
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
console.log(chalk.green(' ✓ Klasör oluşturuldu\n'));
|
|
33
|
+
|
|
34
|
+
console.log(chalk.cyan('✦ Varsayılan ayarlar yükleniyor...'));
|
|
35
|
+
console.log(chalk.green(' ✓ Ayarlar hazır\n'));
|
|
36
|
+
|
|
37
|
+
// API key sor
|
|
38
|
+
process.stdin.resume();
|
|
39
|
+
const { apiKey } = await inquirer.prompt([
|
|
40
|
+
{
|
|
41
|
+
type: 'input',
|
|
42
|
+
name: 'apiKey',
|
|
43
|
+
message: 'API key girin:',
|
|
44
|
+
validate: async (input) => {
|
|
45
|
+
if (!input || input.trim().length === 0) {
|
|
46
|
+
return 'API key gerekli';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const trimmed = input.trim();
|
|
50
|
+
if (!trimmed.startsWith('nc_') && !trimmed.startsWith('nco_')) {
|
|
51
|
+
return 'API key nc_ veya nco_ ile başlamalı';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// API key'i validate et
|
|
55
|
+
console.log(chalk.yellow('\n ⏳ API key doğrulanıyor...'));
|
|
56
|
+
try {
|
|
57
|
+
const response = await fetch('https://api.natureco.me/api/v1/bots', {
|
|
58
|
+
headers: {
|
|
59
|
+
'Authorization': `Bearer ${trimmed}`,
|
|
60
|
+
'Content-Type': 'application/json',
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
return 'Geçersiz API key';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const data = await response.json();
|
|
69
|
+
if (!data.bots || data.bots.length === 0) {
|
|
70
|
+
return 'Bu API key ile bot bulunamadı';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log(chalk.green(' ✓ API key doğrulandı\n'));
|
|
74
|
+
return true;
|
|
75
|
+
} catch (err) {
|
|
76
|
+
return `API hatası: ${err.message}`;
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
]);
|
|
81
|
+
|
|
82
|
+
const trimmedApiKey = apiKey.trim();
|
|
83
|
+
|
|
84
|
+
// Botları çek
|
|
85
|
+
console.log(chalk.yellow('⏳ Botlar yükleniyor...\n'));
|
|
86
|
+
let botList;
|
|
87
|
+
try {
|
|
88
|
+
botList = await getBots(trimmedApiKey);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
console.log(chalk.red(`\n❌ Hata: ${err.message}\n`));
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!botList || !botList.bots || botList.bots.length === 0) {
|
|
95
|
+
console.log(chalk.red('❌ Bot bulunamadı.\n'));
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Bot seç
|
|
100
|
+
process.stdin.resume();
|
|
101
|
+
const { selectedBotId } = await inquirer.prompt([
|
|
102
|
+
{
|
|
103
|
+
type: 'list',
|
|
104
|
+
name: 'selectedBotId',
|
|
105
|
+
message: 'Varsayılan bot seçin:',
|
|
106
|
+
choices: botList.bots.map(b => ({
|
|
107
|
+
name: b.name,
|
|
108
|
+
value: b.id,
|
|
109
|
+
})),
|
|
110
|
+
},
|
|
111
|
+
]);
|
|
112
|
+
|
|
113
|
+
const selectedBot = botList.bots.find(b => b.id === selectedBotId);
|
|
114
|
+
|
|
115
|
+
// Telegram bağlantısı
|
|
116
|
+
process.stdin.resume();
|
|
117
|
+
const { connectTelegram } = await inquirer.prompt([
|
|
118
|
+
{
|
|
119
|
+
type: 'confirm',
|
|
120
|
+
name: 'connectTelegram',
|
|
121
|
+
message: 'Telegram bağlamak ister misiniz?',
|
|
122
|
+
default: false,
|
|
123
|
+
},
|
|
124
|
+
]);
|
|
125
|
+
|
|
126
|
+
let telegramConnected = false;
|
|
127
|
+
let telegramSkipped = false;
|
|
128
|
+
|
|
129
|
+
if (connectTelegram) {
|
|
130
|
+
process.stdin.resume();
|
|
131
|
+
const { telegramToken } = await inquirer.prompt([
|
|
132
|
+
{
|
|
133
|
+
type: 'input',
|
|
134
|
+
name: 'telegramToken',
|
|
135
|
+
message: 'Telegram Bot Token girin (BotFather\'dan alınır):',
|
|
136
|
+
validate: (input) => {
|
|
137
|
+
if (!input || input.trim().length === 0) {
|
|
138
|
+
return 'Token gerekli';
|
|
139
|
+
}
|
|
140
|
+
return true;
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
]);
|
|
144
|
+
|
|
145
|
+
process.stdin.resume();
|
|
146
|
+
const { telegramUserId } = await inquirer.prompt([
|
|
147
|
+
{
|
|
148
|
+
type: 'input',
|
|
149
|
+
name: 'telegramUserId',
|
|
150
|
+
message: 'Telegram kullanıcı ID\'niz nedir? (t.me/userinfobot ile öğrenebilirsiniz):',
|
|
151
|
+
validate: (val) => val.trim() !== '' || 'Kullanıcı ID boş olamaz',
|
|
152
|
+
},
|
|
153
|
+
]);
|
|
154
|
+
|
|
155
|
+
console.log(chalk.yellow('\n⏳ Telegram bağlanıyor...\n'));
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
const response = await fetch('https://api.natureco.me/api/agent/telegram/connect', {
|
|
159
|
+
method: 'POST',
|
|
160
|
+
headers: {
|
|
161
|
+
'Authorization': `Bearer ${trimmedApiKey}`,
|
|
162
|
+
'Content-Type': 'application/json',
|
|
163
|
+
},
|
|
164
|
+
body: JSON.stringify({
|
|
165
|
+
agent_id: selectedBotId,
|
|
166
|
+
telegram_bot_token: telegramToken.trim(),
|
|
167
|
+
telegram_user_id: telegramUserId.trim(),
|
|
168
|
+
}),
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
if (response.ok) {
|
|
172
|
+
console.log(chalk.green('✅ Telegram bağlandı\n'));
|
|
173
|
+
telegramConnected = true;
|
|
174
|
+
|
|
175
|
+
// Config'e telegramUserId ekle
|
|
176
|
+
config.telegramUserId = telegramUserId.trim();
|
|
177
|
+
} else {
|
|
178
|
+
const errorText = await response.text();
|
|
179
|
+
console.log(chalk.red(`❌ Telegram bağlanamadı: ${errorText}\n`));
|
|
180
|
+
}
|
|
181
|
+
} catch (err) {
|
|
182
|
+
console.log(chalk.red(`❌ Telegram bağlanamadı: ${err.message}\n`));
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
telegramSkipped = true;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Config kaydet
|
|
189
|
+
const config = {
|
|
190
|
+
apiKey: trimmedApiKey,
|
|
191
|
+
defaultBot: selectedBot.name,
|
|
192
|
+
defaultBotId: selectedBot.id,
|
|
193
|
+
skills: {
|
|
194
|
+
enabled: true,
|
|
195
|
+
list: [],
|
|
196
|
+
},
|
|
197
|
+
mcpServers: {},
|
|
198
|
+
setupCompleted: true,
|
|
199
|
+
setupDate: new Date().toISOString(),
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
saveConfig(config);
|
|
203
|
+
|
|
204
|
+
// Kurulum tamamlandı
|
|
205
|
+
console.log(chalk.green.bold('✅ Kurulum tamamlandı!\n'));
|
|
206
|
+
console.log(chalk.cyan('Aktif bot:'), chalk.white(selectedBot.name));
|
|
207
|
+
|
|
208
|
+
if (telegramConnected) {
|
|
209
|
+
console.log(chalk.cyan('Telegram:'), chalk.green('✅ Bağlı'));
|
|
210
|
+
} else if (telegramSkipped) {
|
|
211
|
+
console.log(chalk.cyan('Telegram:'), chalk.gray('⏭ Atlandı'));
|
|
212
|
+
} else {
|
|
213
|
+
console.log(chalk.cyan('Telegram:'), chalk.red('❌ Bağlanamadı'));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
console.log(chalk.cyan('Config:'), chalk.white(CONFIG_FILE));
|
|
217
|
+
console.log('');
|
|
218
|
+
console.log(chalk.yellow('Başlamak için:'), chalk.cyan('natureco chat'));
|
|
219
|
+
console.log('');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
module.exports = setup;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const inquirer = require('inquirer');
|
|
3
|
+
const { getSkills, installSkill, removeSkill, updateAllSkills, createSkillTemplate } = require('../utils/skills');
|
|
4
|
+
|
|
5
|
+
async function skills(args) {
|
|
6
|
+
const [action, ...params] = args;
|
|
7
|
+
|
|
8
|
+
if (!action || action === 'list') {
|
|
9
|
+
await listSkills();
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (action === 'install') {
|
|
14
|
+
const slug = params[0];
|
|
15
|
+
if (!slug) {
|
|
16
|
+
console.log(chalk.red('\n❌ Kullanım: natureco skills install <slug>\n'));
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
await installSkillCommand(slug);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (action === 'remove') {
|
|
24
|
+
const slug = params[0];
|
|
25
|
+
if (!slug) {
|
|
26
|
+
console.log(chalk.red('\n❌ Kullanım: natureco skills remove <slug>\n'));
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
await removeSkillCommand(slug);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (action === 'update') {
|
|
34
|
+
const flag = params[0];
|
|
35
|
+
if (flag === '--all') {
|
|
36
|
+
await updateAllSkillsCommand();
|
|
37
|
+
} else {
|
|
38
|
+
console.log(chalk.red('\n❌ Kullanım: natureco skills update --all\n'));
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (action === 'create') {
|
|
45
|
+
const name = params[0];
|
|
46
|
+
if (!name) {
|
|
47
|
+
console.log(chalk.red('\n❌ Kullanım: natureco skills create <ad>\n'));
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
await createSkillCommand(name);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
console.log(chalk.red(`\n❌ Geçersiz action: ${action}\n`));
|
|
55
|
+
console.log(chalk.gray('Kullanım: natureco skills [list|install|remove|update|create]\n'));
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function listSkills() {
|
|
60
|
+
console.log(chalk.green.bold('\n╭─ Yüklü Skill\'ler ─╮\n'));
|
|
61
|
+
|
|
62
|
+
const allSkills = getSkills();
|
|
63
|
+
|
|
64
|
+
if (allSkills.length === 0) {
|
|
65
|
+
console.log(chalk.gray('Hiç skill yüklü değil.\n'));
|
|
66
|
+
console.log(chalk.yellow('Skill yüklemek için:'), chalk.white('natureco skills install <slug>\n'));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
allSkills.forEach((skill, index) => {
|
|
71
|
+
const sourceLabel = skill.source === 'builtin' ? chalk.blue('[Yerleşik]') :
|
|
72
|
+
skill.source === 'user' ? chalk.cyan('[Kişisel]') :
|
|
73
|
+
chalk.magenta('[Proje]');
|
|
74
|
+
|
|
75
|
+
console.log(chalk.white(`${index + 1}. ${skill.name}`) + ' ' + sourceLabel);
|
|
76
|
+
console.log(chalk.gray(` ${skill.description}`));
|
|
77
|
+
|
|
78
|
+
if (skill.metadata?.requires?.bins) {
|
|
79
|
+
console.log(chalk.gray(` Gerekli: ${skill.metadata.requires.bins.join(', ')}`));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (skill.metadata?.os) {
|
|
83
|
+
console.log(chalk.gray(` Platform: ${skill.metadata.os.join(', ')}`));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log('');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
console.log(chalk.green('╰────────────────────╯\n'));
|
|
90
|
+
console.log(chalk.gray(`Toplam: ${allSkills.length} skill\n`));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function installSkillCommand(slug) {
|
|
94
|
+
console.log(chalk.yellow(`\n⏳ "${slug}" skill'i yükleniyor...\n`));
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
await installSkill(slug);
|
|
98
|
+
console.log(chalk.green(`✅ "${slug}" başarıyla yüklendi!\n`));
|
|
99
|
+
} catch (err) {
|
|
100
|
+
console.log(chalk.red(`\n❌ Hata: ${err.message}\n`));
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function removeSkillCommand(slug) {
|
|
106
|
+
const { confirm } = await inquirer.prompt([
|
|
107
|
+
{
|
|
108
|
+
type: 'confirm',
|
|
109
|
+
name: 'confirm',
|
|
110
|
+
message: `"${slug}" skill'ini silmek istediğinizden emin misiniz?`,
|
|
111
|
+
default: false,
|
|
112
|
+
},
|
|
113
|
+
]);
|
|
114
|
+
|
|
115
|
+
if (!confirm) {
|
|
116
|
+
console.log(chalk.gray('\nİptal edildi.\n'));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
removeSkill(slug);
|
|
122
|
+
console.log(chalk.green(`\n✅ "${slug}" silindi.\n`));
|
|
123
|
+
} catch (err) {
|
|
124
|
+
console.log(chalk.red(`\n❌ Hata: ${err.message}\n`));
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function updateAllSkillsCommand() {
|
|
130
|
+
console.log(chalk.yellow('\n⏳ Tüm skill\'ler güncelleniyor...\n'));
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const updated = await updateAllSkills();
|
|
134
|
+
if (updated.length === 0) {
|
|
135
|
+
console.log(chalk.gray('Güncellenecek skill bulunamadı.\n'));
|
|
136
|
+
} else {
|
|
137
|
+
console.log(chalk.green(`✅ ${updated.length} skill güncellendi:\n`));
|
|
138
|
+
updated.forEach(s => console.log(chalk.cyan(` - ${s}`)));
|
|
139
|
+
console.log('');
|
|
140
|
+
}
|
|
141
|
+
} catch (err) {
|
|
142
|
+
console.log(chalk.red(`\n❌ Hata: ${err.message}\n`));
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function createSkillCommand(name) {
|
|
148
|
+
console.log(chalk.yellow(`\n⏳ "${name}" skill şablonu oluşturuluyor...\n`));
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
const skillPath = createSkillTemplate(name);
|
|
152
|
+
console.log(chalk.green(`✅ Skill şablonu oluşturuldu:\n`));
|
|
153
|
+
console.log(chalk.cyan(` ${skillPath}\n`));
|
|
154
|
+
console.log(chalk.gray('SKILL.md dosyasını düzenleyerek skill\'i özelleştirin.\n'));
|
|
155
|
+
} catch (err) {
|
|
156
|
+
console.log(chalk.red(`\n❌ Hata: ${err.message}\n`));
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
module.exports = skills;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const { execSync } = require('child_process');
|
|
3
|
+
const packageJson = require('../../package.json');
|
|
4
|
+
|
|
5
|
+
async function update() {
|
|
6
|
+
const currentVersion = packageJson.version;
|
|
7
|
+
|
|
8
|
+
console.log(chalk.yellow('\n⏳ Güncelleme kontrol ediliyor...\n'));
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
// npm'den en son versiyonu al
|
|
12
|
+
const latestVersion = execSync('npm view natureco-cli version', {
|
|
13
|
+
encoding: 'utf8',
|
|
14
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
15
|
+
}).trim();
|
|
16
|
+
|
|
17
|
+
console.log(chalk.cyan('Mevcut versiyon:'), chalk.white(currentVersion));
|
|
18
|
+
console.log(chalk.cyan('En son versiyon:'), chalk.white(latestVersion));
|
|
19
|
+
console.log('');
|
|
20
|
+
|
|
21
|
+
if (currentVersion === latestVersion) {
|
|
22
|
+
console.log(chalk.green('✅ NatureCo CLI güncel!\n'));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Versiyon karşılaştırması
|
|
27
|
+
const isNewer = compareVersions(latestVersion, currentVersion) > 0;
|
|
28
|
+
|
|
29
|
+
if (isNewer) {
|
|
30
|
+
console.log(chalk.yellow('🔔 Yeni versiyon mevcut!\n'));
|
|
31
|
+
console.log(chalk.gray('Güncellemek için:\n'));
|
|
32
|
+
console.log(chalk.cyan(' npm install -g natureco-cli@latest\n'));
|
|
33
|
+
console.log(chalk.gray('veya\n'));
|
|
34
|
+
console.log(chalk.cyan(' npm update -g natureco-cli\n'));
|
|
35
|
+
} else {
|
|
36
|
+
console.log(chalk.green('✅ NatureCo CLI güncel!\n'));
|
|
37
|
+
}
|
|
38
|
+
} catch (err) {
|
|
39
|
+
// npm view başarısız olursa (paket henüz yayınlanmamış)
|
|
40
|
+
console.log(chalk.gray('Güncelleme kontrolü yapılamadı.\n'));
|
|
41
|
+
console.log(chalk.gray('Paket henüz npm\'de yayınlanmamış olabilir.\n'));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Versiyon karşılaştırma (semver)
|
|
46
|
+
function compareVersions(v1, v2) {
|
|
47
|
+
const parts1 = v1.split('.').map(Number);
|
|
48
|
+
const parts2 = v2.split('.').map(Number);
|
|
49
|
+
|
|
50
|
+
for (let i = 0; i < 3; i++) {
|
|
51
|
+
const p1 = parts1[i] || 0;
|
|
52
|
+
const p2 = parts2[i] || 0;
|
|
53
|
+
|
|
54
|
+
if (p1 > p2) return 1;
|
|
55
|
+
if (p1 < p2) return -1;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = update;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const AGENTS_FILE = path.join(process.cwd(), '.natureco', 'AGENTS.md');
|
|
5
|
+
|
|
6
|
+
// Read AGENTS.md content
|
|
7
|
+
function getAgentsPrompt() {
|
|
8
|
+
if (!fs.existsSync(AGENTS_FILE)) {
|
|
9
|
+
return '';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const content = fs.readFileSync(AGENTS_FILE, 'utf8');
|
|
14
|
+
return content.trim();
|
|
15
|
+
} catch {
|
|
16
|
+
return '';
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Check if AGENTS.md exists
|
|
21
|
+
function hasAgentsFile() {
|
|
22
|
+
return fs.existsSync(AGENTS_FILE);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = {
|
|
26
|
+
getAgentsPrompt,
|
|
27
|
+
hasAgentsFile,
|
|
28
|
+
};
|
package/src/utils/api.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const API_BASE = 'https://api.natureco.me';
|
|
2
|
+
|
|
3
|
+
async function request(endpoint, options = {}) {
|
|
4
|
+
const url = `${API_BASE}${endpoint}`;
|
|
5
|
+
const response = await fetch(url, {
|
|
6
|
+
...options,
|
|
7
|
+
headers: {
|
|
8
|
+
'Content-Type': 'application/json',
|
|
9
|
+
...options.headers,
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
if (!response.ok) {
|
|
14
|
+
const text = await response.text();
|
|
15
|
+
throw new Error(`API Error: ${response.status} - ${text}`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return response.json();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function getBots(apiKey) {
|
|
22
|
+
return request('/api/v1/bots', {
|
|
23
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function sendMessage(apiKey, botId, message, conversationId = null, skillPrompts = '') {
|
|
28
|
+
const body = {
|
|
29
|
+
agent_id: botId,
|
|
30
|
+
message,
|
|
31
|
+
conversation_id: conversationId,
|
|
32
|
+
platform: 'cli',
|
|
33
|
+
user_id: 'cli-user'
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// Skill prompts varsa system_prompt olarak ekle
|
|
37
|
+
if (skillPrompts && skillPrompts.trim().length > 0) {
|
|
38
|
+
body.system_prompt = skillPrompts;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return request('/api/agent/chat', {
|
|
42
|
+
method: 'POST',
|
|
43
|
+
headers: {
|
|
44
|
+
Authorization: `Bearer ${apiKey}`,
|
|
45
|
+
'X-User-ID': 'cli-user'
|
|
46
|
+
},
|
|
47
|
+
body: JSON.stringify(body),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function validateApiKey(apiKey) {
|
|
52
|
+
try {
|
|
53
|
+
const result = await getBots(apiKey);
|
|
54
|
+
return true;
|
|
55
|
+
} catch (err) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = {
|
|
61
|
+
getBots,
|
|
62
|
+
sendMessage,
|
|
63
|
+
validateApiKey,
|
|
64
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
|
|
5
|
+
const CONFIG_DIR = path.join(os.homedir(), '.natureco');
|
|
6
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
7
|
+
|
|
8
|
+
function ensureConfigDir() {
|
|
9
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
10
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function saveConfig(data) {
|
|
15
|
+
ensureConfigDir();
|
|
16
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(data, null, 2), 'utf8');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function loadConfig() {
|
|
20
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const content = fs.readFileSync(CONFIG_FILE, 'utf8');
|
|
25
|
+
return JSON.parse(content);
|
|
26
|
+
} catch (err) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function deleteConfig() {
|
|
32
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
33
|
+
fs.unlinkSync(CONFIG_FILE);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getApiKey() {
|
|
38
|
+
const config = loadConfig();
|
|
39
|
+
return config?.apiKey || null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function saveApiKey(apiKey) {
|
|
43
|
+
const config = loadConfig() || {};
|
|
44
|
+
config.apiKey = apiKey;
|
|
45
|
+
saveConfig(config);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function getConfig() {
|
|
49
|
+
return loadConfig() || {};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getAllConfig() {
|
|
53
|
+
return loadConfig() || {};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function setConfigValue(key, value) {
|
|
57
|
+
const config = loadConfig() || {};
|
|
58
|
+
const keys = key.split('.');
|
|
59
|
+
let current = config;
|
|
60
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
61
|
+
if (!current[keys[i]]) {
|
|
62
|
+
current[keys[i]] = {};
|
|
63
|
+
}
|
|
64
|
+
current = current[keys[i]];
|
|
65
|
+
}
|
|
66
|
+
current[keys[keys.length - 1]] = value;
|
|
67
|
+
saveConfig(config);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = {
|
|
71
|
+
saveConfig,
|
|
72
|
+
loadConfig,
|
|
73
|
+
deleteConfig,
|
|
74
|
+
getApiKey,
|
|
75
|
+
saveApiKey,
|
|
76
|
+
getConfig,
|
|
77
|
+
getAllConfig,
|
|
78
|
+
setConfigValue,
|
|
79
|
+
CONFIG_FILE,
|
|
80
|
+
CONFIG_DIR,
|
|
81
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { CONFIG_DIR } = require('./config');
|
|
4
|
+
|
|
5
|
+
const HISTORY_DIR = path.join(CONFIG_DIR, 'history');
|
|
6
|
+
|
|
7
|
+
// Ensure history directory exists
|
|
8
|
+
function ensureHistoryDir() {
|
|
9
|
+
if (!fs.existsSync(HISTORY_DIR)) {
|
|
10
|
+
fs.mkdirSync(HISTORY_DIR, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Get history file path for a bot
|
|
15
|
+
function getHistoryFilePath(botId) {
|
|
16
|
+
ensureHistoryDir();
|
|
17
|
+
return path.join(HISTORY_DIR, `${botId}.json`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Load conversation history for a bot
|
|
21
|
+
function loadHistory(botId) {
|
|
22
|
+
const filePath = getHistoryFilePath(botId);
|
|
23
|
+
|
|
24
|
+
if (!fs.existsSync(filePath)) {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
30
|
+
return JSON.parse(content);
|
|
31
|
+
} catch {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Save conversation history for a bot
|
|
37
|
+
function saveHistory(botId, history) {
|
|
38
|
+
const filePath = getHistoryFilePath(botId);
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
fs.writeFileSync(filePath, JSON.stringify(history, null, 2), 'utf8');
|
|
42
|
+
} catch (err) {
|
|
43
|
+
// Silently fail - history is not critical
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Add message to history
|
|
48
|
+
function addToHistory(botId, userMessage, botReply, conversationId = null) {
|
|
49
|
+
const history = loadHistory(botId);
|
|
50
|
+
|
|
51
|
+
history.push({
|
|
52
|
+
timestamp: new Date().toISOString(),
|
|
53
|
+
user: userMessage,
|
|
54
|
+
bot: botReply,
|
|
55
|
+
conversationId,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Keep only last 100 messages
|
|
59
|
+
if (history.length > 100) {
|
|
60
|
+
history.shift();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
saveHistory(botId, history);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Get command history (only user messages)
|
|
67
|
+
function getCommandHistory(botId) {
|
|
68
|
+
const history = loadHistory(botId);
|
|
69
|
+
return history.map(h => h.user);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Clear history for a bot
|
|
73
|
+
function clearHistory(botId) {
|
|
74
|
+
const filePath = getHistoryFilePath(botId);
|
|
75
|
+
|
|
76
|
+
if (fs.existsSync(filePath)) {
|
|
77
|
+
fs.unlinkSync(filePath);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports = {
|
|
82
|
+
loadHistory,
|
|
83
|
+
saveHistory,
|
|
84
|
+
addToHistory,
|
|
85
|
+
getCommandHistory,
|
|
86
|
+
clearHistory,
|
|
87
|
+
};
|