natureco-cli 4.9.1 → 5.0.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/CHANGELOG.md +486 -422
- package/bin/natureco.js +9 -3
- package/package.json +1 -1
- package/src/commands/code_v5.js +279 -0
- package/src/commands/skills.js +497 -414
- package/src/tools/file_search.js +11 -4
- package/src/tools/skills_autoload.js +97 -0
- package/src/tools/skills_marketplace.js +233 -0
package/src/tools/file_search.js
CHANGED
|
@@ -21,11 +21,18 @@ async function searchFiles({ pattern, basePath = null, maxResults = 100 }) {
|
|
|
21
21
|
const results = [];
|
|
22
22
|
|
|
23
23
|
// Basit glob regex donusumu (glob deseni)
|
|
24
|
+
// **/ ve ** pattern'lerini placeholder yap (once kalsin),
|
|
25
|
+
// sonra escape et, en son placeholder'lari replace et.
|
|
26
|
+
// Glob -> regex: **/* is once, ** is sonra, sonra *, ?
|
|
24
27
|
const regexPattern = pattern
|
|
25
|
-
.replace(
|
|
26
|
-
.replace(
|
|
27
|
-
.replace(
|
|
28
|
-
.replace(
|
|
28
|
+
.replace(/\*\*\//g, '@@DSLASH@@') // **/ -> placeholder
|
|
29
|
+
.replace(/\*\*/g, '@@DSTAR@@') // ** -> placeholder
|
|
30
|
+
.replace(/\?/g, '@@QMARK@@') // ? -> placeholder
|
|
31
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // diger ozel karakterleri escape
|
|
32
|
+
.replace(/@@DSLASH@@/g, '(?:.*\\/)?') // **/ -> (?:.*\/)? (sifir veya daha fazla dizin)
|
|
33
|
+
.replace(/@@DSTAR@@/g, '.*') // ** -> .*
|
|
34
|
+
.replace(/@@QMARK@@/g, '[^/]') // ? -> [^/]
|
|
35
|
+
.replace(/\*/g, '[^/]*');
|
|
29
36
|
|
|
30
37
|
const regex = new RegExp("^" + regexPattern + "$");
|
|
31
38
|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skills_autoload - Otomatik skill yukleme (v5.0.0)
|
|
3
|
+
*
|
|
4
|
+
* Parton'un vizyonu: "Ihtiyaca gore skill'ler otomatik yuklensin"
|
|
5
|
+
*
|
|
6
|
+
* Mantik:
|
|
7
|
+
* 1. Kullanici bir istek yapar
|
|
8
|
+
* 2. REPL anahtar kelimeleri tarar (seo, telegram, git commit, vb.)
|
|
9
|
+
* 3. Ilgili skill varsa otomatik yuklenir
|
|
10
|
+
* 4. System prompt'a eklenir
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fs = require("fs");
|
|
14
|
+
const path = require("path");
|
|
15
|
+
const os = require("os");
|
|
16
|
+
|
|
17
|
+
const SKILLS_DIR = path.join(os.homedir(), ".natureco", "skills");
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Anahtar kelime -> skill mapping
|
|
21
|
+
*/
|
|
22
|
+
const KEYWORD_MAP = {
|
|
23
|
+
// SEO
|
|
24
|
+
"seo": ["seo", "audit", "site", "website", "ranking", "meta", "search engine", "url"],
|
|
25
|
+
"telegram": ["telegram", "bot", "botfather", "t.me"],
|
|
26
|
+
"git-commit": ["commit", "git commit", "conventional commit", "kaydet", "gönder"],
|
|
27
|
+
"code-review": ["review", "incele", "kod incele", "bug", "security check"],
|
|
28
|
+
"morning-briefing": ["briefing", "morning", "sabah brifingi", "günlük özet"],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function loadAllSkills() {
|
|
32
|
+
const loaded = [];
|
|
33
|
+
try {
|
|
34
|
+
if (!fs.existsSync(SKILLS_DIR)) return loaded;
|
|
35
|
+
const dirs = fs.readdirSync(SKILLS_DIR, { withFileTypes: true });
|
|
36
|
+
for (const dir of dirs) {
|
|
37
|
+
if (!dir.isDirectory()) continue;
|
|
38
|
+
const skillFile = path.join(SKILLS_DIR, dir.name, "SKILL.md");
|
|
39
|
+
if (fs.existsSync(skillFile)) {
|
|
40
|
+
loaded.push({ name: dir.name, content: fs.readFileSync(skillFile, "utf8") });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
} catch {}
|
|
44
|
+
return loaded;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Mesaj icindeki anahtar kelimeleri tara, ilgili skill'leri bul
|
|
49
|
+
*/
|
|
50
|
+
function detectRelevantSkills(message, availableSkills) {
|
|
51
|
+
const lower = message.toLowerCase();
|
|
52
|
+
const detected = new Set();
|
|
53
|
+
|
|
54
|
+
for (const [skill, keywords] of Object.entries(KEYWORD_MAP)) {
|
|
55
|
+
for (const kw of keywords) {
|
|
56
|
+
if (lower.includes(kw)) {
|
|
57
|
+
detected.add(skill);
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Yuklu skill'lerle kesistir
|
|
64
|
+
return availableSkills.filter(s => detected.has(s.name));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function autoLoad(message) {
|
|
68
|
+
const available = loadAllSkills();
|
|
69
|
+
const relevant = detectRelevantSkills(message, available);
|
|
70
|
+
if (relevant.length === 0) return [];
|
|
71
|
+
|
|
72
|
+
return relevant.map(s => ({
|
|
73
|
+
name: s.name,
|
|
74
|
+
summary: s.content.slice(0, 500).split("\n").slice(0, 3).join("\n"),
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
module.exports = {
|
|
79
|
+
name: "skills_autoload",
|
|
80
|
+
description: "Kullanici istegine gore otomatik skill yukle. Mesaj analiz edilir, ilgili skill sistem prompt'a eklenir.",
|
|
81
|
+
inputSchema: {
|
|
82
|
+
type: "object",
|
|
83
|
+
properties: {
|
|
84
|
+
message: { type: "string", description: "Kullanici mesaji / istegi" },
|
|
85
|
+
},
|
|
86
|
+
required: ["message"],
|
|
87
|
+
},
|
|
88
|
+
async execute(params) {
|
|
89
|
+
const loaded = autoLoad(params.message);
|
|
90
|
+
return {
|
|
91
|
+
success: true,
|
|
92
|
+
message: params.message,
|
|
93
|
+
detectedSkills: loaded.map(s => s.name),
|
|
94
|
+
skillContext: loaded.map(s => s.content).join("\n\n"),
|
|
95
|
+
};
|
|
96
|
+
},
|
|
97
|
+
};
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skills_marketplace - Skill marketplace (v5.0.0)
|
|
3
|
+
*
|
|
4
|
+
* Parton'un vizyonu: "herkes kendi skill'ini paylassin, CLI otomatik yuklesin"
|
|
5
|
+
*
|
|
6
|
+
* Format: ~/.natureco/marketplace/<skill_name>.json
|
|
7
|
+
* Source: NatureCo GitHub repo (community-contributed) veya local
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require("fs");
|
|
11
|
+
const path = require("path");
|
|
12
|
+
const os = require("os");
|
|
13
|
+
const https = require("https");
|
|
14
|
+
|
|
15
|
+
const MARKETPLACE_DIR = path.join(os.homedir(), ".natureco", "marketplace");
|
|
16
|
+
const SKILLS_DIR = path.join(os.homedir(), ".natureco", "skills");
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Marketplace URL'leri — Parton kendi GitHub repo'sunu koyacak
|
|
20
|
+
*/
|
|
21
|
+
const MARKETPLACE_SOURCES = [
|
|
22
|
+
{
|
|
23
|
+
name: "NatureCo Official",
|
|
24
|
+
url: "https://raw.githubusercontent.com/naturecoofficial/natureco-skills/main/index.json",
|
|
25
|
+
enabled: true,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "Community",
|
|
29
|
+
url: "https://raw.githubusercontent.com/natureco-community/skills/main/index.json",
|
|
30
|
+
enabled: true,
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Built-in skill paketleri — Parton'un NatureCo vizyonu icin onemli
|
|
36
|
+
*/
|
|
37
|
+
const BUILTIN_SKILLS = {
|
|
38
|
+
"seo-audit": {
|
|
39
|
+
name: "SEO Audit",
|
|
40
|
+
description: "Web sitesi SEO denetimi - meta tags, headings, schema.org, performance",
|
|
41
|
+
author: "NatureCo Team",
|
|
42
|
+
version: "1.0.0",
|
|
43
|
+
tags: ["seo", "web", "audit"],
|
|
44
|
+
instructions: "Kullanici bir URL isteyince, bu skill devreye girer. http_request ile sayfayi cek, og:title, og:description, og:image, h1/h2 sayisi, schema.org/l* varligi, robots.txt, sitemap.xml kontrol et. Skor 0-100 dondur.",
|
|
45
|
+
},
|
|
46
|
+
"code-review": {
|
|
47
|
+
name: "Code Review",
|
|
48
|
+
description: "Kod inceleme - style, best practices, security, performance",
|
|
49
|
+
author: "NatureCo Team",
|
|
50
|
+
version: "1.0.0",
|
|
51
|
+
tags: ["code", "review", "security"],
|
|
52
|
+
instructions: "Kullanici kod gonderdiginde, grep_search ile TODO/FIXME/security issue bul, linting kontrolu yap, ozellikle XSS, SQL injection, hardcoded secret'lere bak. Olumlu/olumsuz yonleri listele.",
|
|
53
|
+
},
|
|
54
|
+
"git-commit": {
|
|
55
|
+
name: "Smart Git Commit",
|
|
56
|
+
description: "AI ile conventional commit mesaji uret",
|
|
57
|
+
author: "NatureCo Team",
|
|
58
|
+
version: "1.0.0",
|
|
59
|
+
tags: ["git", "workflow"],
|
|
60
|
+
instructions: "git diff ciktisini oku, degisiklik tipine gore (feat/fix/docs/style/refactor/test/chore) conventional commit formatinda mesaj uret. Turkce veya Ingilizce gore dili ayarla.",
|
|
61
|
+
},
|
|
62
|
+
"telegram-bot": {
|
|
63
|
+
name: "Telegram Bot Setup",
|
|
64
|
+
description: "Telegram bot kurulum wizard - BotFather adim adim",
|
|
65
|
+
author: "NatureCo Team",
|
|
66
|
+
version: "1.0.0",
|
|
67
|
+
tags: ["telegram", "integration", "tutorial"],
|
|
68
|
+
instructions: "Kullanici 'Telegram bot kur' dediginde, sirasiyla: 1) @BotFather'a git, 2) /newbot, 3) isim ve username, 4) token al, 5) natureco telegram connect ile gir, 6) @userinfobot'tan user ID al, 7) natureco gateway start. Adim adim Turkce yonlendir.",
|
|
69
|
+
},
|
|
70
|
+
"morning-briefing": {
|
|
71
|
+
name: "Morning Briefing",
|
|
72
|
+
description: "Her sabah 9'da ozet: hava, takvim, todo'lar, RSS",
|
|
73
|
+
author: "NatureCo Team",
|
|
74
|
+
version: "1.0.0",
|
|
75
|
+
tags: ["productivity", "cron", "daily"],
|
|
76
|
+
instructions: "cron_create ile her sabah 9'da calisan bir setup kur. natureco weather, natureco calendar today, natureco todo_write list, natureco memory_search - tum bunlari ozetleyen bir gunluk briefing ver.",
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Local skill yukle (skill dosyasi -> ~/.natureco/skills/<name>/)
|
|
82
|
+
*/
|
|
83
|
+
function installLocal(skillData) {
|
|
84
|
+
if (!skillData.name) return { success: false, error: "Skill name gerekli" };
|
|
85
|
+
const skillDir = path.join(SKILLS_DIR, skillData.name);
|
|
86
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
87
|
+
|
|
88
|
+
const skillFile = path.join(skillDir, "SKILL.md");
|
|
89
|
+
const content = skillData.instructions || skillData.content || `# ${skillData.name}\n\n${skillData.description || ""}`;
|
|
90
|
+
fs.writeFileSync(skillFile, content, "utf8");
|
|
91
|
+
|
|
92
|
+
// Metadata
|
|
93
|
+
const meta = {
|
|
94
|
+
name: skillData.name,
|
|
95
|
+
description: skillData.description,
|
|
96
|
+
author: skillData.author || "Unknown",
|
|
97
|
+
version: skillData.version || "1.0.0",
|
|
98
|
+
tags: skillData.tags || [],
|
|
99
|
+
installedAt: new Date().toISOString(),
|
|
100
|
+
};
|
|
101
|
+
fs.writeFileSync(path.join(skillDir, "metadata.json"), JSON.stringify(meta, null, 2), "utf8");
|
|
102
|
+
|
|
103
|
+
return { success: true, path: skillDir, skill: meta };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* URL'den skill yukle (GitHub raw content)
|
|
108
|
+
*/
|
|
109
|
+
function installFromUrl(url) {
|
|
110
|
+
return new Promise((resolve) => {
|
|
111
|
+
https.get(url, (res) => {
|
|
112
|
+
let data = "";
|
|
113
|
+
res.on("data", d => data += d);
|
|
114
|
+
res.on("end", () => {
|
|
115
|
+
try {
|
|
116
|
+
const skill = JSON.parse(data);
|
|
117
|
+
resolve(installLocal(skill));
|
|
118
|
+
} catch (e) {
|
|
119
|
+
resolve({ success: false, error: "Skill JSON parse hatasi: " + e.message });
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}).on("error", e => resolve({ success: false, error: e.message }));
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Marketplace listele
|
|
128
|
+
*/
|
|
129
|
+
async function listMarketplace() {
|
|
130
|
+
const skills = { ...BUILTIN_SKILLS };
|
|
131
|
+
|
|
132
|
+
// Remote sources'dan da cekmeyi dene
|
|
133
|
+
for (const source of MARKETPLACE_SOURCES.filter(s => s.enabled)) {
|
|
134
|
+
try {
|
|
135
|
+
const remote = await new Promise((resolve) => {
|
|
136
|
+
const req = https.get(source.url, { timeout: 5000 }, (res) => {
|
|
137
|
+
let data = "";
|
|
138
|
+
res.on("data", d => data += d);
|
|
139
|
+
res.on("end", () => {
|
|
140
|
+
try { resolve(JSON.parse(data)); } catch { resolve({}); }
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
req.on("error", () => resolve({}));
|
|
144
|
+
req.on("timeout", () => { req.destroy(); resolve({}); });
|
|
145
|
+
});
|
|
146
|
+
Object.assign(skills, remote);
|
|
147
|
+
} catch {}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return skills;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Tool definitions
|
|
155
|
+
*/
|
|
156
|
+
module.exports = {
|
|
157
|
+
name: "skills_marketplace",
|
|
158
|
+
description: "Skill marketplace - topluluk tarafindan paylasilan NatureCo CLI skill'leri. action: list, install, uninstall, search.",
|
|
159
|
+
inputSchema: {
|
|
160
|
+
type: "object",
|
|
161
|
+
properties: {
|
|
162
|
+
action: { type: "string", description: "list/install/uninstall/search", enum: ["list", "install", "uninstall", "search"] },
|
|
163
|
+
skillName: { type: "string", description: "Skill adi (install/uninstall icin)" },
|
|
164
|
+
query: { type: "string", description: "Arama sorgusu (search icin)" },
|
|
165
|
+
source: { type: "string", description: "Marketplace URL (custom source icin)" },
|
|
166
|
+
},
|
|
167
|
+
required: ["action"],
|
|
168
|
+
},
|
|
169
|
+
async execute(params) {
|
|
170
|
+
const { action, skillName, query, source } = params;
|
|
171
|
+
|
|
172
|
+
if (action === "list") {
|
|
173
|
+
const all = await listMarketplace();
|
|
174
|
+
return {
|
|
175
|
+
success: true,
|
|
176
|
+
count: Object.keys(all).length,
|
|
177
|
+
skills: Object.entries(all).map(([name, s]) => ({
|
|
178
|
+
name,
|
|
179
|
+
description: s.description,
|
|
180
|
+
author: s.author,
|
|
181
|
+
version: s.version,
|
|
182
|
+
tags: s.tags,
|
|
183
|
+
})),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (action === "search") {
|
|
188
|
+
if (!query) return { success: false, error: "query gerekli" };
|
|
189
|
+
const all = await listMarketplace();
|
|
190
|
+
const q = query.toLowerCase();
|
|
191
|
+
const matches = Object.entries(all).filter(([_, s]) =>
|
|
192
|
+
s.description?.toLowerCase().includes(q) ||
|
|
193
|
+
s.tags?.some(t => t.toLowerCase().includes(q)) ||
|
|
194
|
+
s.name.toLowerCase().includes(q)
|
|
195
|
+
);
|
|
196
|
+
return { success: true, query, count: matches.length, results: matches.map(([n, s]) => ({ name: n, ...s })) };
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (action === "install") {
|
|
200
|
+
if (!skillName) return { success: false, error: "skillName gerekli" };
|
|
201
|
+
|
|
202
|
+
// Once local BUILTIN'den dene
|
|
203
|
+
if (BUILTIN_SKILLS[skillName]) {
|
|
204
|
+
return installLocal(BUILTIN_SKILLS[skillName]);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Sonra URL'den dene
|
|
208
|
+
if (source) {
|
|
209
|
+
return await installFromUrl(source);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Marketplace'ten dene
|
|
213
|
+
const all = await listMarketplace();
|
|
214
|
+
if (all[skillName]) {
|
|
215
|
+
return installLocal(all[skillName]);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return { success: false, error: `Skill bulunamadi: ${skillName}. Once 'list' calistirin.` };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (action === "uninstall") {
|
|
222
|
+
if (!skillName) return { success: false, error: "skillName gerekli" };
|
|
223
|
+
const skillDir = path.join(SKILLS_DIR, skillName);
|
|
224
|
+
if (!fs.existsSync(skillDir)) {
|
|
225
|
+
return { success: false, error: `Skill yuklu degil: ${skillName}` };
|
|
226
|
+
}
|
|
227
|
+
fs.rmSync(skillDir, { recursive: true });
|
|
228
|
+
return { success: true, message: `Skill kaldirildi: ${skillName}` };
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return { success: false, error: `Bilinmeyen action: ${action}` };
|
|
232
|
+
},
|
|
233
|
+
};
|