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.
- package/README.md +387 -0
- package/dist/commands/create.d.ts +2 -0
- package/dist/commands/create.js +260 -0
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.js +138 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.js +252 -0
- package/dist/commands/install-plugin.d.ts +1 -0
- package/dist/commands/install-plugin.js +35 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.js +123 -0
- package/dist/commands/remove.d.ts +6 -0
- package/dist/commands/remove.js +121 -0
- package/dist/commands/update.d.ts +4 -0
- package/dist/commands/update.js +141 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +156 -0
- package/dist/lib/__tests__/frontmatter.test.d.ts +1 -0
- package/dist/lib/__tests__/frontmatter.test.js +180 -0
- package/dist/lib/__tests__/paths.test.d.ts +1 -0
- package/dist/lib/__tests__/paths.test.js +29 -0
- package/dist/lib/__tests__/symlinks.test.d.ts +1 -0
- package/dist/lib/__tests__/symlinks.test.js +142 -0
- package/dist/lib/format.d.ts +13 -0
- package/dist/lib/format.js +47 -0
- package/dist/lib/frontmatter.d.ts +9 -0
- package/dist/lib/frontmatter.js +45 -0
- package/dist/lib/paths.d.ts +33 -0
- package/dist/lib/paths.js +111 -0
- package/dist/lib/plugins.d.ts +3 -0
- package/dist/lib/plugins.js +24 -0
- package/dist/lib/symlinks.d.ts +8 -0
- package/dist/lib/symlinks.js +56 -0
- package/dist/lib/templates.d.ts +26 -0
- package/dist/lib/templates.js +75 -0
- package/dist/types.d.ts +25 -0
- package/dist/types.js +1 -0
- package/package.json +47 -0
- package/templates/CLAUDE-CODE-BEST-PRACTICES.md +508 -0
- package/templates/CLOUD-CLI-GUIDE.md +405 -0
- package/templates/agents/architect.md +128 -0
- package/templates/agents/aws-specialist.md +104 -0
- package/templates/agents/azure-specialist.md +117 -0
- package/templates/agents/database-specialist.md +104 -0
- package/templates/agents/dod-specialist.md +101 -0
- package/templates/agents/gcp-specialist.md +124 -0
- package/templates/agents/idea-refiner.md +146 -0
- package/templates/agents/implementation-planner.md +149 -0
- package/templates/agents/nodejs-specialist.md +105 -0
- package/templates/agents/pr-reviewer.md +132 -0
- package/templates/agents/product-owner.md +88 -0
- package/templates/agents/project-manager.md +95 -0
- package/templates/agents/prompt-engineer.md +115 -0
- package/templates/agents/python-specialist.md +103 -0
- package/templates/agents/react-specialist.md +94 -0
- package/templates/agents/security-specialist.md +145 -0
- package/templates/agents/test-specialist.md +157 -0
- package/templates/agents/uxui-specialist.md +102 -0
- package/templates/global-CLAUDE.md +100 -0
- package/templates/skills/architecture-decision/SKILL.md +102 -0
- package/templates/skills/meet-dod/SKILL.md +124 -0
- package/templates/skills/pm-templates/SKILL.md +125 -0
- package/templates/skills/pr-template/SKILL.md +87 -0
- package/templates/skills/product-templates/SKILL.md +97 -0
- package/templates/skills/python-patterns/SKILL.md +123 -0
- package/templates/skills/security-checklist/SKILL.md +80 -0
- package/templates/skills/sql-templates/SKILL.md +93 -0
- 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,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,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,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
|
+
}
|