@sysvv/ai-skill 1.0.0 → 1.2.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.
Files changed (2) hide show
  1. package/dist/index.js +173 -15
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -2,23 +2,115 @@
2
2
  import inquirer from "inquirer";
3
3
  import fs from "fs-extra";
4
4
  import path from "node:path";
5
+ import { readFileSync } from "node:fs";
6
+ import { fileURLToPath } from "node:url";
5
7
  import { findSkillFiles } from "./core/registry.js";
6
8
  import { parseSkillFile } from "./core/frontmatter.js";
7
9
  import { loadSkill } from "./core/skill.js";
10
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
+ // ── ANSI ────────────────────────────────────────────────────────────────
12
+ const ANSI = {
13
+ bold: '\x1b[1m',
14
+ dim: '\x1b[2m',
15
+ reset: '\x1b[0m',
16
+ };
17
+ const PINK = '\x1b[38;2;238;54;141m';
18
+ const BLUE = '\x1b[38;2;14;93;171m';
19
+ const RED = '\x1b[38;2;255;70;70m';
20
+ const GREEN = '\x1b[38;2;80;200;120m';
21
+ const WHITE = '\x1b[97m';
22
+ // ── Inquirer Theme ──────────────────────────────────────────────────────
23
+ const sysTheme = {
24
+ icon: {
25
+ cursor: PINK + '❯' + ANSI.reset,
26
+ checked: PINK + '◉' + ANSI.reset,
27
+ unchecked: ANSI.dim + '○' + ANSI.reset,
28
+ },
29
+ style: {
30
+ highlight: (text) => PINK + ANSI.bold + text + ANSI.reset,
31
+ answer: (text) => BLUE + ANSI.bold + text + ANSI.reset,
32
+ message: (text) => WHITE + ANSI.bold + text + ANSI.reset,
33
+ },
34
+ helpMode: 'always',
35
+ };
36
+ // ── ASCII Art Letters (7 lines, bigger) ─────────────────────────────────
37
+ const LETTERS = {
38
+ A: [' ██████ ', ' ██ ██ ', '██ ██', '██████████', '██ ██', '██ ██', '██ ██'],
39
+ I: ['████', ' ██ ', ' ██ ', ' ██ ', ' ██ ', ' ██ ', '████'],
40
+ K: ['██ ██', '██ ██ ', '██ ██ ', '█████ ', '██ ██ ', '██ ██ ', '██ ██'],
41
+ L: ['██ ', '██ ', '██ ', '██ ', '██ ', '██ ', '█████████'],
42
+ S: [' ████████ ', '██ ', '██ ', ' ████████ ', ' ██ ', ' ██ ', ' ████████ '],
43
+ Y: ['██ ██', ' ██ ██ ', ' ██ ██ ', ' ███ ', ' ███ ', ' ███ ', ' ███ '],
44
+ };
45
+ function joinLetters(keys, gap = ' ') {
46
+ const letters = keys.map(k => LETTERS[k]);
47
+ return Array.from({ length: 7 }, (_, i) => letters.map(l => l[i]).join(gap));
48
+ }
49
+ function centerPad(line, totalWidth) {
50
+ const spaces = Math.max(0, Math.floor((totalWidth - line.length) / 2));
51
+ return ' '.repeat(spaces) + line;
52
+ }
53
+ function showBanner() {
54
+ let version = '0.0.0';
55
+ try {
56
+ const pkg = JSON.parse(readFileSync(path.join(__dirname, '../package.json'), 'utf8'));
57
+ version = pkg.version;
58
+ }
59
+ catch { /* ignore */ }
60
+ const sysLines = joinLetters(['S', 'Y', 'S']);
61
+ const aiLines = joinLetters(['A', 'I']);
62
+ const skillsLines = joinLetters(['S', 'K', 'I', 'L', 'L', 'S']);
63
+ const maxWidth = Math.max(sysLines[0].length, aiLines[0].length, skillsLines[0].length);
64
+ const indent = ' ';
65
+ const separator = ANSI.dim + indent + centerPad('─'.repeat(maxWidth), maxWidth) + ANSI.reset;
66
+ console.log('');
67
+ console.log('');
68
+ for (const line of sysLines) {
69
+ console.log(indent + PINK + ANSI.bold + centerPad(line, maxWidth) + ANSI.reset);
70
+ }
71
+ console.log('');
72
+ for (const line of aiLines) {
73
+ console.log(indent + BLUE + ANSI.bold + centerPad(line, maxWidth) + ANSI.reset);
74
+ }
75
+ console.log('');
76
+ for (const line of skillsLines) {
77
+ console.log(indent + BLUE + centerPad(line, maxWidth) + ANSI.reset);
78
+ }
79
+ console.log('');
80
+ console.log(separator);
81
+ console.log('');
82
+ console.log(indent + WHITE + ANSI.bold + centerPad(`v${version}`, maxWidth) + ANSI.reset);
83
+ console.log('');
84
+ const desc = 'Skills para turbinar seus agentes de codigo';
85
+ const boxInner = desc.length + 4;
86
+ console.log(indent + ANSI.dim + centerPad('┌' + '─'.repeat(boxInner) + '┐', maxWidth) + ANSI.reset);
87
+ console.log(indent + ANSI.dim + centerPad('│ ' + WHITE + desc + ANSI.reset + ANSI.dim + ' │', maxWidth) + ANSI.reset);
88
+ console.log(indent + ANSI.dim + centerPad('└' + '─'.repeat(boxInner) + '┘', maxWidth) + ANSI.reset);
89
+ console.log('');
90
+ console.log(indent + ANSI.dim + centerPad('npx @sysvv/ai-skill --claude | --codex | --gemini | --clear', maxWidth) + ANSI.reset);
91
+ console.log('');
92
+ console.log(separator);
93
+ console.log('');
94
+ }
95
+ // ── Config ──────────────────────────────────────────────────────────────
8
96
  const AGENT_DIRS = {
9
97
  claude: ".claude/skills",
10
98
  codex: ".codex/skills",
11
99
  gemini: ".gemini/skills",
12
100
  };
13
- async function main() {
14
- const { agent } = await inquirer.prompt([
15
- {
16
- type: "list",
17
- name: "agent",
18
- message: "Qual IA você usa?",
19
- choices: Object.keys(AGENT_DIRS)
20
- }
21
- ]);
101
+ // ── Parse args ──────────────────────────────────────────────────────────
102
+ function parseArgs() {
103
+ const args = process.argv.slice(2);
104
+ if (args.includes("--clear"))
105
+ return { clear: true };
106
+ for (const key of Object.keys(AGENT_DIRS)) {
107
+ if (args.includes(`--${key}`))
108
+ return { agent: key };
109
+ }
110
+ return {};
111
+ }
112
+ // ── Install skills for agent ────────────────────────────────────────────
113
+ async function installSkills(agent) {
22
114
  const skillFiles = await findSkillFiles();
23
115
  const available = [];
24
116
  for (const file of skillFiles) {
@@ -32,30 +124,96 @@ async function main() {
32
124
  });
33
125
  }
34
126
  if (available.length === 0) {
35
- console.log("Nenhuma skill encontrada.");
127
+ console.log(" Nenhuma skill encontrada.");
36
128
  process.exit(1);
37
129
  }
38
130
  const { selected } = await inquirer.prompt([
39
131
  {
40
132
  type: "checkbox",
41
133
  name: "selected",
42
- message: "Escolha as skills que deseja instalar:",
134
+ message: "Escolha as skills:",
43
135
  choices: available.map((s) => ({
44
- name: `${s.title} — ${s.description}`,
136
+ name: `${s.title} ${ANSI.dim}— ${s.description}${ANSI.reset}`,
45
137
  value: s.file
46
138
  })),
47
- validate: (answer) => answer.length > 0 ? true : "Selecione pelo menos uma skill."
139
+ validate: (answer) => answer.length > 0 ? true : "Selecione pelo menos uma skill.",
140
+ theme: sysTheme
48
141
  }
49
142
  ]);
50
143
  const destBase = path.resolve(AGENT_DIRS[agent]);
144
+ console.log('');
51
145
  for (const file of selected) {
52
146
  const skill = await loadSkill(file, agent);
53
147
  const skillDir = path.join(destBase, skill.metadata.name);
54
148
  await fs.ensureDir(skillDir);
55
149
  await fs.writeFile(path.join(skillDir, "SKILL.md"), skill.renderedBody, "utf8");
56
- console.log(` ${skill.metadata.name}`);
150
+ console.log(` ${GREEN}✔${ANSI.reset} ${skill.metadata.name}`);
151
+ }
152
+ console.log(`\n Skills instaladas em ${ANSI.bold}${destBase}/${ANSI.reset}\n`);
153
+ }
154
+ // ── Clear all skills ────────────────────────────────────────────────────
155
+ async function clearSkills() {
156
+ const existing = [];
157
+ for (const [agent, dir] of Object.entries(AGENT_DIRS)) {
158
+ const full = path.resolve(dir);
159
+ if (await fs.pathExists(full)) {
160
+ existing.push(agent);
161
+ }
162
+ }
163
+ if (existing.length === 0) {
164
+ console.log(" Nenhuma pasta de skills encontrada.\n");
165
+ return;
166
+ }
167
+ console.log(` ${RED}⚠${ANSI.reset} Pastas encontradas:\n`);
168
+ for (const agent of existing) {
169
+ console.log(` ${ANSI.dim}${path.resolve(AGENT_DIRS[agent])}${ANSI.reset}`);
170
+ }
171
+ console.log('');
172
+ const { confirm } = await inquirer.prompt([
173
+ {
174
+ type: "confirm",
175
+ name: "confirm",
176
+ message: "Tem certeza que deseja apagar TODAS as pastas de skills?",
177
+ default: false,
178
+ theme: sysTheme
179
+ }
180
+ ]);
181
+ if (!confirm) {
182
+ console.log("\n Operação cancelada.\n");
183
+ return;
57
184
  }
58
- console.log(`\nSkills instaladas em ${destBase}/\n`);
185
+ for (const agent of existing) {
186
+ const full = path.resolve(AGENT_DIRS[agent]);
187
+ await fs.remove(full);
188
+ console.log(` ${RED}✖${ANSI.reset} ${full} removida`);
189
+ }
190
+ console.log("\n Todas as skills foram removidas.\n");
191
+ }
192
+ // ── Main ────────────────────────────────────────────────────────────────
193
+ async function main() {
194
+ showBanner();
195
+ const { agent, clear } = parseArgs();
196
+ if (clear) {
197
+ await clearSkills();
198
+ return;
199
+ }
200
+ if (agent) {
201
+ await installSkills(agent);
202
+ return;
203
+ }
204
+ const { chosenAgent } = await inquirer.prompt([
205
+ {
206
+ type: "list",
207
+ name: "chosenAgent",
208
+ message: "Qual IA você usa?",
209
+ choices: Object.keys(AGENT_DIRS).map((key) => ({
210
+ name: `${ANSI.bold}${key.charAt(0).toUpperCase() + key.slice(1)}${ANSI.reset}`,
211
+ value: key
212
+ })),
213
+ theme: sysTheme
214
+ }
215
+ ]);
216
+ await installSkills(chosenAgent);
59
217
  }
60
218
  main().catch((err) => {
61
219
  console.error("Erro:", err.message);
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@sysvv/ai-skill",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "Instale skills de IA direto no seu projeto. Escolha o agent, escolha as skills.",
5
5
  "type": "module",
6
6
  "bin": {
7
- "ai-skill": "./dist/index.js"
7
+ "ai-skill": "dist/index.js"
8
8
  },
9
9
  "files": [
10
10
  "dist",