@sysvv/ai-skill 1.6.1 → 1.7.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/dist/index.js +88 -68
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { fileURLToPath } from "node:url";
|
|
|
7
7
|
import { findSkillFiles } from "./core/registry.js";
|
|
8
8
|
import { parseSkillFile } from "./core/frontmatter.js";
|
|
9
9
|
import { loadSkill } from "./core/skill.js";
|
|
10
|
-
import { loadMcp, writeMcp
|
|
10
|
+
import { loadMcp, writeMcp } from "./core/mcp.js";
|
|
11
11
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
12
|
// ── ANSI ────────────────────────────────────────────────────────────────
|
|
13
13
|
const ANSI = {
|
|
@@ -159,88 +159,116 @@ async function installSkills(agent) {
|
|
|
159
159
|
}
|
|
160
160
|
if (mcpsToInstall.size > 0) {
|
|
161
161
|
console.log('');
|
|
162
|
+
const envVarsNeeded = new Map();
|
|
162
163
|
for (const mcpName of mcpsToInstall) {
|
|
163
164
|
try {
|
|
164
165
|
const mcp = await loadMcp(mcpName);
|
|
165
166
|
const mcpTarget = await writeMcp(agent, mcp);
|
|
166
167
|
console.log(` ${GREEN}✔${ANSI.reset} MCP ${ANSI.bold}${mcpName}${ANSI.reset} ${ANSI.dim}→ ${mcpTarget}${ANSI.reset}`);
|
|
168
|
+
// Coleta env vars do MCP
|
|
169
|
+
if (mcp.env) {
|
|
170
|
+
for (const key of Object.keys(mcp.env)) {
|
|
171
|
+
envVarsNeeded.set(key, mcpName);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
167
174
|
}
|
|
168
175
|
catch (err) {
|
|
169
176
|
console.log(` ${RED}✖${ANSI.reset} MCP ${mcpName}: ${err.message}`);
|
|
170
177
|
}
|
|
171
178
|
}
|
|
179
|
+
// Atualiza .env
|
|
180
|
+
if (envVarsNeeded.size > 0) {
|
|
181
|
+
await ensureEnvFile(envVarsNeeded);
|
|
182
|
+
}
|
|
172
183
|
}
|
|
173
184
|
console.log(`\n Skills instaladas em ${ANSI.bold}${destBase}/${ANSI.reset}\n`);
|
|
174
185
|
}
|
|
175
|
-
// ──
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
186
|
+
// ── .env ────────────────────────────────────────────────────────────────
|
|
187
|
+
/** Garante que o .env tenha as variáveis necessárias dos MCPs */
|
|
188
|
+
async function ensureEnvFile(envVars) {
|
|
189
|
+
const envPath = path.resolve(".env");
|
|
190
|
+
// Lê .env existente
|
|
191
|
+
let existing = '';
|
|
192
|
+
if (await fs.pathExists(envPath)) {
|
|
193
|
+
existing = await fs.readFile(envPath, "utf8");
|
|
194
|
+
}
|
|
195
|
+
// Descobre quais chaves já existem
|
|
196
|
+
const existingKeys = new Set();
|
|
197
|
+
for (const line of existing.split('\n')) {
|
|
198
|
+
const match = line.match(/^([A-Z_][A-Z0-9_]*)=/);
|
|
199
|
+
if (match)
|
|
200
|
+
existingKeys.add(match[1]);
|
|
201
|
+
}
|
|
202
|
+
// Filtra só as que faltam
|
|
203
|
+
const missing = [];
|
|
204
|
+
for (const [key, mcp] of envVars) {
|
|
205
|
+
if (!existingKeys.has(key)) {
|
|
206
|
+
missing.push({ key, mcp });
|
|
191
207
|
}
|
|
192
208
|
}
|
|
193
|
-
|
|
194
|
-
const hasMcps = foundMcps.length > 0;
|
|
195
|
-
if (!hasSkills && !hasMcps) {
|
|
196
|
-
console.log(" Nenhuma skill ou MCP instalado.\n");
|
|
209
|
+
if (missing.length === 0)
|
|
197
210
|
return;
|
|
211
|
+
// Monta as linhas novas
|
|
212
|
+
const lines = [];
|
|
213
|
+
if (existing.length > 0 && !existing.endsWith('\n')) {
|
|
214
|
+
lines.push('');
|
|
198
215
|
}
|
|
199
|
-
//
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
216
|
+
// Agrupa por MCP
|
|
217
|
+
const byMcp = new Map();
|
|
218
|
+
for (const { key, mcp } of missing) {
|
|
219
|
+
if (!byMcp.has(mcp))
|
|
220
|
+
byMcp.set(mcp, []);
|
|
221
|
+
byMcp.get(mcp).push(key);
|
|
206
222
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
for (const m of foundMcps) {
|
|
212
|
-
console.log(` ${ANSI.dim}${m.file}${ANSI.reset}`);
|
|
223
|
+
for (const [mcp, keys] of byMcp) {
|
|
224
|
+
lines.push(`# ${mcp}`);
|
|
225
|
+
for (const key of keys) {
|
|
226
|
+
lines.push(`${key}=`);
|
|
213
227
|
}
|
|
228
|
+
lines.push('');
|
|
214
229
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
230
|
+
await fs.writeFile(envPath, existing + lines.join('\n'), "utf8");
|
|
231
|
+
console.log(`\n ${GREEN}✔${ANSI.reset} .env ${ANSI.dim}→ ${missing.map(m => m.key).join(', ')}${ANSI.reset}`);
|
|
232
|
+
console.log(` ${YELLOW}!${ANSI.reset} Preencha as variáveis no ${ANSI.bold}.env${ANSI.reset} antes de usar`);
|
|
233
|
+
}
|
|
234
|
+
// ── Clear ───────────────────────────────────────────────────────────────
|
|
235
|
+
/** Todas as pastas/arquivos que o CLI pode criar, por agent */
|
|
236
|
+
const AGENT_ROOTS = {
|
|
237
|
+
claude: [".claude", ".mcp.json"],
|
|
238
|
+
codex: [".codex"],
|
|
239
|
+
gemini: [".gemini"],
|
|
240
|
+
copilot: [".github", ".vscode"],
|
|
241
|
+
};
|
|
242
|
+
async function clearFlow() {
|
|
243
|
+
// Descobre o que existe
|
|
244
|
+
const found = [];
|
|
245
|
+
const seen = new Set();
|
|
246
|
+
for (const [agent, paths] of Object.entries(AGENT_ROOTS)) {
|
|
247
|
+
for (const p of paths) {
|
|
248
|
+
if (seen.has(p))
|
|
249
|
+
continue;
|
|
250
|
+
seen.add(p);
|
|
251
|
+
const full = path.resolve(p);
|
|
252
|
+
if (await fs.pathExists(full)) {
|
|
253
|
+
found.push({ label: `${agent} → ${p}`, fullPath: full });
|
|
254
|
+
}
|
|
255
|
+
}
|
|
219
256
|
}
|
|
220
|
-
|
|
221
|
-
|
|
257
|
+
if (found.length === 0) {
|
|
258
|
+
console.log(" Nenhuma pasta ou arquivo de agent encontrado.\n");
|
|
259
|
+
return;
|
|
222
260
|
}
|
|
223
|
-
|
|
224
|
-
|
|
261
|
+
// Mostra o que vai ser removido
|
|
262
|
+
console.log(` ${RED}⚠${ANSI.reset} Será removido:\n`);
|
|
263
|
+
for (const f of found) {
|
|
264
|
+
console.log(` ${RED}✖${ANSI.reset} ${ANSI.dim}${f.fullPath}${ANSI.reset}`);
|
|
225
265
|
}
|
|
226
|
-
|
|
227
|
-
{
|
|
228
|
-
type: "list",
|
|
229
|
-
name: "action",
|
|
230
|
-
message: "O que deseja remover?",
|
|
231
|
-
choices,
|
|
232
|
-
theme: sysTheme
|
|
233
|
-
}
|
|
234
|
-
]);
|
|
235
|
-
const removeSkills = action === "all" || action === "skills";
|
|
236
|
-
const removeMcps = action === "all" || action === "mcps";
|
|
237
|
-
// Confirmação
|
|
238
|
-
const target = action === "all" ? "skills e MCPs" : action === "skills" ? "skills" : "MCPs";
|
|
266
|
+
console.log('');
|
|
239
267
|
const { confirm } = await inquirer.prompt([
|
|
240
268
|
{
|
|
241
269
|
type: "confirm",
|
|
242
270
|
name: "confirm",
|
|
243
|
-
message:
|
|
271
|
+
message: "Confirma a remoção de TUDO?",
|
|
244
272
|
default: false,
|
|
245
273
|
theme: sysTheme
|
|
246
274
|
}
|
|
@@ -250,19 +278,11 @@ async function clearFlow() {
|
|
|
250
278
|
return;
|
|
251
279
|
}
|
|
252
280
|
console.log('');
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
console.log(` ${RED}✖${ANSI.reset} ${ANSI.dim}${s.dir}${ANSI.reset}`);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
if (removeMcps) {
|
|
260
|
-
for (const m of foundMcps) {
|
|
261
|
-
await fs.remove(m.file);
|
|
262
|
-
console.log(` ${RED}✖${ANSI.reset} ${ANSI.dim}${m.file}${ANSI.reset}`);
|
|
263
|
-
}
|
|
281
|
+
for (const f of found) {
|
|
282
|
+
await fs.remove(f.fullPath);
|
|
283
|
+
console.log(` ${RED}✖${ANSI.reset} ${ANSI.dim}${f.fullPath}${ANSI.reset} removido`);
|
|
264
284
|
}
|
|
265
|
-
console.log("\n
|
|
285
|
+
console.log("\n Projeto limpo.\n");
|
|
266
286
|
}
|
|
267
287
|
// ── Main ────────────────────────────────────────────────────────────────
|
|
268
288
|
async function main() {
|