@ruyfranca/myskills 1.0.33 → 1.0.35

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,9 +1,9 @@
1
1
  ---
2
- name: sdd-spec-writer
3
- description: Specification writer for Spec-Driven Development (SDD) creates executable specifications that serve as unambiguous contracts.
4
- tools: Read, Grep, Glob, Bash
5
- model: inherit
6
- skills: sdd-spec-writer, clean-code, writing-plans
2
+ name: "sdd-spec-writer"
3
+ description: "Specification writer for Spec-Driven Development (SDD) - creates executable specifications that serve as unambiguous contracts."
4
+ tools: "Read, Grep, Glob, Bash"
5
+ model: "inherit"
6
+ skills: "sdd-spec-writer, clean-code, writing-plans"
7
7
  ---
8
8
 
9
9
  # SDD Spec Writer
@@ -1,6 +1,6 @@
1
1
  ---
2
- name: SDD Spec Writer
3
- description: Specification writing methodology for Spec-Driven Development (SDD)
2
+ name: "SDD Spec Writer"
3
+ description: "Specification writing methodology for Spec-Driven Development (SDD)"
4
4
  ---
5
5
 
6
6
  # SDD Spec Writer Skill
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Spec-Driven Development format. Create a clear spec contract for a task.
2
+ description: "Spec-Driven Development format. Create a clear spec contract for a task."
3
3
  ---
4
4
 
5
5
  # /sdd-spec Workflow
package/index.js CHANGED
@@ -2,10 +2,11 @@
2
2
 
3
3
  import { Command } from 'commander';
4
4
  import chalk from 'chalk';
5
- import fs from 'fs-extra';
5
+ import fs from 'fs/promises';
6
+ import { existsSync, statSync } from 'fs';
6
7
  import path from 'path';
7
8
  import { fileURLToPath } from 'url';
8
- import inquirer from 'inquirer';
9
+ import * as readline from 'readline/promises';
9
10
 
10
11
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
12
  const program = new Command();
@@ -16,7 +17,39 @@ const AGENTS_DIR = path.join(__dirname, '.agent', 'agents');
16
17
  program
17
18
  .name('myskills')
18
19
  .description('CLI para gerenciar e instalar skills e agents do Antigravity')
19
- .version('1.0.33');
20
+ .version('1.0.34');
21
+
22
+ // Helper para copiar pastas recursivamente
23
+ async function copyRecursively(src, dest) {
24
+ const stat = await fs.stat(src);
25
+ if (stat.isDirectory()) {
26
+ await fs.mkdir(dest, { recursive: true });
27
+ const entries = await fs.readdir(src);
28
+ for (const entry of entries) {
29
+ await copyRecursively(path.join(src, entry), path.join(dest, entry));
30
+ }
31
+ } else {
32
+ // Para simplificar, substitui se existir
33
+ await fs.copyFile(src, dest);
34
+ }
35
+ }
36
+
37
+ // Helper para substituir inquirer.prompt
38
+ async function promptList(message, choices) {
39
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
40
+ console.log(chalk.bold(`\n${message}`));
41
+ choices.forEach((c, idx) => console.log(` ${chalk.cyan(idx + 1)}) ${c}`));
42
+
43
+ while (true) {
44
+ const answer = await rl.question(chalk.yellow('\nDigite o número da opção desejada: '));
45
+ const num = parseInt(answer.trim(), 10);
46
+ if (!isNaN(num) && num > 0 && num <= choices.length) {
47
+ rl.close();
48
+ return choices[num - 1];
49
+ }
50
+ console.log(chalk.red('❌ Opção inválida, tente novamente digitando o número correspondente.'));
51
+ }
52
+ }
20
53
 
21
54
  program
22
55
  .command('list')
@@ -25,7 +58,7 @@ program
25
58
  const skills = await fs.readdir(SKILLS_DIR);
26
59
  console.log(chalk.cyan.bold('\n🚀 Skills Disponíveis:\n'));
27
60
  skills.forEach(skill => {
28
- if (fs.statSync(path.join(SKILLS_DIR, skill)).isDirectory()) {
61
+ if (statSync(path.join(SKILLS_DIR, skill)).isDirectory()) {
29
62
  console.log(` - ${chalk.green(skill)}`);
30
63
  }
31
64
  });
@@ -36,7 +69,7 @@ program
36
69
  .command('list-agents')
37
70
  .description('Lista todos os agents disponíveis na biblioteca')
38
71
  .action(async () => {
39
- if (!await fs.pathExists(AGENTS_DIR)) {
72
+ if (!existsSync(AGENTS_DIR)) {
40
73
  console.log(chalk.yellow('\n⚠️ Nenhum agent disponível ainda.\n'));
41
74
  return;
42
75
  }
@@ -61,18 +94,16 @@ program
61
94
  console.log(chalk.cyan('\n🚀 Inicializando kit completo do Antigravity...\n'));
62
95
 
63
96
  try {
64
- // Copy .agent/ folder (skills, agents, workflows, rules, scripts)
65
- await fs.ensureDir(destAgentDir);
66
- await fs.copy(sourceAgentDir, destAgentDir);
97
+ await fs.mkdir(destAgentDir, { recursive: true });
98
+ await copyRecursively(sourceAgentDir, destAgentDir);
67
99
  console.log(chalk.green(' ✅ Pasta .agent instalada!'));
68
100
 
69
- // Copy root rule files so Antigravity picks them up automatically
70
101
  const rootRuleFiles = ['AGENTS.md', 'GEMINI.md'];
71
102
  for (const ruleFile of rootRuleFiles) {
72
103
  const src = path.join(__dirname, ruleFile);
73
104
  const dest = path.join(destRoot, ruleFile);
74
- if (await fs.pathExists(src)) {
75
- await fs.copy(src, dest, { overwrite: true });
105
+ if (existsSync(src)) {
106
+ await copyRecursively(src, dest);
76
107
  console.log(chalk.green(` ✅ ${ruleFile} instalado na raiz!`));
77
108
  }
78
109
  }
@@ -93,7 +124,7 @@ program
93
124
  .action(async (name, options) => {
94
125
  if (options.all) {
95
126
  const skills = (await fs.readdir(SKILLS_DIR)).filter(s =>
96
- fs.statSync(path.join(SKILLS_DIR, s)).isDirectory()
127
+ statSync(path.join(SKILLS_DIR, s)).isDirectory()
97
128
  );
98
129
  console.log(chalk.cyan(`\n📦 Instalando todas as ${skills.length} skills...\n`));
99
130
 
@@ -102,8 +133,8 @@ program
102
133
  const destDir = path.join(process.cwd(), '.agent', 'skills', s);
103
134
 
104
135
  try {
105
- await fs.ensureDir(path.dirname(destDir));
106
- await fs.copy(sourceDir, destDir);
136
+ await fs.mkdir(path.dirname(destDir), { recursive: true });
137
+ await copyRecursively(sourceDir, destDir);
107
138
  console.log(` - ${chalk.green(s)}: ${chalk.gray('OK')}`);
108
139
  } catch (err) {
109
140
  console.error(chalk.red(` - ${s}: Erro - ${err.message}`));
@@ -119,15 +150,7 @@ program
119
150
  const agentNames = agents.map(a => a.replace('.md', ''));
120
151
 
121
152
  if (!name) {
122
- const answers = await inquirer.prompt([
123
- {
124
- type: 'list',
125
- name: 'selectedAgent',
126
- message: 'Qual agent você deseja adicionar?',
127
- choices: agentNames
128
- }
129
- ]);
130
- name = answers.selectedAgent;
153
+ name = await promptList('📋 Qual agent você deseja adicionar?', agentNames);
131
154
  }
132
155
 
133
156
  if (!agentNames.includes(name)) {
@@ -139,8 +162,8 @@ program
139
162
  const destFile = path.join(process.cwd(), '.agent', 'agents', `${name}.md`);
140
163
 
141
164
  try {
142
- await fs.ensureDir(path.dirname(destFile));
143
- await fs.copy(sourceFile, destFile);
165
+ await fs.mkdir(path.dirname(destFile), { recursive: true });
166
+ await copyRecursively(sourceFile, destFile);
144
167
  console.log(chalk.green(`\n✅ Agent "${name}" instalado com sucesso em .agent/agents/${name}.md!\n`));
145
168
  } catch (err) {
146
169
  console.error(chalk.red(`\n❌ Erro ao copiar agent: ${err.message}\n`));
@@ -150,19 +173,11 @@ program
150
173
 
151
174
  // Default: Skill
152
175
  const skills = (await fs.readdir(SKILLS_DIR)).filter(s =>
153
- fs.statSync(path.join(SKILLS_DIR, s)).isDirectory()
176
+ statSync(path.join(SKILLS_DIR, s)).isDirectory()
154
177
  );
155
178
 
156
179
  if (!name) {
157
- const answers = await inquirer.prompt([
158
- {
159
- type: 'list',
160
- name: 'selectedSkill',
161
- message: 'Qual skill você deseja adicionar?',
162
- choices: skills
163
- }
164
- ]);
165
- name = answers.selectedSkill;
180
+ name = await promptList('📋 Qual skill você deseja adicionar?', skills);
166
181
  }
167
182
 
168
183
  if (!skills.includes(name)) {
@@ -174,8 +189,8 @@ program
174
189
  const destDir = path.join(process.cwd(), '.agent', 'skills', name);
175
190
 
176
191
  try {
177
- await fs.ensureDir(path.dirname(destDir));
178
- await fs.copy(sourceDir, destDir);
192
+ await fs.mkdir(path.dirname(destDir), { recursive: true });
193
+ await copyRecursively(sourceDir, destDir);
179
194
  console.log(chalk.green(`\n✅ Skill "${name}" instalada com sucesso em .agent/skills/${name}!\n`));
180
195
  } catch (err) {
181
196
  console.error(chalk.red(`\n❌ Erro ao copiar skill: ${err.message}\n`));
@@ -209,13 +224,13 @@ program
209
224
  }
210
225
 
211
226
  for (const task of tasks) {
212
- if (!await fs.pathExists(task.src)) {
227
+ if (!existsSync(task.src)) {
213
228
  console.log(chalk.yellow(` ⚠️ Fonte não encontrada: ${task.label} (${task.src})`));
214
229
  continue;
215
230
  }
216
231
  try {
217
- await fs.ensureDir(task.dest);
218
- await fs.copy(task.src, task.dest, { overwrite: true });
232
+ await fs.mkdir(task.dest, { recursive: true });
233
+ await copyRecursively(task.src, task.dest);
219
234
  console.log(chalk.green(` ✅ ${task.label}: copiado`));
220
235
  } catch (err) {
221
236
  console.error(chalk.red(` ❌ ${task.label}: erro na cópia — ${err.message}`));
@@ -223,7 +238,6 @@ program
223
238
  }
224
239
  }
225
240
 
226
- // Rewrite hardcoded paths (file:///...mySkills...) to point to the dest project
227
241
  if (destRoot !== srcRoot) {
228
242
  console.log(chalk.cyan('\n🔧 Corrigindo paths nos arquivos copiados...\n'));
229
243
 
@@ -240,7 +254,7 @@ program
240
254
  let fixedFiles = 0;
241
255
 
242
256
  for (const dir of dirsToFix) {
243
- if (!await fs.pathExists(dir)) continue;
257
+ if (!existsSync(dir)) continue;
244
258
 
245
259
  const walk = async (currentDir) => {
246
260
  const entries = await fs.readdir(currentDir, { withFileTypes: true });
@@ -257,7 +271,7 @@ program
257
271
  fixedFiles++;
258
272
  }
259
273
  } catch {
260
- // ignorar arquivos binários ou inacessíveis
274
+ // ignorar
261
275
  }
262
276
  }
263
277
  }
@@ -273,15 +287,14 @@ program
273
287
  }
274
288
  }
275
289
 
276
- // Update root rule files (AGENTS.md, GEMINI.md)
277
290
  if (updateAll || options.rules) {
278
291
  const rootRuleFiles = ['AGENTS.md', 'GEMINI.md'];
279
292
  for (const ruleFile of rootRuleFiles) {
280
293
  const src = path.join(srcRoot, ruleFile);
281
294
  const dest = path.join(destRoot, ruleFile);
282
- if (await fs.pathExists(src)) {
295
+ if (existsSync(src)) {
283
296
  try {
284
- await fs.copy(src, dest, { overwrite: true });
297
+ await copyRecursively(src, dest);
285
298
  console.log(chalk.green(` ✅ ${ruleFile}: atualizado na raiz`));
286
299
  } catch (err) {
287
300
  console.error(chalk.red(` ❌ ${ruleFile}: ${err.message}`));
@@ -290,20 +303,19 @@ program
290
303
  }
291
304
  }
292
305
 
293
- // Instalar workflows globalmente para aparecerem no / do Antigravity
294
306
  if (updateAll || options.workflows) {
295
307
  const homeDir = process.env.HOME || process.env.USERPROFILE || '';
296
308
  const globalWorkflowsDir = path.join(homeDir, '.gemini', 'antigravity', 'global_workflows');
297
309
  const workflowsSrc = path.join(srcRoot, '.agent', 'workflows');
298
310
 
299
- if (await fs.pathExists(workflowsSrc)) {
311
+ if (existsSync(workflowsSrc)) {
300
312
  try {
301
- await fs.ensureDir(globalWorkflowsDir);
313
+ await fs.mkdir(globalWorkflowsDir, { recursive: true });
302
314
  const files = await fs.readdir(workflowsSrc);
303
315
  let copied = 0;
304
316
  for (const file of files) {
305
317
  if (file.endsWith('.md')) {
306
- await fs.copy(path.join(workflowsSrc, file), path.join(globalWorkflowsDir, file), { overwrite: true });
318
+ await copyRecursively(path.join(workflowsSrc, file), path.join(globalWorkflowsDir, file));
307
319
  copied++;
308
320
  }
309
321
  }
@@ -315,7 +327,6 @@ program
315
327
  }
316
328
 
317
329
  console.log(chalk.cyan.bold('\n✨ Atualização concluída!\n'));
318
- console.log(chalk.gray('💡 Dica: reinicie o Antigravity para que o / exiba os workflows.\n'));
319
330
  });
320
331
 
321
332
  program
@@ -329,12 +340,12 @@ program
329
340
  console.log(chalk.cyan('\n🌐 Instalando workflows globalmente...\n'));
330
341
 
331
342
  try {
332
- await fs.ensureDir(globalWorkflowsDir);
343
+ await fs.mkdir(globalWorkflowsDir, { recursive: true });
333
344
  const files = await fs.readdir(workflowsSrc);
334
345
  let copied = 0;
335
346
  for (const file of files) {
336
347
  if (file.endsWith('.md')) {
337
- await fs.copy(path.join(workflowsSrc, file), path.join(globalWorkflowsDir, file), { overwrite: true });
348
+ await copyRecursively(path.join(workflowsSrc, file), path.join(globalWorkflowsDir, file));
338
349
  copied++;
339
350
  }
340
351
  }
@@ -345,7 +356,4 @@ program
345
356
  }
346
357
  });
347
358
 
348
-
349
-
350
359
  program.parse();
351
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ruyfranca/myskills",
3
- "version": "1.0.33",
3
+ "version": "1.0.35",
4
4
  "description": "Biblioteca de skills customizadas para Antigravity / Claude Code",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -21,8 +21,6 @@
21
21
  "license": "MIT",
22
22
  "dependencies": {
23
23
  "chalk": "^5.3.0",
24
- "commander": "^12.0.0",
25
- "fs-extra": "^11.2.0",
26
- "inquirer": "^9.2.15"
24
+ "commander": "^12.0.0"
27
25
  }
28
26
  }
package/test-yaml.js ADDED
@@ -0,0 +1,31 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ function checkDir(dir) {
5
+ let files = fs.readdirSync(dir, { withFileTypes: true });
6
+ for (let f of files) {
7
+ let full = path.join(dir, f.name);
8
+ if (f.isDirectory()) {
9
+ checkDir(full);
10
+ } else if (f.name.endsWith('.md')) {
11
+ let content = fs.readFileSync(full, 'utf8');
12
+ if (content.startsWith('---')) {
13
+ let closing = content.indexOf('\n---', 3);
14
+ if (closing === -1) {
15
+ console.log('Error: No closing --- in', full);
16
+ } else {
17
+ // extract
18
+ let yamlStr = content.substring(4, closing);
19
+ // check if there's another block immediately following
20
+ let rest = content.substring(closing + 4).trimStart();
21
+ if (rest.startsWith('---')) {
22
+ console.log('Error: Duplicate frontmatter block in', full);
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
28
+ }
29
+
30
+ checkDir('.agent');
31
+ console.log('Done checking.');