claudiao 1.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.
Files changed (68) hide show
  1. package/README.md +387 -0
  2. package/dist/commands/create.d.ts +2 -0
  3. package/dist/commands/create.js +260 -0
  4. package/dist/commands/doctor.d.ts +1 -0
  5. package/dist/commands/doctor.js +138 -0
  6. package/dist/commands/init.d.ts +3 -0
  7. package/dist/commands/init.js +252 -0
  8. package/dist/commands/install-plugin.d.ts +1 -0
  9. package/dist/commands/install-plugin.js +35 -0
  10. package/dist/commands/list.d.ts +3 -0
  11. package/dist/commands/list.js +123 -0
  12. package/dist/commands/remove.d.ts +6 -0
  13. package/dist/commands/remove.js +121 -0
  14. package/dist/commands/update.d.ts +4 -0
  15. package/dist/commands/update.js +141 -0
  16. package/dist/index.d.ts +2 -0
  17. package/dist/index.js +156 -0
  18. package/dist/lib/__tests__/frontmatter.test.d.ts +1 -0
  19. package/dist/lib/__tests__/frontmatter.test.js +180 -0
  20. package/dist/lib/__tests__/paths.test.d.ts +1 -0
  21. package/dist/lib/__tests__/paths.test.js +29 -0
  22. package/dist/lib/__tests__/symlinks.test.d.ts +1 -0
  23. package/dist/lib/__tests__/symlinks.test.js +142 -0
  24. package/dist/lib/format.d.ts +13 -0
  25. package/dist/lib/format.js +47 -0
  26. package/dist/lib/frontmatter.d.ts +9 -0
  27. package/dist/lib/frontmatter.js +45 -0
  28. package/dist/lib/paths.d.ts +33 -0
  29. package/dist/lib/paths.js +111 -0
  30. package/dist/lib/plugins.d.ts +3 -0
  31. package/dist/lib/plugins.js +24 -0
  32. package/dist/lib/symlinks.d.ts +8 -0
  33. package/dist/lib/symlinks.js +56 -0
  34. package/dist/lib/templates.d.ts +26 -0
  35. package/dist/lib/templates.js +75 -0
  36. package/dist/types.d.ts +25 -0
  37. package/dist/types.js +1 -0
  38. package/package.json +47 -0
  39. package/templates/CLAUDE-CODE-BEST-PRACTICES.md +508 -0
  40. package/templates/CLOUD-CLI-GUIDE.md +405 -0
  41. package/templates/agents/architect.md +128 -0
  42. package/templates/agents/aws-specialist.md +104 -0
  43. package/templates/agents/azure-specialist.md +117 -0
  44. package/templates/agents/database-specialist.md +104 -0
  45. package/templates/agents/dod-specialist.md +101 -0
  46. package/templates/agents/gcp-specialist.md +124 -0
  47. package/templates/agents/idea-refiner.md +146 -0
  48. package/templates/agents/implementation-planner.md +149 -0
  49. package/templates/agents/nodejs-specialist.md +105 -0
  50. package/templates/agents/pr-reviewer.md +132 -0
  51. package/templates/agents/product-owner.md +88 -0
  52. package/templates/agents/project-manager.md +95 -0
  53. package/templates/agents/prompt-engineer.md +115 -0
  54. package/templates/agents/python-specialist.md +103 -0
  55. package/templates/agents/react-specialist.md +94 -0
  56. package/templates/agents/security-specialist.md +145 -0
  57. package/templates/agents/test-specialist.md +157 -0
  58. package/templates/agents/uxui-specialist.md +102 -0
  59. package/templates/global-CLAUDE.md +100 -0
  60. package/templates/skills/architecture-decision/SKILL.md +102 -0
  61. package/templates/skills/meet-dod/SKILL.md +124 -0
  62. package/templates/skills/pm-templates/SKILL.md +125 -0
  63. package/templates/skills/pr-template/SKILL.md +87 -0
  64. package/templates/skills/product-templates/SKILL.md +97 -0
  65. package/templates/skills/python-patterns/SKILL.md +123 -0
  66. package/templates/skills/security-checklist/SKILL.md +80 -0
  67. package/templates/skills/sql-templates/SKILL.md +93 -0
  68. package/templates/skills/ui-review-checklist/SKILL.md +73 -0
@@ -0,0 +1,138 @@
1
+ import { existsSync, readdirSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { execSync } from 'node:child_process';
4
+ import chalk from 'chalk';
5
+ import { CLAUDE_DIR, CLAUDE_AGENTS_DIR, CLAUDE_SKILLS_DIR, CLAUDE_MD, CONFIG_FILE, getExternalRepoPath, getAgentsSource } from '../lib/paths.js';
6
+ import { isSymlink, getSymlinkTarget } from '../lib/symlinks.js';
7
+ import { banner, success, warn, error, heading } from '../lib/format.js';
8
+ export function doctor() {
9
+ banner();
10
+ heading('Diagnostico do claudiao');
11
+ let issues = 0;
12
+ // 1. Claude Code
13
+ try {
14
+ execSync('which claude', { stdio: 'pipe' });
15
+ success('Claude Code instalado');
16
+ }
17
+ catch {
18
+ warn('Claude Code nao encontrado no PATH');
19
+ console.log(chalk.dim(' Instale: npm install -g @anthropic-ai/claude-code'));
20
+ issues++;
21
+ }
22
+ // 2. ~/.claude/ exists
23
+ if (existsSync(CLAUDE_DIR)) {
24
+ success('~/.claude/ existe');
25
+ }
26
+ else {
27
+ error('~/.claude/ nao existe');
28
+ console.log(chalk.dim(' Rode: claudiao init'));
29
+ issues++;
30
+ }
31
+ // 3. CLAUDE.md global
32
+ if (existsSync(CLAUDE_MD)) {
33
+ if (isSymlink(CLAUDE_MD)) {
34
+ const target = getSymlinkTarget(CLAUDE_MD);
35
+ if (target && existsSync(target)) {
36
+ success(`CLAUDE.md global OK ${chalk.dim('→ ' + target)}`);
37
+ }
38
+ else {
39
+ error(`CLAUDE.md global: symlink quebrado → ${target}`);
40
+ issues++;
41
+ }
42
+ }
43
+ else {
44
+ warn('CLAUDE.md global existe mas nao e symlink (nao sera atualizado automaticamente)');
45
+ }
46
+ }
47
+ else {
48
+ warn('CLAUDE.md global nao instalado');
49
+ console.log(chalk.dim(' Rode: claudiao init'));
50
+ issues++;
51
+ }
52
+ // 4. Agents
53
+ if (existsSync(CLAUDE_AGENTS_DIR)) {
54
+ const agents = readdirSync(CLAUDE_AGENTS_DIR).filter(f => f.endsWith('.md'));
55
+ let broken = 0;
56
+ for (const agent of agents) {
57
+ const agentPath = join(CLAUDE_AGENTS_DIR, agent);
58
+ if (isSymlink(agentPath)) {
59
+ const target = getSymlinkTarget(agentPath);
60
+ if (!target || !existsSync(target)) {
61
+ error(`Agente ${agent}: symlink quebrado → ${target}`);
62
+ broken++;
63
+ }
64
+ }
65
+ }
66
+ if (broken === 0) {
67
+ success(`${agents.length} agentes instalados, todos OK`);
68
+ }
69
+ else {
70
+ error(`${broken} agente(s) com symlink quebrado`);
71
+ console.log(chalk.dim(' Rode: claudiao init (para reinstalar)'));
72
+ issues += broken;
73
+ }
74
+ }
75
+ else {
76
+ warn('Nenhum agente instalado');
77
+ issues++;
78
+ }
79
+ // 5. Skills
80
+ if (existsSync(CLAUDE_SKILLS_DIR)) {
81
+ const skills = readdirSync(CLAUDE_SKILLS_DIR, { withFileTypes: true })
82
+ .filter(d => d.isDirectory() || d.isSymbolicLink());
83
+ let broken = 0;
84
+ for (const skill of skills) {
85
+ const skillPath = join(CLAUDE_SKILLS_DIR, skill.name);
86
+ if (isSymlink(skillPath)) {
87
+ const target = getSymlinkTarget(skillPath);
88
+ if (!target || !existsSync(target)) {
89
+ error(`Skill ${skill.name}: symlink quebrado → ${target}`);
90
+ broken++;
91
+ }
92
+ }
93
+ const skillMd = join(skillPath, 'SKILL.md');
94
+ if (!existsSync(skillMd)) {
95
+ warn(`Skill ${skill.name}: falta SKILL.md`);
96
+ }
97
+ }
98
+ if (broken === 0) {
99
+ success(`${skills.length} skills instaladas, todas OK`);
100
+ }
101
+ else {
102
+ error(`${broken} skill(s) com symlink quebrado`);
103
+ issues += broken;
104
+ }
105
+ }
106
+ else {
107
+ warn('Nenhuma skill instalada');
108
+ issues++;
109
+ }
110
+ // 6. Config file
111
+ if (existsSync(CONFIG_FILE)) {
112
+ success('Config claudiao OK');
113
+ }
114
+ else {
115
+ warn('Config claudiao nao encontrado (nao e obrigatorio)');
116
+ }
117
+ // 7. Repo path
118
+ const repoPath = getExternalRepoPath();
119
+ if (repoPath) {
120
+ success(`Repo externo de agentes/skills: ${chalk.dim(repoPath)}`);
121
+ }
122
+ const agentsSource = getAgentsSource();
123
+ if (agentsSource) {
124
+ success(`Fonte de agentes: ${chalk.dim(agentsSource)}`);
125
+ }
126
+ else {
127
+ warn('Nenhuma fonte de agentes encontrada');
128
+ }
129
+ // Summary
130
+ console.log('');
131
+ if (issues === 0) {
132
+ console.log(chalk.green.bold(' Tudo certo! Nenhum problema encontrado.'));
133
+ }
134
+ else {
135
+ console.log(chalk.yellow.bold(` ${issues} problema(s) encontrado(s). Veja as sugestoes acima.`));
136
+ }
137
+ console.log('');
138
+ }
@@ -0,0 +1,3 @@
1
+ export declare function init(options?: {
2
+ dryRun?: boolean;
3
+ }): Promise<void>;
@@ -0,0 +1,252 @@
1
+ import { existsSync, readFileSync, writeFileSync, readdirSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import chalk from 'chalk';
4
+ import inquirer from 'inquirer';
5
+ import { CLAUDE_DIR, CLAUDE_AGENTS_DIR, CLAUDE_SKILLS_DIR, CLAUDE_MD, CONFIG_FILE, getAgentsSource, getSkillsSource, getGlobalMdSource, getExternalRepoPath, } from '../lib/paths.js';
6
+ import { createSymlink, ensureDir } from '../lib/symlinks.js';
7
+ import { parseAgentFile } from '../lib/frontmatter.js';
8
+ import { banner, success, warn, error, info, dim, heading, separator } from '../lib/format.js';
9
+ import { PLUGINS } from '../lib/plugins.js';
10
+ import { execSync } from 'node:child_process';
11
+ export async function init(options) {
12
+ const dryRun = options?.dryRun ?? false;
13
+ banner();
14
+ if (dryRun) {
15
+ info('[dry-run] Nenhuma alteracao sera feita');
16
+ console.log('');
17
+ }
18
+ // Check prerequisites
19
+ heading('Verificando pre-requisitos...');
20
+ const hasNode = process.version;
21
+ success(`Node.js ${hasNode}`);
22
+ if (!dryRun) {
23
+ try {
24
+ execSync('which claude', { stdio: 'pipe' });
25
+ success('Claude Code encontrado');
26
+ }
27
+ catch {
28
+ warn('Claude Code nao encontrado no PATH');
29
+ dim('Instale com: npm install -g @anthropic-ai/claude-code');
30
+ }
31
+ }
32
+ else {
33
+ info('[dry-run] Verificaria se Claude Code esta no PATH');
34
+ }
35
+ // Resolve sources
36
+ const agentsSource = getAgentsSource();
37
+ const skillsSource = getSkillsSource();
38
+ const globalMdSource = getGlobalMdSource();
39
+ // Create ~/.claude/
40
+ if (!dryRun) {
41
+ ensureDir(CLAUDE_DIR);
42
+ }
43
+ else {
44
+ info('[dry-run] Criaria diretorio ~/.claude/ (se nao existir)');
45
+ }
46
+ // [1/3] Install CLAUDE.md global
47
+ heading('[1/3] CLAUDE.md Global');
48
+ dim('Regras universais de codigo, git workflow, lista de agentes/skills');
49
+ console.log('');
50
+ if (globalMdSource) {
51
+ if (dryRun) {
52
+ info(`[dry-run] Linkaria ${globalMdSource} -> ~/.claude/CLAUDE.md`);
53
+ }
54
+ else {
55
+ const result = createSymlink(globalMdSource, CLAUDE_MD);
56
+ if (result.status === 'created' || result.status === 'backup') {
57
+ success('~/.claude/CLAUDE.md instalado');
58
+ }
59
+ else if (result.status === 'skipped') {
60
+ info('CLAUDE.md ja estava instalado');
61
+ }
62
+ }
63
+ }
64
+ else {
65
+ warn('global-CLAUDE.md nao encontrado');
66
+ }
67
+ // [2/3] Install agents
68
+ heading('[2/3] Agentes');
69
+ dim('Especialistas que o Claude Code invoca automaticamente pelo contexto');
70
+ console.log('');
71
+ let agentCount = 0;
72
+ if (agentsSource && existsSync(agentsSource)) {
73
+ if (!dryRun) {
74
+ ensureDir(CLAUDE_AGENTS_DIR);
75
+ }
76
+ const agentFiles = readdirSync(agentsSource).filter(f => f.endsWith('.md'));
77
+ agentCount = agentFiles.length;
78
+ if (dryRun) {
79
+ for (const file of agentFiles) {
80
+ const source = join(agentsSource, file);
81
+ try {
82
+ const meta = parseAgentFile(source);
83
+ info(`[dry-run] Linkaria agente: ${meta.name} ${chalk.dim('— ' + meta.description.slice(0, 60))}`);
84
+ }
85
+ catch {
86
+ info(`[dry-run] Linkaria agente: ${file.replace('.md', '')}`);
87
+ }
88
+ }
89
+ console.log('');
90
+ info(`[dry-run] ${agentCount} agentes seriam processados`);
91
+ }
92
+ else {
93
+ let installed = 0;
94
+ let skipped = 0;
95
+ for (const file of agentFiles) {
96
+ const source = join(agentsSource, file);
97
+ const target = join(CLAUDE_AGENTS_DIR, file);
98
+ try {
99
+ const meta = parseAgentFile(source);
100
+ const result = createSymlink(source, target);
101
+ if (result.status === 'created' || result.status === 'backup') {
102
+ success(`${meta.name} ${chalk.dim('— ' + meta.description.slice(0, 60))}`);
103
+ installed++;
104
+ }
105
+ else {
106
+ console.log(` ${chalk.yellow('⏭')} ${meta.name} ${chalk.dim('— ja instalado')}`);
107
+ skipped++;
108
+ }
109
+ }
110
+ catch {
111
+ const result = createSymlink(source, target);
112
+ if (result.status !== 'skipped')
113
+ installed++;
114
+ else
115
+ skipped++;
116
+ }
117
+ }
118
+ console.log('');
119
+ info(`${chalk.green(String(installed) + ' novos')} | ${chalk.dim(String(skipped) + ' ja existiam')}`);
120
+ }
121
+ }
122
+ else {
123
+ warn('Nenhum agente encontrado. Use `claudiao create agent` pra criar.');
124
+ }
125
+ // [3/3] Install skills
126
+ heading('[3/3] Skills');
127
+ dim('Slash commands com templates prontos (ex: /pr-template, /security-checklist)');
128
+ console.log('');
129
+ let skillCount = 0;
130
+ if (skillsSource && existsSync(skillsSource)) {
131
+ if (!dryRun) {
132
+ ensureDir(CLAUDE_SKILLS_DIR);
133
+ }
134
+ const skillDirs = readdirSync(skillsSource, { withFileTypes: true })
135
+ .filter(d => d.isDirectory())
136
+ .map(d => d.name);
137
+ skillCount = skillDirs.length;
138
+ if (dryRun) {
139
+ for (const dir of skillDirs) {
140
+ info(`[dry-run] Linkaria skill: /${dir}`);
141
+ }
142
+ console.log('');
143
+ info(`[dry-run] ${skillCount} skills seriam processadas`);
144
+ }
145
+ else {
146
+ let installed = 0;
147
+ let skipped = 0;
148
+ for (const dir of skillDirs) {
149
+ const source = join(skillsSource, dir);
150
+ const target = join(CLAUDE_SKILLS_DIR, dir);
151
+ const result = createSymlink(source, target);
152
+ if (result.status === 'created' || result.status === 'backup') {
153
+ success(`/${dir}`);
154
+ installed++;
155
+ }
156
+ else {
157
+ console.log(` ${chalk.yellow('⏭')} /${dir} ${chalk.dim('— ja instalada')}`);
158
+ skipped++;
159
+ }
160
+ }
161
+ console.log('');
162
+ info(`${chalk.green(String(installed) + ' novas')} | ${chalk.dim(String(skipped) + ' ja existiam')}`);
163
+ }
164
+ }
165
+ else {
166
+ warn('Nenhuma skill encontrada. Use `claudiao create skill` pra criar.');
167
+ }
168
+ // Ask about plugins
169
+ if (dryRun) {
170
+ console.log('');
171
+ info('[dry-run] Pulando prompts de plugins');
172
+ info('[dry-run] Plugins disponiveis: superpowers, get-shit-done, claude-mem');
173
+ }
174
+ else {
175
+ console.log('');
176
+ const { installPlugins } = await inquirer.prompt([{
177
+ type: 'confirm',
178
+ name: 'installPlugins',
179
+ message: 'Quer instalar plugins da comunidade? (superpowers, get-shit-done, claude-mem)',
180
+ default: false,
181
+ }]);
182
+ if (installPlugins) {
183
+ heading('Plugins da Comunidade');
184
+ for (const plugin of PLUGINS) {
185
+ console.log('');
186
+ console.log(` ${chalk.bold(plugin.name)} ${plugin.stars ? chalk.dim(`(${plugin.stars} stars)`) : ''}`);
187
+ dim(plugin.description);
188
+ dim(`Repo: ${plugin.repo}`);
189
+ console.log('');
190
+ const { install } = await inquirer.prompt([{
191
+ type: 'confirm',
192
+ name: 'install',
193
+ message: ` Instalar ${plugin.name}?`,
194
+ default: false,
195
+ }]);
196
+ if (install) {
197
+ try {
198
+ execSync(plugin.installCommand, { stdio: 'inherit' });
199
+ success(`${plugin.name} instalado`);
200
+ }
201
+ catch {
202
+ error(`Falha ao instalar ${plugin.name}. Tente manualmente: ${plugin.installCommand}`);
203
+ }
204
+ }
205
+ }
206
+ }
207
+ }
208
+ // Save config — preserve existing repoPath if current source is unavailable
209
+ if (dryRun) {
210
+ info('[dry-run] Salvaria configuracao em .claudiao.json');
211
+ }
212
+ else {
213
+ let existingConfig = {};
214
+ if (existsSync(CONFIG_FILE)) {
215
+ try {
216
+ existingConfig = JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'));
217
+ }
218
+ catch {
219
+ // ignore corrupt config
220
+ }
221
+ }
222
+ const config = {
223
+ repoPath: getExternalRepoPath() || existingConfig.repoPath || undefined,
224
+ installedAt: new Date().toISOString(),
225
+ version: existingConfig.version || '1.0.0',
226
+ };
227
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
228
+ }
229
+ // Summary
230
+ separator();
231
+ console.log(chalk.green.bold(' Pronto! claudiao configurado.'));
232
+ separator();
233
+ console.log(chalk.bold(' O que foi instalado:'));
234
+ if (globalMdSource)
235
+ console.log(` ${chalk.green('✓')} CLAUDE.md global com regras e configuracoes`);
236
+ if (agentCount > 0)
237
+ console.log(` ${chalk.green('✓')} ${agentCount} agentes especializados`);
238
+ if (skillCount > 0)
239
+ console.log(` ${chalk.green('✓')} ${skillCount} skills / slash commands`);
240
+ console.log('');
241
+ console.log(chalk.bold(' Proximos passos:'));
242
+ console.log(` ${chalk.cyan('1.')} Abra o terminal e rode ${chalk.yellow('claude')} em qualquer projeto`);
243
+ console.log(` ${chalk.cyan('2.')} Os agentes sao ativados automaticamente pelo contexto`);
244
+ console.log(` ${chalk.cyan('3.')} Use skills digitando o comando (ex: ${chalk.yellow('/security-checklist')})`);
245
+ console.log('');
246
+ console.log(chalk.bold(' Comandos uteis:'));
247
+ console.log(` ${chalk.yellow('claudiao list agents')} Lista todos os agentes instalados`);
248
+ console.log(` ${chalk.yellow('claudiao list skills')} Lista todas as skills`);
249
+ console.log(` ${chalk.yellow('claudiao create agent')} Cria um novo agente`);
250
+ console.log(` ${chalk.yellow('claudiao doctor')} Verifica se tudo esta ok`);
251
+ console.log('');
252
+ }
@@ -0,0 +1 @@
1
+ export declare function installPlugin(name: string): void;
@@ -0,0 +1,35 @@
1
+ import { execSync } from 'node:child_process';
2
+ import chalk from 'chalk';
3
+ import { getPlugin, PLUGINS } from '../lib/plugins.js';
4
+ import { banner, success, error, heading, info } from '../lib/format.js';
5
+ export function installPlugin(name) {
6
+ banner();
7
+ const plugin = getPlugin(name);
8
+ if (!plugin) {
9
+ error(`Plugin "${name}" nao encontrado.`);
10
+ console.log('');
11
+ info('Plugins disponiveis:');
12
+ for (const p of PLUGINS) {
13
+ console.log(` ${chalk.cyan(p.name.padEnd(18))}${chalk.dim(p.description.slice(0, 60))}`);
14
+ }
15
+ console.log('');
16
+ return;
17
+ }
18
+ heading(`Instalando ${plugin.name}...`);
19
+ console.log(chalk.dim(` ${plugin.description}`));
20
+ console.log(chalk.dim(` Repo: ${plugin.repo}`));
21
+ console.log('');
22
+ console.log(chalk.dim(` Executando: ${plugin.installCommand}`));
23
+ console.log('');
24
+ try {
25
+ execSync(plugin.installCommand, { stdio: 'inherit' });
26
+ console.log('');
27
+ success(`${plugin.name} instalado!`);
28
+ }
29
+ catch {
30
+ console.log('');
31
+ error(`Falha ao instalar ${plugin.name}.`);
32
+ info(`Tente manualmente: ${chalk.yellow(plugin.installCommand)}`);
33
+ }
34
+ console.log('');
35
+ }
@@ -0,0 +1,3 @@
1
+ export declare function listAgents(): void;
2
+ export declare function listSkills(): void;
3
+ export declare function listPlugins(): void;
@@ -0,0 +1,123 @@
1
+ import { readdirSync, existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import chalk from 'chalk';
4
+ import { CLAUDE_AGENTS_DIR, CLAUDE_SKILLS_DIR } from '../lib/paths.js';
5
+ import { parseAgentFile, parseSkillFile } from '../lib/frontmatter.js';
6
+ import { banner, heading, table, info } from '../lib/format.js';
7
+ import { PLUGINS } from '../lib/plugins.js';
8
+ export function listAgents() {
9
+ banner();
10
+ heading('Agentes instalados');
11
+ if (!existsSync(CLAUDE_AGENTS_DIR)) {
12
+ info('Nenhum agente instalado. Rode `claudiao init` ou `claudiao create agent`.');
13
+ return;
14
+ }
15
+ const files = readdirSync(CLAUDE_AGENTS_DIR).filter(f => f.endsWith('.md'));
16
+ if (files.length === 0) {
17
+ info('Nenhum agente instalado.');
18
+ return;
19
+ }
20
+ const rows = files.map(file => {
21
+ const filePath = join(CLAUDE_AGENTS_DIR, file);
22
+ try {
23
+ const meta = parseAgentFile(filePath);
24
+ return {
25
+ name: meta.name || file.replace('.md', ''),
26
+ description: meta.description.slice(0, 70),
27
+ category: meta.category || 'other',
28
+ status: 'installed',
29
+ };
30
+ }
31
+ catch {
32
+ return {
33
+ name: file.replace('.md', ''),
34
+ description: chalk.dim('(erro ao ler frontmatter)'),
35
+ category: 'other',
36
+ status: 'installed',
37
+ };
38
+ }
39
+ });
40
+ // Dynamic grouping by category from frontmatter
41
+ const CATEGORY_LABELS = {
42
+ dev: 'Desenvolvimento',
43
+ cloud: 'Cloud & Infra',
44
+ quality: 'Qualidade & Seguranca',
45
+ planning: 'Planejamento & Gestao',
46
+ };
47
+ const CATEGORY_ORDER = ['dev', 'cloud', 'quality', 'planning'];
48
+ const grouped = new Map();
49
+ for (const row of rows) {
50
+ const cat = row.category;
51
+ if (!grouped.has(cat)) {
52
+ grouped.set(cat, []);
53
+ }
54
+ grouped.get(cat).push(row);
55
+ }
56
+ // Ordered categories first, then any others alphabetically
57
+ const orderedKeys = [
58
+ ...CATEGORY_ORDER.filter(k => grouped.has(k)),
59
+ ...[...grouped.keys()].filter(k => !CATEGORY_ORDER.includes(k)).sort(),
60
+ ];
61
+ for (const key of orderedKeys) {
62
+ const catRows = grouped.get(key);
63
+ if (catRows && catRows.length > 0) {
64
+ const label = CATEGORY_LABELS[key] || key.charAt(0).toUpperCase() + key.slice(1);
65
+ console.log(` ${chalk.bold(label)}`);
66
+ table(catRows);
67
+ console.log('');
68
+ }
69
+ }
70
+ info(`${files.length} agentes instalados no total`);
71
+ console.log('');
72
+ }
73
+ export function listSkills() {
74
+ banner();
75
+ heading('Skills instaladas');
76
+ if (!existsSync(CLAUDE_SKILLS_DIR)) {
77
+ info('Nenhuma skill instalada. Rode `claudiao init` ou `claudiao create skill`.');
78
+ return;
79
+ }
80
+ const dirs = readdirSync(CLAUDE_SKILLS_DIR, { withFileTypes: true })
81
+ .filter(d => d.isDirectory() || d.isSymbolicLink());
82
+ if (dirs.length === 0) {
83
+ info('Nenhuma skill instalada.');
84
+ return;
85
+ }
86
+ const rows = dirs.map(d => {
87
+ const skillFile = join(CLAUDE_SKILLS_DIR, d.name, 'SKILL.md');
88
+ try {
89
+ if (existsSync(skillFile)) {
90
+ const meta = parseSkillFile(skillFile);
91
+ return {
92
+ name: '/' + (meta.name || d.name),
93
+ description: meta.description.slice(0, 70),
94
+ };
95
+ }
96
+ }
97
+ catch {
98
+ // fallthrough
99
+ }
100
+ return {
101
+ name: '/' + d.name,
102
+ description: '',
103
+ };
104
+ });
105
+ table(rows);
106
+ console.log('');
107
+ info(`${dirs.length} skills instaladas. Use digitando o comando no Claude Code.`);
108
+ console.log('');
109
+ }
110
+ export function listPlugins() {
111
+ banner();
112
+ heading('Plugins da comunidade');
113
+ console.log(chalk.dim(' Ferramentas extras que complementam os agentes/skills.'));
114
+ console.log(chalk.dim(' Instale com: claudiao install plugin <nome>'));
115
+ console.log('');
116
+ for (const plugin of PLUGINS) {
117
+ console.log(` ${chalk.bold(plugin.name)} ${plugin.stars ? chalk.dim(`(${plugin.stars} stars)`) : ''}`);
118
+ console.log(` ${chalk.dim(plugin.description)}`);
119
+ console.log(` ${chalk.dim('Repo: ' + plugin.repo)}`);
120
+ console.log(` ${chalk.dim('Instalar: ' + plugin.installCommand)}`);
121
+ console.log('');
122
+ }
123
+ }
@@ -0,0 +1,6 @@
1
+ export declare function removeAgent(name: string, options?: {
2
+ dryRun?: boolean;
3
+ }): Promise<void>;
4
+ export declare function removeSkill(name: string, options?: {
5
+ dryRun?: boolean;
6
+ }): Promise<void>;
@@ -0,0 +1,121 @@
1
+ import { existsSync, rmSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import chalk from 'chalk';
4
+ import inquirer from 'inquirer';
5
+ import { CLAUDE_AGENTS_DIR, CLAUDE_SKILLS_DIR, getAgentsSavePath } from '../lib/paths.js';
6
+ import { removeSymlink, isSymlink } from '../lib/symlinks.js';
7
+ import { banner, success, error, heading, info } from '../lib/format.js';
8
+ export async function removeAgent(name, options) {
9
+ const dryRun = options?.dryRun ?? false;
10
+ banner();
11
+ heading(`Remover agente: ${name}`);
12
+ if (dryRun) {
13
+ info('[dry-run] Nenhuma alteracao sera feita');
14
+ console.log('');
15
+ }
16
+ const symlinkPath = join(CLAUDE_AGENTS_DIR, `${name}.md`);
17
+ if (!existsSync(symlinkPath)) {
18
+ error(`Agente "${name}" nao encontrado em ~/.claude/agents/`);
19
+ console.log(chalk.dim(' Rode `claudiao list agents` pra ver os disponiveis.'));
20
+ return;
21
+ }
22
+ const { confirm } = await inquirer.prompt([{
23
+ type: 'confirm',
24
+ name: 'confirm',
25
+ message: `Remover agente "${name}"?`,
26
+ default: false,
27
+ }]);
28
+ if (!confirm) {
29
+ console.log(chalk.dim(' Cancelado.'));
30
+ return;
31
+ }
32
+ if (dryRun) {
33
+ const isLink = isSymlink(symlinkPath);
34
+ if (isLink) {
35
+ info(`[dry-run] Removeria symlink: ~/.claude/agents/${name}.md`);
36
+ }
37
+ else {
38
+ info(`[dry-run] Removeria arquivo: ~/.claude/agents/${name}.md`);
39
+ }
40
+ }
41
+ else {
42
+ // Remove symlink
43
+ const removed = removeSymlink(symlinkPath);
44
+ if (removed) {
45
+ success(`Symlink removido: ~/.claude/agents/${name}.md`);
46
+ }
47
+ else {
48
+ // Not a symlink, just delete
49
+ rmSync(symlinkPath);
50
+ success(`Arquivo removido: ~/.claude/agents/${name}.md`);
51
+ }
52
+ }
53
+ // Ask if should also remove source
54
+ const savePath = getAgentsSavePath();
55
+ if (savePath) {
56
+ const sourcePath = join(savePath, `${name}.md`);
57
+ if (existsSync(sourcePath)) {
58
+ if (dryRun) {
59
+ info(`[dry-run] Perguntaria se quer remover fonte: ${sourcePath}`);
60
+ }
61
+ else {
62
+ const { removeSource } = await inquirer.prompt([{
63
+ type: 'confirm',
64
+ name: 'removeSource',
65
+ message: 'Remover tambem o arquivo fonte do repositorio?',
66
+ default: false,
67
+ }]);
68
+ if (removeSource) {
69
+ rmSync(sourcePath);
70
+ success(`Fonte removido: ${sourcePath}`);
71
+ }
72
+ }
73
+ }
74
+ }
75
+ console.log('');
76
+ }
77
+ export async function removeSkill(name, options) {
78
+ const dryRun = options?.dryRun ?? false;
79
+ banner();
80
+ heading(`Remover skill: ${name}`);
81
+ if (dryRun) {
82
+ info('[dry-run] Nenhuma alteracao sera feita');
83
+ console.log('');
84
+ }
85
+ const symlinkPath = join(CLAUDE_SKILLS_DIR, name);
86
+ if (!existsSync(symlinkPath)) {
87
+ error(`Skill "${name}" nao encontrada em ~/.claude/skills/`);
88
+ console.log(chalk.dim(' Rode `claudiao list skills` pra ver as disponiveis.'));
89
+ return;
90
+ }
91
+ const { confirm } = await inquirer.prompt([{
92
+ type: 'confirm',
93
+ name: 'confirm',
94
+ message: `Remover skill "/${name}"?`,
95
+ default: false,
96
+ }]);
97
+ if (!confirm) {
98
+ console.log(chalk.dim(' Cancelado.'));
99
+ return;
100
+ }
101
+ if (dryRun) {
102
+ const isLink = isSymlink(symlinkPath);
103
+ if (isLink) {
104
+ info(`[dry-run] Removeria symlink: ~/.claude/skills/${name}`);
105
+ }
106
+ else {
107
+ info(`[dry-run] Removeria diretorio: ~/.claude/skills/${name}`);
108
+ }
109
+ }
110
+ else {
111
+ const removed = removeSymlink(symlinkPath);
112
+ if (removed) {
113
+ success(`Symlink removido: ~/.claude/skills/${name}`);
114
+ }
115
+ else {
116
+ rmSync(symlinkPath, { recursive: true });
117
+ success(`Diretorio removido: ~/.claude/skills/${name}`);
118
+ }
119
+ }
120
+ console.log('');
121
+ }