natureco-cli 4.9.1 → 5.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.
@@ -1,414 +1,497 @@
1
- const chalk = require('chalk');
2
- const tui = require('../utils/tui');
3
- const path = require('path');
4
- const fs = require('fs');
5
- const os = require('os');
6
- const inquirer = require('../utils/inquirer-wrapper');
7
- const { getSkills, installSkill, removeSkill, updateAllSkills, createSkillTemplate, getPopularSkills } = require('../utils/skills');
8
- const { NatureCoError, SkillError, handleError } = require('../utils/errors');
9
- const detector = require('../utils/pattern-detector');
10
- const audit = require('../utils/audit');
11
-
12
- async function skills(args) {
13
- const [action, ...params] = args;
14
-
15
- if (!action || action === 'list') {
16
- await listSkills();
17
- return;
18
- }
19
-
20
- if (action === 'install') {
21
- const slug = params[0];
22
- if (!slug) {
23
- console.log(chalk.red('\n❌ Kullanım: natureco skills install <slug>\n'));
24
- process.exit(1);
25
- }
26
- await installSkillCommand(slug);
27
- return;
28
- }
29
-
30
- if (action === 'remove') {
31
- const slug = params[0];
32
- if (!slug) {
33
- console.log(chalk.red('\n❌ Kullanım: natureco skills remove <slug>\n'));
34
- process.exit(1);
35
- }
36
- await removeSkillCommand(slug);
37
- return;
38
- }
39
-
40
- if (action === 'update') {
41
- const flag = params[0];
42
- if (flag === '--all') {
43
- await updateAllSkillsCommand();
44
- } else {
45
- console.log(chalk.red('\n❌ Kullanım: natureco skills update --all\n'));
46
- process.exit(1);
47
- }
48
- return;
49
- }
50
-
51
- if (action === 'create') {
52
- const name = params[0];
53
- if (!name) {
54
- console.log(chalk.red('\n❌ Kullanım: natureco skills create <ad>\n'));
55
- process.exit(1);
56
- }
57
- await createSkillCommand(name);
58
- return;
59
- }
60
-
61
- if (action === 'search') {
62
- const query = params.join(' ');
63
- await searchSkillsCommand(query);
64
- return;
65
- }
66
-
67
- if (action === 'browse') {
68
- await browseSkillsCommand();
69
- return;
70
- }
71
-
72
- if (action === 'info') {
73
- const slug = params[0];
74
- await infoSkill(slug);
75
- return;
76
- }
77
-
78
- if (action === 'check') {
79
- await checkSkills();
80
- return;
81
- }
82
-
83
- if (action === 'suggest' || action === 'proposals') {
84
- await listProposals();
85
- return;
86
- }
87
-
88
- if (action === 'accept') {
89
- const proposalId = params[0];
90
- if (!proposalId) {
91
- console.log(chalk.red('\n❌ Kullanım: natureco skills accept <proposal-id>\n'));
92
- process.exit(1);
93
- }
94
- await acceptProposalCommand(proposalId);
95
- return;
96
- }
97
-
98
- if (action === 'reject') {
99
- const proposalId = params[0];
100
- if (!proposalId) {
101
- console.log(chalk.red('\n❌ Kullanım: natureco skills reject <proposal-id>\n'));
102
- process.exit(1);
103
- }
104
- detector.rejectProposal(proposalId);
105
- console.log(chalk.green(`\n✅ Proposal reddedildi: ${proposalId}\n`));
106
- return;
107
- }
108
-
109
- if (action === 'forget') {
110
- detector.reset();
111
- console.log(chalk.yellow('\n🧹 Tüm pattern hafızası ve proposal\'lar silindi.\n'));
112
- return;
113
- }
114
-
115
- console.log(chalk.red(`\n❌ Geçersiz action: ${action}\n`));
116
- console.log(chalk.gray('Kullanım: natureco skills [list|install|remove|update|create|search|browse|info|check|suggest|accept|reject|forget]\n'));
117
- process.exit(1);
118
- }
119
-
120
- async function listSkills() {
121
- const allSkills = getSkills();
122
-
123
- console.log(chalk.gray('\n ' + '─'.repeat(48)));
124
- console.log(chalk.cyan.bold('\n Yüklü Skill\'ler\n'));
125
-
126
- if (allSkills.length === 0) {
127
- console.log(chalk.gray(' Hiç skill yüklü değil.\n'));
128
- console.log(chalk.gray(' Yüklemek için: ') + chalk.cyan('natureco skills install <slug>'));
129
- console.log(chalk.gray(' Gözatmak için: ') + chalk.cyan('natureco skills browse\n'));
130
- return;
131
- }
132
-
133
- allSkills.forEach((skill, index) => {
134
- const sourceLabel = skill.source === 'builtin' ? chalk.blue('[yerleşik]') :
135
- skill.source === 'user' ? chalk.cyan('[kişisel]') :
136
- chalk.magenta('[proje]');
137
- console.log(chalk.white(` ${index + 1}. ${skill.name} `) + sourceLabel);
138
- console.log(chalk.gray(` ${skill.description}`));
139
- if (skill.metadata?.requires?.bins) {
140
- console.log(chalk.gray(` Gerekli: ${skill.metadata.requires.bins.join(', ')}`));
141
- }
142
- console.log('');
143
- });
144
-
145
- console.log(chalk.gray(' ' + '─'.repeat(48)));
146
- console.log(chalk.gray(` Toplam: ${allSkills.length} skill`));
147
- console.log(chalk.gray(' Kaldırmak için: ') + chalk.cyan('natureco skills remove <slug>\n'));
148
- }
149
-
150
- async function installSkillCommand(slug) {
151
- console.log(chalk.yellow(`\n⏳ "${slug}" skill'i yükleniyor...\n`));
152
-
153
- try {
154
- await installSkill(slug);
155
- console.log(chalk.green(`✅ "${slug}" başarıyla yüklendi!\n`));
156
- } catch (err) {
157
- console.log(chalk.red(`\n❌ Hata: ${err.message}\n`));
158
- process.exit(1);
159
- }
160
- }
161
-
162
- async function removeSkillCommand(slug) {
163
- const { confirm } = await inquirer.prompt([
164
- {
165
- type: 'confirm',
166
- name: 'confirm',
167
- message: `"${slug}" skill'ini silmek istediğinizden emin misiniz?`,
168
- default: false,
169
- },
170
- ]);
171
-
172
- if (!confirm) {
173
- console.log(chalk.gray('\nİptal edildi.\n'));
174
- return;
175
- }
176
-
177
- try {
178
- removeSkill(slug);
179
- console.log(chalk.green(`\n✅ "${slug}" silindi.\n`));
180
- } catch (err) {
181
- console.log(chalk.red(`\n❌ Hata: ${err.message}\n`));
182
- process.exit(1);
183
- }
184
- }
185
-
186
- async function updateAllSkillsCommand() {
187
- console.log(chalk.yellow('\n⏳ Tüm skill\'ler güncelleniyor...\n'));
188
-
189
- try {
190
- const updated = await updateAllSkills();
191
- if (updated.length === 0) {
192
- console.log(chalk.gray('Güncellenecek skill bulunamadı.\n'));
193
- } else {
194
- console.log(chalk.green(`✅ ${updated.length} skill güncellendi:\n`));
195
- updated.forEach(s => console.log(chalk.cyan(` - ${s}`)));
196
- console.log('');
197
- }
198
- } catch (err) {
199
- console.log(chalk.red(`\n Hata: ${err.message}\n`));
200
- process.exit(1);
201
- }
202
- }
203
-
204
- async function createSkillCommand(name) {
205
- console.log(chalk.yellow(`\n⏳ "${name}" skill şablonu oluşturuluyor...\n`));
206
-
207
- try {
208
- const skillPath = createSkillTemplate(name);
209
- console.log(chalk.green(`✅ Skill şablonu oluşturuldu:\n`));
210
- console.log(chalk.cyan(` ${skillPath}\n`));
211
- console.log(chalk.gray('SKILL.md dosyasını düzenleyerek skill\'i özelleştirin.\n'));
212
- } catch (err) {
213
- console.log(chalk.red(`\n❌ Hata: ${err.message}\n`));
214
- process.exit(1);
215
- }
216
- }
217
-
218
- async function searchSkillsCommand(query) {
219
- if (!query || query.trim().length === 0) {
220
- try {
221
- const popularSkills = await getPopularSkills();
222
- console.log(chalk.yellow('\nPopüler Skill\'ler:\n'));
223
- popularSkills.forEach(skill => {
224
- console.log(chalk.cyan(` ${skill.name.padEnd(15)}`), chalk.gray(skill.description));
225
- });
226
- } catch (err) {
227
- console.log(chalk.red(`\n ❌ Popüler skill'ler alınamadı: ${err.message}\n`));
228
- }
229
- console.log('');
230
- console.log(chalk.gray('Kurmak için: '), chalk.cyan('natureco skills install <slug>'));
231
- console.log(chalk.gray('Örnek: '), chalk.cyan('natureco skills install github'));
232
- console.log(chalk.gray('ClawHub: '), chalk.cyan('natureco skills install clawhub:github'));
233
- console.log('');
234
- return;
235
- }
236
-
237
- console.log(chalk.yellow(`\n⏳ "${query}" aranıyor...\n`));
238
-
239
- try {
240
- // ClawHub search API
241
- const searchUrl = `https://clawhub.ai/api/skills?q=${encodeURIComponent(query)}&limit=10`;
242
- const response = await fetch(searchUrl);
243
-
244
- if (!response.ok) {
245
- throw new SkillError('ClawHub API\'ye erişilemedi', 'fetch', `https://clawhub.ai/api/skills?q=${encodeURIComponent(query)}`);
246
- }
247
-
248
- let data;
249
- try {
250
- data = await response.json();
251
- } catch {
252
- throw new SkillError('ClawHub geçersiz yanıt döndü (JSON bekleniyordu)', 'parse', searchUrl);
253
- }
254
- const results = data.skills || [];
255
-
256
- if (results.length === 0) {
257
- console.log(chalk.yellow(`"${query}" için sonuç bulunamadı.\n`));
258
- return;
259
- }
260
-
261
- console.log(chalk.yellow(`"${query}" için ${results.length} sonuç:\n`));
262
- results.forEach(skill => {
263
- console.log(chalk.cyan(` ${skill.name.padEnd(15)}`), chalk.gray(skill.description || 'Açıklama yok'));
264
- console.log(chalk.gray(` Kurmak için: natureco skills install clawhub:${skill.slug}`));
265
- });
266
- console.log('');
267
- } catch (err) {
268
- console.log(chalk.red(`\n ❌ Arama başarısız: ${err.message}\n`));
269
- }
270
- }
271
-
272
- async function browseSkillsCommand() {
273
- let popularSkills;
274
- try {
275
- popularSkills = await getPopularSkills();
276
- } catch (err) {
277
- console.log(chalk.red(`\n ❌ Popüler skill'ler alınamadı: ${err.message}\n`));
278
- return;
279
- }
280
-
281
- console.log(chalk.green.bold('\n╭─ Popüler Skill\'ler ─╮\n'));
282
-
283
- process.stdin.resume();
284
- const { selectedSkills } = await inquirer.prompt([
285
- {
286
- type: 'checkbox',
287
- name: 'selectedSkills',
288
- message: 'Kurmak istediğiniz skill\'leri seçin:',
289
- choices: popularSkills.map(skill => ({
290
- name: `${skill.name} - ${skill.description}`,
291
- value: skill.source === 'clawhub' ? `clawhub:${skill.slug}` : skill.slug,
292
- })),
293
- },
294
- ]);
295
- process.stdin.pause();
296
-
297
- if (selectedSkills.length === 0) {
298
- console.log(chalk.gray('\nHiçbir skill seçilmedi.\n'));
299
- return;
300
- }
301
-
302
- console.log(chalk.yellow(`\n⏳ ${selectedSkills.length} skill kuruluyor...\n`));
303
-
304
- for (const slug of selectedSkills) {
305
- try {
306
- await installSkill(slug);
307
- console.log(chalk.green(`✅ ${slug} kuruldu`));
308
- } catch (err) {
309
- console.log(chalk.red(`❌ ${slug} kurulamadı: ${err.message}`));
310
- }
311
- }
312
-
313
- console.log(chalk.green('\n✅ Kurulum tamamlandı!\n'));
314
- }
315
-
316
- async function infoSkill(slug) {
317
- if (!slug) {
318
- console.log(chalk.red('\n ❌ Skill slug required\n'));
319
- console.log(chalk.gray(' Usage: natureco skills info <slug>\n'));
320
- process.exit(1);
321
- }
322
- const skills = getSkills();
323
- const skill = skills.find(s => s.name === slug || s.slug === slug);
324
- if (!skill) {
325
- console.log(chalk.red(`\n ❌ Skill not found: ${slug}\n`));
326
- process.exit(1);
327
- }
328
- console.log(chalk.gray(' ' + ''.repeat(48)));
329
- console.log(chalk.cyan.bold(`\n ${skill.name}\n`));
330
- console.log(chalk.gray(' Slug : ') + chalk.white(skill.slug || skill.name));
331
- console.log(chalk.gray(' Description : ') + chalk.white(skill.description));
332
- if (skill.source) console.log(chalk.gray(' Source : ') + chalk.white(skill.source));
333
- if (skill.version) console.log(chalk.gray(' Version : ') + chalk.white(skill.version));
334
- if (skill.path) console.log(chalk.gray(' Path : ') + chalk.gray(skill.path));
335
- if (skill.metadata?.requires?.bins) {
336
- console.log(chalk.gray(' Requires : ') + chalk.white(skill.metadata.requires.bins.join(', ')));
337
- }
338
- if (skill.metadata?.requires?.env) {
339
- console.log(chalk.gray(' Env vars : ') + chalk.white(Object.keys(skill.metadata.requires.env).join(', ')));
340
- }
341
- console.log('');
342
- }
343
-
344
- async function checkSkills() {
345
- const skills = getSkills();
346
- if (skills.length === 0) {
347
- console.log(chalk.gray('\n No skills installed.\n'));
348
- return;
349
- }
350
- let issues = 0;
351
- for (const skill of skills) {
352
- const skillPath = path.join(os.homedir(), '.natureco', 'skills', skill.slug || skill.name);
353
- const hasSkillMd = fs.existsSync(path.join(skillPath, 'SKILL.md'));
354
- const hasPackage = fs.existsSync(path.join(skillPath, 'package.json'));
355
- const status = hasSkillMd ? chalk.green('✓') : chalk.yellow('⚠ missing SKILL.md');
356
- console.log(` ${status} ${chalk.white(skill.name)}`);
357
- console.log(chalk.gray(` Path: ${skillPath}`));
358
- console.log(chalk.gray(` Package: ${hasPackage ? chalk.green('✓') : chalk.gray('none')}`));
359
- if (!hasSkillMd) issues++;
360
- }
361
- if (issues > 0) {
362
- console.log(chalk.yellow(`\n ⚠ ${issues} skills have issues\n`));
363
- } else {
364
- console.log(chalk.green(`\n All ${skills.length} skills healthy\n`));
365
- }
366
- }
367
-
368
- async function listProposals() {
369
- const proposals = detector.loadProposals();
370
- const pending = proposals.filter(p => p.status === 'pending');
371
-
372
- console.log('\n' + tui.styled(' 🧠 Self-Evolving Skill Proposals', { color: tui.PALETTE.primary, bold: true }));
373
- console.log(tui.styled(' ' + '─'.repeat(56), { color: tui.PALETTE.border }));
374
- console.log(' ' + tui.C.muted('Kullanımın tekrar eden pattern\'lerinden otomatik skill önerileri.\n'));
375
-
376
- if (pending.length === 0) {
377
- console.log(' ' + tui.C.muted('Şu an öneri yok. Daha fazla tool çağrısı yap, sistem öğrensin.'));
378
- console.log(' ' + tui.C.muted('Pattern\'leri sıfırla: ') + tui.C.brand('natureco skills forget\n'));
379
- return;
380
- }
381
-
382
- const rows = pending.map(p => ({
383
- name: p.suggestedName,
384
- count: p.count + 'x',
385
- pattern: p.pattern.length > 50 ? p.pattern.slice(0, 47) + '...' : p.pattern,
386
- first: new Date(p.firstSeen).toLocaleString(),
387
- id: p.id,
388
- }));
389
-
390
- console.log(tui.table(rows, [
391
- { key: 'name', label: 'Öneri', minWidth: 25, render: r => tui.styled(r.name, { color: tui.PALETTE.primary, bold: true }) },
392
- { key: 'count', label: 'Tekrar', minWidth: 7, render: r => tui.styled(r.count, { color: tui.PALETTE.accent, bold: true }) },
393
- { key: 'pattern', label: 'Pattern', minWidth: 30, render: r => tui.C.muted(r.pattern) },
394
- { key: 'first', label: 'İlk', minWidth: 18, render: r => tui.C.muted(r.first) },
395
- ], { borderStyle: 'round', zebra: true }));
396
-
397
- console.log('\n ' + tui.C.muted('Kabul et: ') + tui.C.brand('natureco skills accept <id>'));
398
- console.log(' ' + tui.C.muted('Reddet: ') + tui.C.brand('natureco skills reject <id>\n'));
399
- }
400
-
401
- async function acceptProposalCommand(proposalId) {
402
- console.log(chalk.yellow('\n⏳ Skill oluşturuluyor...\n'));
403
- const result = detector.acceptProposal(proposalId);
404
- if (!result.success) {
405
- console.log(chalk.red(`\n❌ ${result.reason}\n`));
406
- process.exit(1);
407
- }
408
- console.log(chalk.green(`✅ Yeni skill oluşturuldu: ${result.skillName}\n`));
409
- console.log(chalk.gray(` Yol: ${result.path}\n`));
410
- console.log(chalk.gray(' SKILL.md dosyasını düzenleyerek özelleştirebilirsin.\n'));
411
- audit.log(audit.ACTIONS.SKILL_AUTO, { proposalId, skillName: result.skillName });
412
- }
413
-
414
- module.exports = skills;
1
+ const chalk = require('chalk');
2
+ const tui = require('../utils/tui');
3
+ const path = require('path');
4
+ const fs = require('fs');
5
+ const os = require('os');
6
+ const inquirer = require('../utils/inquirer-wrapper');
7
+ const { getSkills, installSkill, removeSkill, updateAllSkills, createSkillTemplate, getPopularSkills } = require('../utils/skills');
8
+ const { NatureCoError, SkillError, handleError } = require('../utils/errors');
9
+ const detector = require('../utils/pattern-detector');
10
+ const audit = require('../utils/audit');
11
+
12
+ async function skills(args) {
13
+ const [action, ...params] = args;
14
+
15
+ if (!action || action === 'list') {
16
+ await listSkills();
17
+ return;
18
+ }
19
+
20
+ if (action === 'install') {
21
+ const slug = params[0];
22
+ if (!slug) {
23
+ console.log(chalk.red('\n❌ Kullanım: natureco skills install <slug>\n'));
24
+ process.exit(1);
25
+ }
26
+ await installSkillCommand(slug);
27
+ return;
28
+ }
29
+
30
+ if (action === 'remove') {
31
+ const slug = params[0];
32
+ if (!slug) {
33
+ console.log(chalk.red('\n❌ Kullanım: natureco skills remove <slug>\n'));
34
+ process.exit(1);
35
+ }
36
+ await removeSkillCommand(slug);
37
+ return;
38
+ }
39
+
40
+ if (action === 'update') {
41
+ const flag = params[0];
42
+ if (flag === '--all') {
43
+ await updateAllSkillsCommand();
44
+ } else {
45
+ console.log(chalk.red('\n❌ Kullanım: natureco skills update --all\n'));
46
+ process.exit(1);
47
+ }
48
+ return;
49
+ }
50
+
51
+ if (action === 'create') {
52
+ const name = params[0];
53
+ if (!name) {
54
+ console.log(chalk.red('\n❌ Kullanım: natureco skills create <ad>\n'));
55
+ process.exit(1);
56
+ }
57
+ await createSkillCommand(name);
58
+ return;
59
+ }
60
+
61
+ if (action === 'search') {
62
+ const query = params.join(' ');
63
+ await searchSkillsCommand(query);
64
+ return;
65
+ }
66
+
67
+ if (action === 'browse') {
68
+ await browseSkillsCommand();
69
+ return;
70
+ }
71
+
72
+ if (action === 'info') {
73
+ const slug = params[0];
74
+ await infoSkill(slug);
75
+ return;
76
+ }
77
+
78
+ if (action === 'check') {
79
+ await checkSkills();
80
+ return;
81
+ }
82
+
83
+ if (action === 'suggest' || action === 'proposals') {
84
+ await listProposals();
85
+ return;
86
+ }
87
+
88
+ if (action === 'accept') {
89
+ const proposalId = params[0];
90
+ if (!proposalId) {
91
+ console.log(chalk.red('\n❌ Kullanım: natureco skills accept <proposal-id>\n'));
92
+ process.exit(1);
93
+ }
94
+ await acceptProposalCommand(proposalId);
95
+ return;
96
+ }
97
+
98
+ if (action === 'reject') {
99
+ const proposalId = params[0];
100
+ if (!proposalId) {
101
+ console.log(chalk.red('\n❌ Kullanım: natureco skills reject <proposal-id>\n'));
102
+ process.exit(1);
103
+ }
104
+ detector.rejectProposal(proposalId);
105
+ console.log(chalk.green(`\n✅ Proposal reddedildi: ${proposalId}\n`));
106
+ return;
107
+ }
108
+
109
+ if (action === 'forget') {
110
+ detector.reset();
111
+ console.log(chalk.yellow('\n🧹 Tüm pattern hafızası ve proposal\'lar silindi.\n'));
112
+ return;
113
+ }
114
+
115
+ // v5.0.0: Marketplace
116
+ if (action === 'marketplace' || action === 'mp') {
117
+ await listMarketplace();
118
+ return;
119
+ }
120
+
121
+ if (action === 'install-mp') {
122
+ const skillName = params[0];
123
+ if (!skillName) { console.log(chalk.red('\n Kullanım: natureco skills install-mp <name>\n')); process.exit(1); }
124
+ await installFromMarketplace(skillName);
125
+ return;
126
+ }
127
+
128
+ if (action === 'search-mp') {
129
+ const query = params[0];
130
+ if (!query) { console.log(chalk.red('\n❌ Kullanım: natureco skills search-mp <query>\n')); process.exit(1); }
131
+ await searchMarketplace(query);
132
+ return;
133
+ }
134
+
135
+ if (action === 'remove-mp' || action === 'uninstall-mp') {
136
+ const skillName = params[0];
137
+ if (!skillName) { console.log(chalk.red('\n❌ Kullanım: natureco skills remove-mp <name>\n')); process.exit(1); }
138
+ uninstallMarketplace(skillName);
139
+ return;
140
+ }
141
+
142
+ console.log(chalk.red(`\n❌ Geçersiz action: ${action}\n`));
143
+ console.log(chalk.gray('Kullanım: natureco skills [list|install|remove|update|create|search|browse|info|check|suggest|accept|reject|forget|marketplace|install-mp|search-mp|remove-mp]\n'));
144
+ process.exit(1);
145
+ }
146
+
147
+ // v5.0.0: Marketplace wrapper fonksiyonlari
148
+ async function listMarketplace() {
149
+ const { loadToolDefinitions } = require('../utils/tools');
150
+ const tools = loadToolDefinitions();
151
+ const mp = tools.find(t => t.name === 'skills_marketplace');
152
+ if (!mp) return;
153
+ const result = await mp.execute({ action: 'list' });
154
+ if (result.success) {
155
+ console.log(chalk.cyan.bold('\n 🛒 Skill Marketplace (' + result.count + ' skill)\n'));
156
+ console.log(chalk.gray(' ' + '─'.repeat(56)));
157
+ for (const s of result.skills) {
158
+ console.log(' ' + chalk.cyan(s.name.padEnd(22)) + chalk.gray((s.description || '').slice(0, 50)));
159
+ }
160
+ console.log('\n ' + chalk.gray('Kur: ') + chalk.cyan('natureco skills install-mp <name>'));
161
+ console.log('');
162
+ }
163
+ }
164
+
165
+ async function installFromMarketplace(skillName) {
166
+ const { loadToolDefinitions } = require('../utils/tools');
167
+ const tools = loadToolDefinitions();
168
+ const mp = tools.find(t => t.name === 'skills_marketplace');
169
+ if (!mp) return;
170
+ const result = await mp.execute({ action: 'install', skillName });
171
+ if (result.success) {
172
+ console.log(chalk.green('\n ' + skillName + ' kuruldu: ' + result.path + '\n'));
173
+ } else {
174
+ console.log(chalk.red('\n ✗ ' + result.error + '\n'));
175
+ }
176
+ }
177
+
178
+ async function searchMarketplace(query) {
179
+ const { loadToolDefinitions } = require('../utils/tools');
180
+ const tools = loadToolDefinitions();
181
+ const mp = tools.find(t => t.name === 'skills_marketplace');
182
+ if (!mp) return;
183
+ const result = await mp.execute({ action: 'search', query });
184
+ if (result.success) {
185
+ console.log(chalk.cyan.bold('\n 🔍 "' + query + '" icin sonuclar\n'));
186
+ for (const s of result.results) {
187
+ console.log(' ' + chalk.cyan(s.name.padEnd(22)) + chalk.gray((s.description || '').slice(0, 50)));
188
+ }
189
+ console.log('');
190
+ }
191
+ }
192
+
193
+ function uninstallMarketplace(skillName) {
194
+ const skillDir = path.join(os.homedir(), '.natureco', 'skills', skillName);
195
+ if (fs.existsSync(skillDir)) {
196
+ fs.rmSync(skillDir, { recursive: true });
197
+ console.log(chalk.green('\n ✓ ' + skillName + ' kaldirildi\n'));
198
+ } else {
199
+ console.log(chalk.yellow('\n ' + skillName + ' zaten yok\n'));
200
+ }
201
+ }
202
+
203
+ async function listSkills() {
204
+ const allSkills = getSkills();
205
+
206
+ console.log(chalk.gray('\n ' + '─'.repeat(48)));
207
+ console.log(chalk.cyan.bold('\n Yüklü Skill\'ler\n'));
208
+
209
+ if (allSkills.length === 0) {
210
+ console.log(chalk.gray(' Hiç skill yüklü değil.\n'));
211
+ console.log(chalk.gray(' Yüklemek için: ') + chalk.cyan('natureco skills install <slug>'));
212
+ console.log(chalk.gray(' Gözatmak için: ') + chalk.cyan('natureco skills browse\n'));
213
+ return;
214
+ }
215
+
216
+ allSkills.forEach((skill, index) => {
217
+ const sourceLabel = skill.source === 'builtin' ? chalk.blue('[yerleşik]') :
218
+ skill.source === 'user' ? chalk.cyan('[kişisel]') :
219
+ chalk.magenta('[proje]');
220
+ console.log(chalk.white(` ${index + 1}. ${skill.name} `) + sourceLabel);
221
+ console.log(chalk.gray(` ${skill.description}`));
222
+ if (skill.metadata?.requires?.bins) {
223
+ console.log(chalk.gray(` Gerekli: ${skill.metadata.requires.bins.join(', ')}`));
224
+ }
225
+ console.log('');
226
+ });
227
+
228
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
229
+ console.log(chalk.gray(` Toplam: ${allSkills.length} skill`));
230
+ console.log(chalk.gray(' Kaldırmak için: ') + chalk.cyan('natureco skills remove <slug>\n'));
231
+ }
232
+
233
+ async function installSkillCommand(slug) {
234
+ console.log(chalk.yellow(`\n⏳ "${slug}" skill'i yükleniyor...\n`));
235
+
236
+ try {
237
+ await installSkill(slug);
238
+ console.log(chalk.green(`✅ "${slug}" başarıyla yüklendi!\n`));
239
+ } catch (err) {
240
+ console.log(chalk.red(`\n❌ Hata: ${err.message}\n`));
241
+ process.exit(1);
242
+ }
243
+ }
244
+
245
+ async function removeSkillCommand(slug) {
246
+ const { confirm } = await inquirer.prompt([
247
+ {
248
+ type: 'confirm',
249
+ name: 'confirm',
250
+ message: `"${slug}" skill'ini silmek istediğinizden emin misiniz?`,
251
+ default: false,
252
+ },
253
+ ]);
254
+
255
+ if (!confirm) {
256
+ console.log(chalk.gray('\nİptal edildi.\n'));
257
+ return;
258
+ }
259
+
260
+ try {
261
+ removeSkill(slug);
262
+ console.log(chalk.green(`\n✅ "${slug}" silindi.\n`));
263
+ } catch (err) {
264
+ console.log(chalk.red(`\n❌ Hata: ${err.message}\n`));
265
+ process.exit(1);
266
+ }
267
+ }
268
+
269
+ async function updateAllSkillsCommand() {
270
+ console.log(chalk.yellow('\n⏳ Tüm skill\'ler güncelleniyor...\n'));
271
+
272
+ try {
273
+ const updated = await updateAllSkills();
274
+ if (updated.length === 0) {
275
+ console.log(chalk.gray('Güncellenecek skill bulunamadı.\n'));
276
+ } else {
277
+ console.log(chalk.green(`✅ ${updated.length} skill güncellendi:\n`));
278
+ updated.forEach(s => console.log(chalk.cyan(` - ${s}`)));
279
+ console.log('');
280
+ }
281
+ } catch (err) {
282
+ console.log(chalk.red(`\n❌ Hata: ${err.message}\n`));
283
+ process.exit(1);
284
+ }
285
+ }
286
+
287
+ async function createSkillCommand(name) {
288
+ console.log(chalk.yellow(`\n⏳ "${name}" skill şablonu oluşturuluyor...\n`));
289
+
290
+ try {
291
+ const skillPath = createSkillTemplate(name);
292
+ console.log(chalk.green(`✅ Skill şablonu oluşturuldu:\n`));
293
+ console.log(chalk.cyan(` ${skillPath}\n`));
294
+ console.log(chalk.gray('SKILL.md dosyasını düzenleyerek skill\'i özelleştirin.\n'));
295
+ } catch (err) {
296
+ console.log(chalk.red(`\n❌ Hata: ${err.message}\n`));
297
+ process.exit(1);
298
+ }
299
+ }
300
+
301
+ async function searchSkillsCommand(query) {
302
+ if (!query || query.trim().length === 0) {
303
+ try {
304
+ const popularSkills = await getPopularSkills();
305
+ console.log(chalk.yellow('\nPopüler Skill\'ler:\n'));
306
+ popularSkills.forEach(skill => {
307
+ console.log(chalk.cyan(` ${skill.name.padEnd(15)}`), chalk.gray(skill.description));
308
+ });
309
+ } catch (err) {
310
+ console.log(chalk.red(`\n ❌ Popüler skill'ler alınamadı: ${err.message}\n`));
311
+ }
312
+ console.log('');
313
+ console.log(chalk.gray('Kurmak için: '), chalk.cyan('natureco skills install <slug>'));
314
+ console.log(chalk.gray('Örnek: '), chalk.cyan('natureco skills install github'));
315
+ console.log(chalk.gray('ClawHub: '), chalk.cyan('natureco skills install clawhub:github'));
316
+ console.log('');
317
+ return;
318
+ }
319
+
320
+ console.log(chalk.yellow(`\n⏳ "${query}" aranıyor...\n`));
321
+
322
+ try {
323
+ // ClawHub search API
324
+ const searchUrl = `https://clawhub.ai/api/skills?q=${encodeURIComponent(query)}&limit=10`;
325
+ const response = await fetch(searchUrl);
326
+
327
+ if (!response.ok) {
328
+ throw new SkillError('ClawHub API\'ye erişilemedi', 'fetch', `https://clawhub.ai/api/skills?q=${encodeURIComponent(query)}`);
329
+ }
330
+
331
+ let data;
332
+ try {
333
+ data = await response.json();
334
+ } catch {
335
+ throw new SkillError('ClawHub geçersiz yanıt döndü (JSON bekleniyordu)', 'parse', searchUrl);
336
+ }
337
+ const results = data.skills || [];
338
+
339
+ if (results.length === 0) {
340
+ console.log(chalk.yellow(`"${query}" için sonuç bulunamadı.\n`));
341
+ return;
342
+ }
343
+
344
+ console.log(chalk.yellow(`"${query}" için ${results.length} sonuç:\n`));
345
+ results.forEach(skill => {
346
+ console.log(chalk.cyan(` ${skill.name.padEnd(15)}`), chalk.gray(skill.description || 'Açıklama yok'));
347
+ console.log(chalk.gray(` Kurmak için: natureco skills install clawhub:${skill.slug}`));
348
+ });
349
+ console.log('');
350
+ } catch (err) {
351
+ console.log(chalk.red(`\n Arama başarısız: ${err.message}\n`));
352
+ }
353
+ }
354
+
355
+ async function browseSkillsCommand() {
356
+ let popularSkills;
357
+ try {
358
+ popularSkills = await getPopularSkills();
359
+ } catch (err) {
360
+ console.log(chalk.red(`\n ❌ Popüler skill'ler alınamadı: ${err.message}\n`));
361
+ return;
362
+ }
363
+
364
+ console.log(chalk.green.bold('\n╭─ Popüler Skill\'ler ─╮\n'));
365
+
366
+ process.stdin.resume();
367
+ const { selectedSkills } = await inquirer.prompt([
368
+ {
369
+ type: 'checkbox',
370
+ name: 'selectedSkills',
371
+ message: 'Kurmak istediğiniz skill\'leri seçin:',
372
+ choices: popularSkills.map(skill => ({
373
+ name: `${skill.name} - ${skill.description}`,
374
+ value: skill.source === 'clawhub' ? `clawhub:${skill.slug}` : skill.slug,
375
+ })),
376
+ },
377
+ ]);
378
+ process.stdin.pause();
379
+
380
+ if (selectedSkills.length === 0) {
381
+ console.log(chalk.gray('\nHiçbir skill seçilmedi.\n'));
382
+ return;
383
+ }
384
+
385
+ console.log(chalk.yellow(`\n⏳ ${selectedSkills.length} skill kuruluyor...\n`));
386
+
387
+ for (const slug of selectedSkills) {
388
+ try {
389
+ await installSkill(slug);
390
+ console.log(chalk.green(`✅ ${slug} kuruldu`));
391
+ } catch (err) {
392
+ console.log(chalk.red(`❌ ${slug} kurulamadı: ${err.message}`));
393
+ }
394
+ }
395
+
396
+ console.log(chalk.green('\n✅ Kurulum tamamlandı!\n'));
397
+ }
398
+
399
+ async function infoSkill(slug) {
400
+ if (!slug) {
401
+ console.log(chalk.red('\n ❌ Skill slug required\n'));
402
+ console.log(chalk.gray(' Usage: natureco skills info <slug>\n'));
403
+ process.exit(1);
404
+ }
405
+ const skills = getSkills();
406
+ const skill = skills.find(s => s.name === slug || s.slug === slug);
407
+ if (!skill) {
408
+ console.log(chalk.red(`\n ❌ Skill not found: ${slug}\n`));
409
+ process.exit(1);
410
+ }
411
+ console.log(chalk.gray(' ' + '─'.repeat(48)));
412
+ console.log(chalk.cyan.bold(`\n ${skill.name}\n`));
413
+ console.log(chalk.gray(' Slug : ') + chalk.white(skill.slug || skill.name));
414
+ console.log(chalk.gray(' Description : ') + chalk.white(skill.description));
415
+ if (skill.source) console.log(chalk.gray(' Source : ') + chalk.white(skill.source));
416
+ if (skill.version) console.log(chalk.gray(' Version : ') + chalk.white(skill.version));
417
+ if (skill.path) console.log(chalk.gray(' Path : ') + chalk.gray(skill.path));
418
+ if (skill.metadata?.requires?.bins) {
419
+ console.log(chalk.gray(' Requires : ') + chalk.white(skill.metadata.requires.bins.join(', ')));
420
+ }
421
+ if (skill.metadata?.requires?.env) {
422
+ console.log(chalk.gray(' Env vars : ') + chalk.white(Object.keys(skill.metadata.requires.env).join(', ')));
423
+ }
424
+ console.log('');
425
+ }
426
+
427
+ async function checkSkills() {
428
+ const skills = getSkills();
429
+ if (skills.length === 0) {
430
+ console.log(chalk.gray('\n No skills installed.\n'));
431
+ return;
432
+ }
433
+ let issues = 0;
434
+ for (const skill of skills) {
435
+ const skillPath = path.join(os.homedir(), '.natureco', 'skills', skill.slug || skill.name);
436
+ const hasSkillMd = fs.existsSync(path.join(skillPath, 'SKILL.md'));
437
+ const hasPackage = fs.existsSync(path.join(skillPath, 'package.json'));
438
+ const status = hasSkillMd ? chalk.green('✓') : chalk.yellow('⚠ missing SKILL.md');
439
+ console.log(` ${status} ${chalk.white(skill.name)}`);
440
+ console.log(chalk.gray(` Path: ${skillPath}`));
441
+ console.log(chalk.gray(` Package: ${hasPackage ? chalk.green('✓') : chalk.gray('none')}`));
442
+ if (!hasSkillMd) issues++;
443
+ }
444
+ if (issues > 0) {
445
+ console.log(chalk.yellow(`\n ⚠ ${issues} skills have issues\n`));
446
+ } else {
447
+ console.log(chalk.green(`\n ✓ All ${skills.length} skills healthy\n`));
448
+ }
449
+ }
450
+
451
+ async function listProposals() {
452
+ const proposals = detector.loadProposals();
453
+ const pending = proposals.filter(p => p.status === 'pending');
454
+
455
+ console.log('\n' + tui.styled(' 🧠 Self-Evolving Skill Proposals', { color: tui.PALETTE.primary, bold: true }));
456
+ console.log(tui.styled(' ' + '─'.repeat(56), { color: tui.PALETTE.border }));
457
+ console.log(' ' + tui.C.muted('Kullanımın tekrar eden pattern\'lerinden otomatik skill önerileri.\n'));
458
+
459
+ if (pending.length === 0) {
460
+ console.log(' ' + tui.C.muted('Şu an öneri yok. Daha fazla tool çağrısı yap, sistem öğrensin.'));
461
+ console.log(' ' + tui.C.muted('Pattern\'leri sıfırla: ') + tui.C.brand('natureco skills forget\n'));
462
+ return;
463
+ }
464
+
465
+ const rows = pending.map(p => ({
466
+ name: p.suggestedName,
467
+ count: p.count + 'x',
468
+ pattern: p.pattern.length > 50 ? p.pattern.slice(0, 47) + '...' : p.pattern,
469
+ first: new Date(p.firstSeen).toLocaleString(),
470
+ id: p.id,
471
+ }));
472
+
473
+ console.log(tui.table(rows, [
474
+ { key: 'name', label: 'Öneri', minWidth: 25, render: r => tui.styled(r.name, { color: tui.PALETTE.primary, bold: true }) },
475
+ { key: 'count', label: 'Tekrar', minWidth: 7, render: r => tui.styled(r.count, { color: tui.PALETTE.accent, bold: true }) },
476
+ { key: 'pattern', label: 'Pattern', minWidth: 30, render: r => tui.C.muted(r.pattern) },
477
+ { key: 'first', label: 'İlk', minWidth: 18, render: r => tui.C.muted(r.first) },
478
+ ], { borderStyle: 'round', zebra: true }));
479
+
480
+ console.log('\n ' + tui.C.muted('Kabul et: ') + tui.C.brand('natureco skills accept <id>'));
481
+ console.log(' ' + tui.C.muted('Reddet: ') + tui.C.brand('natureco skills reject <id>\n'));
482
+ }
483
+
484
+ async function acceptProposalCommand(proposalId) {
485
+ console.log(chalk.yellow('\n⏳ Skill oluşturuluyor...\n'));
486
+ const result = detector.acceptProposal(proposalId);
487
+ if (!result.success) {
488
+ console.log(chalk.red(`\n❌ ${result.reason}\n`));
489
+ process.exit(1);
490
+ }
491
+ console.log(chalk.green(`✅ Yeni skill oluşturuldu: ${result.skillName}\n`));
492
+ console.log(chalk.gray(` Yol: ${result.path}\n`));
493
+ console.log(chalk.gray(' SKILL.md dosyasını düzenleyerek özelleştirebilirsin.\n'));
494
+ audit.log(audit.ACTIONS.SKILL_AUTO, { proposalId, skillName: result.skillName });
495
+ }
496
+
497
+ module.exports = skills;