@fontdata/ai-harness 2.0.0 → 2.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +9 -2
- package/LICENSE +21 -0
- package/README.md +175 -140
- package/{src → dist}/catalog.js +5 -12
- package/dist/cli.js +180 -0
- package/dist/comentarios/command.js +74 -0
- package/dist/comentarios/instalar.js +33 -0
- package/dist/config/config.js +99 -0
- package/dist/contratos/artefatos.js +284 -0
- package/dist/contratos/eventos.js +103 -0
- package/dist/doctor/checks.js +424 -0
- package/dist/init.js +240 -0
- package/dist/install/atomic.js +51 -0
- package/dist/install/flags.js +99 -0
- package/dist/install/hooks.js +47 -0
- package/dist/install/lock.js +39 -0
- package/dist/install/plan.js +209 -0
- package/dist/install/selection.js +77 -0
- package/dist/install/settings.js +112 -0
- package/dist/memoria/indice.js +195 -0
- package/dist/migrar/migrar.js +426 -0
- package/dist/rastro/command.js +46 -0
- package/dist/run.js +86 -0
- package/dist/trabalhos/conflitos.js +115 -0
- package/dist/types.js +1 -0
- package/dist/update/legado.js +74 -0
- package/dist/update/update.js +284 -0
- package/package.json +17 -8
- package/templates/CLAUDE.md +59 -30
- package/templates/agents/auditor-plano.md +44 -0
- package/templates/agents/investigador.md +32 -0
- package/templates/agents/qa.md +44 -0
- package/templates/agents/revisor-testes.md +40 -0
- package/templates/catalog.json +24 -61
- package/templates/commands/atualizar-deps.md +43 -9
- package/templates/commands/diagrama.md +35 -10
- package/templates/commands/gerar-env.md +39 -10
- package/templates/commands/gerar-testes.md +42 -10
- package/templates/commands/git-commit-push.md +0 -0
- package/templates/commands/onboarding.md +44 -15
- package/templates/commands/refatorar.md +50 -10
- package/templates/commands/revisar-pr.md +56 -12
- package/templates/commands/sincronizar-claude-md.md +177 -9
- package/templates/commands/versao.md +0 -0
- package/templates/hooks/comentarios/check.mjs +210 -0
- package/templates/hooks/hooks.json +34 -0
- package/templates/hooks/lembrete.mjs +29 -0
- package/templates/hooks/lib/config.mjs +40 -0
- package/templates/hooks/lib/hook.mjs +85 -0
- package/templates/hooks/lib/rastro.mjs +144 -0
- package/templates/hooks/lib/segredos.mjs +91 -0
- package/templates/hooks/lib/temas.mjs +111 -0
- package/templates/hooks/lib/trabalho.mjs +94 -0
- package/templates/hooks/proteger-contratos.mjs +80 -0
- package/templates/hooks/segredo-no-commit.mjs +76 -0
- package/templates/hooks/sem-jargao.mjs +58 -0
- package/templates/hooks/task-so-fecha-verde.mjs +33 -0
- package/templates/legado/manifesto.json +1267 -0
- package/templates/rules/comentarios.md +166 -0
- package/templates/rules/harness-projeto.md +41 -0
- package/templates/skills/auditar-performance/SKILL.md +53 -0
- package/templates/skills/auditar-performance/references/pontos-quentes.md +35 -0
- package/templates/skills/auditar-performance/templates/relatorios/CLIENTE.md +26 -0
- package/templates/skills/auditar-performance/templates/relatorios/TECNICO.md +27 -0
- package/templates/skills/auditar-seguranca/SKILL.md +67 -0
- package/templates/skills/auditar-seguranca/references/seguranca-tecnica.md +23 -0
- package/templates/skills/auditar-seguranca/templates/relatorios/CLIENTE.md +30 -0
- package/templates/skills/auditar-seguranca/templates/relatorios/TECNICO.md +38 -0
- package/templates/skills/auditar-ui/SKILL.md +64 -0
- package/templates/skills/auditar-ui/references/lentes.md +33 -0
- package/templates/skills/auditar-ui/templates/relatorios/CLIENTE.md +26 -0
- package/templates/skills/auditar-ui/templates/relatorios/TECNICO.md +31 -0
- package/templates/skills/evoluir-harness/SKILL.md +81 -0
- package/templates/skills/evoluir-harness/references/agent.md +83 -0
- package/templates/skills/evoluir-harness/references/auditoria.md +107 -0
- package/templates/skills/evoluir-harness/references/code-reviewer.md +68 -0
- package/templates/skills/evoluir-harness/references/design-system.md +56 -0
- package/templates/skills/evoluir-harness/references/hook.md +95 -0
- package/templates/skills/evoluir-harness/references/rule.md +67 -0
- package/templates/skills/evoluir-harness/references/skill.md +63 -0
- package/templates/skills/executar-plan/SKILL.md +130 -0
- package/templates/skills/executar-plan/references/delegacao.md +43 -0
- package/templates/skills/executar-plan/references/retomada.md +33 -0
- package/templates/skills/executar-plan/templates/BLOQUEIOS.md +30 -0
- package/templates/skills/harness/SKILL.md +75 -0
- package/templates/skills/harness/references/auto-tag.md +118 -0
- package/templates/skills/harness/references/ignores.md +40 -0
- package/templates/skills/harness/references/scaffold.md +29 -0
- package/templates/skills/harness/references/validar-ideia.md +42 -0
- package/templates/skills/memoria/SKILL.md +52 -0
- package/templates/skills/nova-tarefa/SKILL.md +99 -0
- package/templates/skills/nova-tarefa/references/isso-ja-existe.md +24 -0
- package/templates/skills/nova-tarefa/references/regras-do-plano.md +35 -0
- package/templates/skills/nova-tarefa/templates/DECISOES.md +20 -0
- package/templates/skills/nova-tarefa/templates/PLAN.md +58 -0
- package/templates/skills/nova-tarefa/templates/SPEC.md +37 -0
- package/templates/skills/resolver-bug/SKILL.md +104 -0
- package/templates/skills/resolver-bug/references/relatorio-para-cliente.md +26 -0
- package/templates/skills/resolver-bug/templates/PLAN.md +62 -0
- package/templates/skills/resolver-bug/templates/relatorios/CLIENTE.md +29 -0
- package/templates/skills/resolver-bug/templates/relatorios/TECNICO.md +32 -0
- package/bin/cli.js +0 -122
- package/src/init.js +0 -317
- package/src/installer.js +0 -92
- package/src/run.js +0 -99
- package/templates/commands/auditar-performance.md +0 -27
- package/templates/commands/auditar-seguranca.md +0 -64
- package/templates/commands/auditar-ui.md +0 -38
- package/templates/commands/codigo-morto.md +0 -22
- package/templates/commands/configurar-auto-tag.md +0 -185
- package/templates/commands/configurar-comentarios.md +0 -543
- package/templates/commands/configurar-orquestrador.md +0 -13
- package/templates/commands/corrigir-review.md +0 -11
- package/templates/commands/criar-agents.md +0 -42
- package/templates/commands/criar-code-reviewer.md +0 -30
- package/templates/commands/criar-hooks.md +0 -32
- package/templates/commands/criar-rag.md +0 -25
- package/templates/commands/criar-rules.md +0 -31
- package/templates/commands/criar-skill.md +0 -22
- package/templates/commands/design-system.md +0 -27
- package/templates/commands/executar-plan.md +0 -36
- package/templates/commands/gerar-claude-md.md +0 -66
- package/templates/commands/gerar-ignore.md +0 -37
- package/templates/commands/gerar-spec.md +0 -33
- package/templates/commands/harness.md +0 -34
- package/templates/commands/nova-tarefa.md +0 -60
- package/templates/commands/resolver-bug.md +0 -25
- package/templates/commands/review-por-task.md +0 -16
- package/templates/commands/scaffold.md +0 -25
- package/templates/commands/validar-commands.md +0 -24
- package/templates/commands/validar-ideia.md +0 -36
package/src/init.js
DELETED
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
3
|
-
import * as p from '@clack/prompts';
|
|
4
|
-
import { loadCatalog, allCommands, recommendedCommands } from './catalog.js';
|
|
5
|
-
import { installCommand, installClaudeMd, installMaster, installSkill } from './installer.js';
|
|
6
|
-
|
|
7
|
-
/** Encerra o fluxo com mensagem amigável quando o usuário cancela (Ctrl+C). */
|
|
8
|
-
function bail(value) {
|
|
9
|
-
if (p.isCancel(value)) {
|
|
10
|
-
p.cancel('Operação cancelada.');
|
|
11
|
-
process.exit(0);
|
|
12
|
-
}
|
|
13
|
-
return value;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Quantos itens a lista pode mostrar de uma vez sem estourar a altura do terminal.
|
|
18
|
-
* Calcula a partir das linhas reais do terminal (process.stdout.rows), deixando
|
|
19
|
-
* margem para a mensagem e os indicadores de rolagem do clack. Sem isso, em um
|
|
20
|
-
* terminal baixo a lista sobrepõe as renderizações ("itens duplicados").
|
|
21
|
-
*/
|
|
22
|
-
function viewportItems(min = 3, reserve = 6) {
|
|
23
|
-
const rows = process.stdout.rows || 20;
|
|
24
|
-
return Math.max(min, rows - reserve);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Manifestos de stack: se algum existir na raiz, é um projeto já existente.
|
|
29
|
-
*/
|
|
30
|
-
const PROJECT_MANIFESTS = [
|
|
31
|
-
'package.json', 'pyproject.toml', 'requirements.txt', 'go.mod',
|
|
32
|
-
'Cargo.toml', 'pom.xml', 'build.gradle', 'build.gradle.kts',
|
|
33
|
-
'composer.json', 'Gemfile', 'Makefile', 'CMakeLists.txt',
|
|
34
|
-
'tsconfig.json', 'pubspec.yaml', 'mix.exs',
|
|
35
|
-
];
|
|
36
|
-
|
|
37
|
-
/** Pastas de código-fonte que, se tiverem conteúdo, indicam projeto existente. */
|
|
38
|
-
const SOURCE_DIRS = ['src', 'app', 'lib', 'source'];
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Detecta se a pasta alvo já é um projeto com código ('existing') ou está
|
|
42
|
-
* essencialmente vazia/recém-criada ('new'). Ignora .git e .claude — a presença
|
|
43
|
-
* deles sozinha não caracteriza um projeto existente.
|
|
44
|
-
*/
|
|
45
|
-
function detectProjectKind(repoPath) {
|
|
46
|
-
// 1. Manifesto de stack na raiz.
|
|
47
|
-
if (PROJECT_MANIFESTS.some((f) => existsSync(resolve(repoPath, f)))) return 'existing';
|
|
48
|
-
|
|
49
|
-
// 2. Arquivo de solução/projeto .NET na raiz.
|
|
50
|
-
let rootEntries = [];
|
|
51
|
-
try {
|
|
52
|
-
rootEntries = readdirSync(repoPath);
|
|
53
|
-
} catch {
|
|
54
|
-
return 'new';
|
|
55
|
-
}
|
|
56
|
-
if (rootEntries.some((f) => /\.(sln|csproj|fsproj|vbproj)$/i.test(f))) return 'existing';
|
|
57
|
-
|
|
58
|
-
// 3. Pasta de código-fonte com algum conteúdo.
|
|
59
|
-
for (const dir of SOURCE_DIRS) {
|
|
60
|
-
const dirPath = resolve(repoPath, dir);
|
|
61
|
-
try {
|
|
62
|
-
if (statSync(dirPath).isDirectory() && readdirSync(dirPath).length) return 'existing';
|
|
63
|
-
} catch {
|
|
64
|
-
// pasta não existe — segue.
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return 'new';
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Seleção interativa em dois níveis: menu de grupos → submenu de itens do grupo
|
|
73
|
-
* → volta ao menu de grupos. Mantém cada lista pequena (cabe em terminais baixos)
|
|
74
|
-
* e mostra o quanto já foi marcado em cada grupo. Retorna os comandos escolhidos.
|
|
75
|
-
*
|
|
76
|
-
* `initialIds` define os comandos já marcados ao abrir (ex.: recomendados em
|
|
77
|
-
* projeto novo). Em projeto existente vem vazio — o usuário marca só os avulsos.
|
|
78
|
-
*/
|
|
79
|
-
async function selectByGroups(catalog, initialIds = new Set()) {
|
|
80
|
-
const selectedIds = new Set(initialIds);
|
|
81
|
-
const DONE = '__done__';
|
|
82
|
-
|
|
83
|
-
for (;;) {
|
|
84
|
-
const groupOptions = catalog.groups.map((g) => {
|
|
85
|
-
const chosen = g.commands.filter((c) => selectedIds.has(c.id)).length;
|
|
86
|
-
return {
|
|
87
|
-
value: g.id,
|
|
88
|
-
label: `${g.title} (${chosen}/${g.commands.length})`,
|
|
89
|
-
hint: chosen ? `${chosen} marcado(s)` : undefined,
|
|
90
|
-
};
|
|
91
|
-
});
|
|
92
|
-
groupOptions.push({
|
|
93
|
-
value: DONE,
|
|
94
|
-
label: `✓ Concluir e instalar (${selectedIds.size} comando(s) marcado(s))`,
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
const groupChoice = bail(
|
|
98
|
-
await p.select({
|
|
99
|
-
message: 'Escolha um grupo para marcar comandos — ou Concluir:',
|
|
100
|
-
options: groupOptions,
|
|
101
|
-
maxItems: viewportItems(),
|
|
102
|
-
})
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
if (groupChoice === DONE) break;
|
|
106
|
-
|
|
107
|
-
const group = catalog.groups.find((g) => g.id === groupChoice);
|
|
108
|
-
const picked = bail(
|
|
109
|
-
await p.multiselect({
|
|
110
|
-
message: `${group.title} — espaço marca, enter volta ao menu de grupos:`,
|
|
111
|
-
options: group.commands.map((c) => ({ value: c.id, label: c.title, hint: c.description })),
|
|
112
|
-
initialValues: group.commands.filter((c) => selectedIds.has(c.id)).map((c) => c.id),
|
|
113
|
-
required: false,
|
|
114
|
-
maxItems: viewportItems(),
|
|
115
|
-
})
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
// Reconcilia só este grupo: limpa os ids dele e re-adiciona os que ficaram marcados.
|
|
119
|
-
for (const c of group.commands) selectedIds.delete(c.id);
|
|
120
|
-
for (const id of picked) selectedIds.add(id);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return allCommands(catalog).filter((c) => selectedIds.has(c.id));
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export async function runInit(initialPath) {
|
|
127
|
-
const catalog = loadCatalog();
|
|
128
|
-
|
|
129
|
-
p.intro('Fontdata · ai-harness — instalador do harness para Claude Code');
|
|
130
|
-
|
|
131
|
-
// 1. Diretório alvo
|
|
132
|
-
const repoInput = bail(
|
|
133
|
-
await p.text({
|
|
134
|
-
message: 'Em qual pasta do projeto deseja instalar?',
|
|
135
|
-
placeholder: '. (pasta atual)',
|
|
136
|
-
initialValue: initialPath || '.',
|
|
137
|
-
})
|
|
138
|
-
);
|
|
139
|
-
const repoPath = resolve(process.cwd(), repoInput.trim() || '.');
|
|
140
|
-
|
|
141
|
-
if (!existsSync(repoPath)) {
|
|
142
|
-
p.cancel(`Pasta não encontrada: ${repoPath}`);
|
|
143
|
-
process.exit(1);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Detecta o tipo de projeto: muda como a seleção "Manual" começa.
|
|
147
|
-
const projectKind = detectProjectKind(repoPath);
|
|
148
|
-
p.note(
|
|
149
|
-
projectKind === 'existing'
|
|
150
|
-
? 'Projeto existente detectado. Na opção "Escolher manualmente" nada vem marcado — ideal para cadastrar comandos avulsos.'
|
|
151
|
-
: 'Projeto novo detectado. Na opção "Escolher manualmente" os comandos recomendados já vêm marcados.',
|
|
152
|
-
projectKind === 'existing' ? 'Projeto existente' : 'Projeto novo'
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
// 2. O que instalar
|
|
156
|
-
const scope = bail(
|
|
157
|
-
await p.select({
|
|
158
|
-
message: 'O que deseja instalar?',
|
|
159
|
-
options: [
|
|
160
|
-
{ value: 'recommended', label: 'Conjunto recomendado', hint: 'núcleo de setup + dia a dia' },
|
|
161
|
-
{ value: 'all', label: 'Tudo', hint: `${allCommands(catalog).length} comandos` },
|
|
162
|
-
{
|
|
163
|
-
value: 'manual',
|
|
164
|
-
label: 'Escolher manualmente',
|
|
165
|
-
hint: projectKind === 'existing' ? 'seleção por categoria (nada marcado)' : 'seleção por categoria (recomendados marcados)',
|
|
166
|
-
},
|
|
167
|
-
],
|
|
168
|
-
})
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
let selected;
|
|
172
|
-
if (scope === 'all') {
|
|
173
|
-
selected = allCommands(catalog);
|
|
174
|
-
} else if (scope === 'recommended') {
|
|
175
|
-
selected = recommendedCommands(catalog);
|
|
176
|
-
} else {
|
|
177
|
-
// Projeto novo começa com os recomendados marcados; existente começa vazio.
|
|
178
|
-
const initialIds =
|
|
179
|
-
projectKind === 'new'
|
|
180
|
-
? new Set(recommendedCommands(catalog).map((c) => c.id))
|
|
181
|
-
: new Set();
|
|
182
|
-
selected = await selectByGroups(catalog, initialIds);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// 3. Comando-mestre /harness
|
|
186
|
-
const wantMaster = bail(
|
|
187
|
-
await p.confirm({
|
|
188
|
-
message: 'Incluir também o comando-mestre /harness (conduz a sequência de setup em ordem)?',
|
|
189
|
-
initialValue: true,
|
|
190
|
-
})
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
// Se o /harness foi escolhido, garante que os comandos que ele invoca também sejam instalados.
|
|
194
|
-
let autoAdded = [];
|
|
195
|
-
if (wantMaster) {
|
|
196
|
-
const required = catalog.master.requires || [];
|
|
197
|
-
const selectedIds = new Set(selected.map((c) => c.id));
|
|
198
|
-
const missing = allCommands(catalog).filter(
|
|
199
|
-
(c) => required.includes(c.id) && !selectedIds.has(c.id)
|
|
200
|
-
);
|
|
201
|
-
if (missing.length) {
|
|
202
|
-
selected = [...selected, ...missing];
|
|
203
|
-
autoAdded = missing.map((c) => c.title);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Resolve dependências por comando (campo `requires`): se um comando selecionado
|
|
208
|
-
// depende de outro, o dependente entra junto, mesmo que não tenha sido marcado —
|
|
209
|
-
// como acontece com o /harness.
|
|
210
|
-
{
|
|
211
|
-
const selectedIds = new Set(selected.map((c) => c.id));
|
|
212
|
-
const deps = allCommands(catalog).filter(
|
|
213
|
-
(c) =>
|
|
214
|
-
!selectedIds.has(c.id) &&
|
|
215
|
-
selected.some((sel) => (sel.requires || []).includes(c.id))
|
|
216
|
-
);
|
|
217
|
-
if (deps.length) {
|
|
218
|
-
selected = [...selected, ...deps];
|
|
219
|
-
autoAdded = [...autoAdded, ...deps.map((c) => c.title)];
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// 4. CLAUDE.md base
|
|
224
|
-
const claudeExists = existsSync(resolve(repoPath, catalog.claudeMd.target));
|
|
225
|
-
let claudeMode = 'create';
|
|
226
|
-
const wantClaude = bail(
|
|
227
|
-
await p.confirm({
|
|
228
|
-
message: claudeExists
|
|
229
|
-
? 'Já existe um CLAUDE.md na raiz. Deseja tratá-lo?'
|
|
230
|
-
: 'Criar o CLAUDE.md base na raiz (filosofia de orquestração/TDD)?',
|
|
231
|
-
initialValue: !claudeExists,
|
|
232
|
-
})
|
|
233
|
-
);
|
|
234
|
-
if (wantClaude && claudeExists) {
|
|
235
|
-
claudeMode = bail(
|
|
236
|
-
await p.select({
|
|
237
|
-
message: 'O que fazer com o CLAUDE.md existente?',
|
|
238
|
-
options: [
|
|
239
|
-
{ value: 'backup', label: 'Sobrescrever criando .bak', hint: 'recomendado' },
|
|
240
|
-
{ value: 'overwrite', label: 'Sobrescrever sem backup' },
|
|
241
|
-
{ value: 'skip', label: 'Manter o existente' },
|
|
242
|
-
],
|
|
243
|
-
})
|
|
244
|
-
);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// 5. Confirmação final
|
|
248
|
-
if (selected.length === 0 && !wantMaster && !wantClaude) {
|
|
249
|
-
p.outro('Nada selecionado. Nenhuma alteração feita.');
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
// Skills exigidas pelos comandos selecionados (campo `requiresSkills`).
|
|
254
|
-
const skillCatalog = catalog.skills || [];
|
|
255
|
-
const neededSkillIds = new Set(selected.flatMap((c) => c.requiresSkills || []));
|
|
256
|
-
const neededSkills = skillCatalog.filter((sk) => neededSkillIds.has(sk.id));
|
|
257
|
-
|
|
258
|
-
// Política global de conflito: perguntamos UMA vez se houver risco de sobrescrever.
|
|
259
|
-
const anyConflict =
|
|
260
|
-
selected.some((c) => existsSync(resolve(repoPath, '.claude', 'commands', `${c.id}.md`))) ||
|
|
261
|
-
(wantMaster && existsSync(resolve(repoPath, '.claude', 'commands', `${catalog.master.id}.md`))) ||
|
|
262
|
-
neededSkills.some((sk) => existsSync(resolve(repoPath, '.claude', 'skills', sk.id)));
|
|
263
|
-
|
|
264
|
-
let conflictPolicy = 'overwrite';
|
|
265
|
-
if (anyConflict) {
|
|
266
|
-
conflictPolicy = bail(
|
|
267
|
-
await p.select({
|
|
268
|
-
message: 'Alguns itens já existem no destino. O que fazer com os conflitos?',
|
|
269
|
-
options: [
|
|
270
|
-
{ value: 'overwrite', label: 'Sobrescrever os existentes' },
|
|
271
|
-
{ value: 'skip', label: 'Pular os que já existem' },
|
|
272
|
-
],
|
|
273
|
-
})
|
|
274
|
-
);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// Execução
|
|
278
|
-
const s = p.spinner();
|
|
279
|
-
s.start('Instalando...');
|
|
280
|
-
|
|
281
|
-
const results = { created: [], overwritten: [], skipped: [] };
|
|
282
|
-
for (const cmd of selected) {
|
|
283
|
-
const status = installCommand(cmd, repoPath, () => conflictPolicy);
|
|
284
|
-
results[status].push(cmd.title);
|
|
285
|
-
}
|
|
286
|
-
if (wantMaster) {
|
|
287
|
-
const status = installMaster(catalog, repoPath, () => conflictPolicy);
|
|
288
|
-
results[status].push(catalog.master.title);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
const skillResults = { created: [], overwritten: [], skipped: [] };
|
|
292
|
-
for (const skill of neededSkills) {
|
|
293
|
-
const status = installSkill(skill, repoPath, () => conflictPolicy);
|
|
294
|
-
skillResults[status].push(skill.title);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
let claudeResult = null;
|
|
298
|
-
if (wantClaude) {
|
|
299
|
-
claudeResult = installClaudeMd(catalog, repoPath, claudeExists ? claudeMode : 'create');
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
s.stop('Instalação concluída.');
|
|
303
|
-
|
|
304
|
-
// Resumo
|
|
305
|
-
const lines = [];
|
|
306
|
-
if (results.created.length) lines.push(`Criados (${results.created.length}): ${results.created.join(', ')}`);
|
|
307
|
-
if (results.overwritten.length) lines.push(`Sobrescritos (${results.overwritten.length}): ${results.overwritten.join(', ')}`);
|
|
308
|
-
if (results.skipped.length) lines.push(`Pulados (${results.skipped.length}): ${results.skipped.join(', ')}`);
|
|
309
|
-
const skillsInstalled = [...skillResults.created, ...skillResults.overwritten];
|
|
310
|
-
if (skillsInstalled.length) lines.push(`Skills (${skillsInstalled.length}): ${skillsInstalled.join(', ')}`);
|
|
311
|
-
if (skillResults.skipped.length) lines.push(`Skills puladas (${skillResults.skipped.length}): ${skillResults.skipped.join(', ')}`);
|
|
312
|
-
if (autoAdded.length) lines.push(`Adicionados como dependência (${autoAdded.length}): ${autoAdded.join(', ')}`);
|
|
313
|
-
if (claudeResult) lines.push(`CLAUDE.md: ${claudeResult}`);
|
|
314
|
-
p.note(lines.join('\n') || 'Nada a instalar.', `Resumo · ${repoPath}`);
|
|
315
|
-
|
|
316
|
-
p.outro('Abra o projeto no Claude Code e digite "/" para ver os comandos instalados.');
|
|
317
|
-
}
|
package/src/installer.js
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
import { cpSync, copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { dirname, join } from 'node:path';
|
|
3
|
-
import { templatesDir } from './catalog.js';
|
|
4
|
-
|
|
5
|
-
/** Garante que o diretório de um arquivo exista. */
|
|
6
|
-
function ensureDir(filePath) {
|
|
7
|
-
mkdirSync(dirname(filePath), { recursive: true });
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Copia um comando (template) para <repo>/.claude/commands/<id>.md.
|
|
12
|
-
* Retorna o status da operação: 'created' | 'overwritten' | 'skipped'.
|
|
13
|
-
*
|
|
14
|
-
* @param {object} cmd Item do catálogo (precisa de id e file).
|
|
15
|
-
* @param {string} repoPath Raiz do repositório alvo.
|
|
16
|
-
* @param {function} resolveConflict (destPath) => 'overwrite' | 'skip'. Chamado só se o destino existir.
|
|
17
|
-
*/
|
|
18
|
-
export function installCommand(cmd, repoPath, resolveConflict) {
|
|
19
|
-
const source = join(templatesDir, cmd.file);
|
|
20
|
-
const dest = join(repoPath, '.claude', 'commands', `${cmd.id}.md`);
|
|
21
|
-
|
|
22
|
-
if (existsSync(dest)) {
|
|
23
|
-
const decision = resolveConflict ? resolveConflict(dest) : 'overwrite';
|
|
24
|
-
if (decision === 'skip') return 'skipped';
|
|
25
|
-
ensureDir(dest);
|
|
26
|
-
copyFileSync(source, dest);
|
|
27
|
-
return 'overwritten';
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
ensureDir(dest);
|
|
31
|
-
copyFileSync(source, dest);
|
|
32
|
-
return 'created';
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Instala/atualiza o CLAUDE.md base na raiz do repositório.
|
|
37
|
-
* mode: 'overwrite' | 'skip' | 'backup' (cria CLAUDE.md.bak antes de sobrescrever).
|
|
38
|
-
* Retorna 'created' | 'overwritten' | 'skipped' | 'backed-up'.
|
|
39
|
-
*/
|
|
40
|
-
export function installClaudeMd(catalog, repoPath, mode = 'overwrite') {
|
|
41
|
-
const source = join(templatesDir, catalog.claudeMd.file);
|
|
42
|
-
const dest = join(repoPath, catalog.claudeMd.target);
|
|
43
|
-
|
|
44
|
-
if (!existsSync(dest)) {
|
|
45
|
-
writeFileSync(dest, readFileSync(source, 'utf8'));
|
|
46
|
-
return 'created';
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (mode === 'skip') return 'skipped';
|
|
50
|
-
|
|
51
|
-
if (mode === 'backup') {
|
|
52
|
-
copyFileSync(dest, `${dest}.bak`);
|
|
53
|
-
writeFileSync(dest, readFileSync(source, 'utf8'));
|
|
54
|
-
return 'backed-up';
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
writeFileSync(dest, readFileSync(source, 'utf8'));
|
|
58
|
-
return 'overwritten';
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Copia uma skill (pasta com SKILL.md e references/) para
|
|
63
|
-
* <repo>/.claude/skills/<id>/. Retorna 'created' | 'overwritten' | 'skipped'.
|
|
64
|
-
*
|
|
65
|
-
* @param {object} skill Item do catálogo (precisa de id e dir).
|
|
66
|
-
* @param {string} repoPath Raiz do repositório alvo.
|
|
67
|
-
* @param {function} resolveConflict (destPath) => 'overwrite' | 'skip'. Chamado só se o destino existir.
|
|
68
|
-
*/
|
|
69
|
-
export function installSkill(skill, repoPath, resolveConflict) {
|
|
70
|
-
const source = join(templatesDir, skill.dir);
|
|
71
|
-
const dest = join(repoPath, '.claude', 'skills', skill.id);
|
|
72
|
-
|
|
73
|
-
if (existsSync(dest)) {
|
|
74
|
-
const decision = resolveConflict ? resolveConflict(dest) : 'overwrite';
|
|
75
|
-
if (decision === 'skip') return 'skipped';
|
|
76
|
-
cpSync(source, dest, { recursive: true });
|
|
77
|
-
return 'overwritten';
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
mkdirSync(dirname(dest), { recursive: true });
|
|
81
|
-
cpSync(source, dest, { recursive: true });
|
|
82
|
-
return 'created';
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/** Instala o comando-mestre /harness (mesmo mecanismo de installCommand). */
|
|
86
|
-
export function installMaster(catalog, repoPath, resolveConflict) {
|
|
87
|
-
return installCommand(
|
|
88
|
-
{ id: catalog.master.id, file: catalog.master.file },
|
|
89
|
-
repoPath,
|
|
90
|
-
resolveConflict
|
|
91
|
-
);
|
|
92
|
-
}
|
package/src/run.js
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { spawnSync } from 'node:child_process';
|
|
2
|
-
import { readFileSync } from 'node:fs';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import { dirname, join } from 'node:path';
|
|
5
|
-
import { loadCatalog, allCommands } from './catalog.js';
|
|
6
|
-
|
|
7
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
|
|
9
|
-
/** Raiz do pacote — é ela que vira o plugin carregado via `claude --plugin-dir`. */
|
|
10
|
-
export const pluginRoot = join(__dirname, '..');
|
|
11
|
-
|
|
12
|
-
/** Nome do plugin, lido do manifesto para não duplicar a string. */
|
|
13
|
-
export function pluginName() {
|
|
14
|
-
const manifest = JSON.parse(
|
|
15
|
-
readFileSync(join(pluginRoot, '.claude-plugin', 'plugin.json'), 'utf8')
|
|
16
|
-
);
|
|
17
|
-
return manifest.name;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Ids executáveis: os comandos dos grupos mais o comando-mestre, que fica fora
|
|
22
|
-
* de `groups` no catálogo.
|
|
23
|
-
*/
|
|
24
|
-
export function runnableIds(catalog = loadCatalog()) {
|
|
25
|
-
const ids = allCommands(catalog).map((cmd) => cmd.id);
|
|
26
|
-
if (catalog.master?.id) ids.unshift(catalog.master.id);
|
|
27
|
-
return [...new Set(ids)];
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Ids mais parecidos com o que foi digitado, para sugerir em caso de erro. */
|
|
31
|
-
export function suggestIds(input, ids) {
|
|
32
|
-
const needle = input.toLowerCase();
|
|
33
|
-
return ids
|
|
34
|
-
.filter((id) => id.includes(needle) || needle.includes(id) || id.startsWith(needle.slice(0, 4)))
|
|
35
|
-
.slice(0, 5);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const SYSTEM_NOTE =
|
|
39
|
-
'Os slash commands do harness Fontdata estão disponíveis nesta sessão com o prefixo ' +
|
|
40
|
-
'`/PLUGIN:` (ex.: `/PLUGIN:gerar-spec`). Quando uma instrução referenciar um comando ' +
|
|
41
|
-
'como `/nome`, entenda que se trata de `/PLUGIN:nome`.';
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Executa um comando do catálogo abrindo o Claude Code na pasta atual, com o
|
|
45
|
-
* pacote carregado como plugin da sessão — sem instalar nada no projeto.
|
|
46
|
-
*/
|
|
47
|
-
export function runCommand(id, args = [], claudeFlags = []) {
|
|
48
|
-
const catalog = loadCatalog();
|
|
49
|
-
const ids = runnableIds(catalog);
|
|
50
|
-
const wanted = id.replace(/^\//, '');
|
|
51
|
-
|
|
52
|
-
if (!ids.includes(wanted)) {
|
|
53
|
-
const near = suggestIds(wanted, ids);
|
|
54
|
-
console.error(`Comando desconhecido: ${wanted}`);
|
|
55
|
-
if (near.length) console.error(`\nVocê quis dizer: ${near.join(', ')}`);
|
|
56
|
-
console.error('\nRode `npx @fontdata/ai-harness list` para ver o catálogo completo.');
|
|
57
|
-
return 1;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const name = pluginName();
|
|
61
|
-
const prompt = [`/${name}:${wanted}`, ...args].join(' ').trim();
|
|
62
|
-
const argv = [
|
|
63
|
-
'--plugin-dir',
|
|
64
|
-
pluginRoot,
|
|
65
|
-
'--append-system-prompt',
|
|
66
|
-
SYSTEM_NOTE.replaceAll('PLUGIN', name),
|
|
67
|
-
...claudeFlags,
|
|
68
|
-
'--',
|
|
69
|
-
prompt,
|
|
70
|
-
];
|
|
71
|
-
|
|
72
|
-
const result = spawn(argv);
|
|
73
|
-
|
|
74
|
-
if (result.error?.code === 'ENOENT') {
|
|
75
|
-
console.error(
|
|
76
|
-
'Claude Code não encontrado no PATH.\n' +
|
|
77
|
-
'Instale com: npm install -g @anthropic-ai/claude-code'
|
|
78
|
-
);
|
|
79
|
-
return 127;
|
|
80
|
-
}
|
|
81
|
-
if (result.error) {
|
|
82
|
-
console.error('Erro ao executar o Claude Code:', result.error.message);
|
|
83
|
-
return 1;
|
|
84
|
-
}
|
|
85
|
-
return result.status ?? 0;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* No Windows o `claude` costuma ser um `.cmd`, que o spawn sem shell não
|
|
90
|
-
* resolve; nesse caso repetimos a chamada pelo shell, com os argumentos citados.
|
|
91
|
-
*/
|
|
92
|
-
function spawn(argv) {
|
|
93
|
-
const direct = spawnSync('claude', argv, { stdio: 'inherit', cwd: process.cwd() });
|
|
94
|
-
if (direct.error?.code === 'ENOENT' && process.platform === 'win32') {
|
|
95
|
-
const quoted = argv.map((arg) => `"${String(arg).replaceAll('"', '\\"')}"`).join(' ');
|
|
96
|
-
return spawnSync(`claude ${quoted}`, { stdio: 'inherit', cwd: process.cwd(), shell: true });
|
|
97
|
-
}
|
|
98
|
-
return direct;
|
|
99
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Audita o projeto em busca de gargalos de performance (queries, bundle, renders, algoritmos).
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Auditoria de performance
|
|
6
|
-
|
|
7
|
-
Foco (opcional — ex.: "backend", "frontend", "tela X", "endpoint Y"): $ARGUMENTS
|
|
8
|
-
|
|
9
|
-
Se eu não especifiquei, analise o projeto como um todo e priorize os pontos de maior impacto.
|
|
10
|
-
|
|
11
|
-
Passos:
|
|
12
|
-
|
|
13
|
-
1. Identifique a stack e analise os pontos quentes mais comuns:
|
|
14
|
-
- **Banco/dados**: queries N+1, falta de índices, `SELECT *`, paginação ausente, chamadas em loop.
|
|
15
|
-
- **Backend**: trabalho síncrono bloqueante, ausência de cache, serialização cara, I/O repetido.
|
|
16
|
-
- **Frontend**: tamanho do bundle, imports pesados, re-renders desnecessários, imagens não otimizadas, ausência de lazy-load.
|
|
17
|
-
- **Algoritmos**: complexidade desnecessária (O(n²) evitável), estruturas de dados inadequadas.
|
|
18
|
-
2. Para cada achado, estime **impacto** (alto/médio/baixo) e **esforço** de correção, com o trecho de evidência (`arquivo:linha`).
|
|
19
|
-
3. Onde possível, **meça** em vez de adivinhar (profiler, `EXPLAIN`, análise de bundle, logs de tempo). Não instale ferramentas novas sem me perguntar.
|
|
20
|
-
4. Apresente um relatório priorizado por **impacto/esforço** com a correção recomendada de cada item. Não altere código sem minha confirmação.
|
|
21
|
-
|
|
22
|
-
## Onde gravar o relatório
|
|
23
|
-
|
|
24
|
-
Grave o relatório em `docs/investigacoes/<yyyy-mm-dd>-<slug>.md` — `<yyyy-mm-dd>` é a data atual e
|
|
25
|
-
`<slug>` resume o tema auditado. **Não** grave em `docs/bugs/`: aquela pasta é só para defeito com
|
|
26
|
-
sintoma reproduzível, causa-raiz e correção. Se a auditoria virar trabalho de correção, o plano
|
|
27
|
-
vai para `docs/plans/`.
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Auditoria de segurança e LGPD — segredos, deps vulneráveis, inputs sem validação, configs inseguras e conformidade com a Lei nº 13.709/2018.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Auditoria de segurança e LGPD
|
|
6
|
-
|
|
7
|
-
Foco (opcional): $ARGUMENTS
|
|
8
|
-
|
|
9
|
-
Esta é uma auditoria **defensiva** do próprio projeto, em duas frentes: **segurança técnica** e
|
|
10
|
-
**conformidade com a LGPD**. Se `$ARGUMENTS` restringir o escopo (ex.: `só segurança`, `só lgpd`,
|
|
11
|
-
`autenticação`), respeite-o; sem argumento, rode as duas frentes.
|
|
12
|
-
|
|
13
|
-
## Parte 1 — Segurança técnica
|
|
14
|
-
|
|
15
|
-
1. **Segredos**: procure chaves de API, senhas, tokens e credenciais hardcoded no código e no histórico recente. Verifique se `.env` está no `.gitignore`.
|
|
16
|
-
2. **Dependências**: rode o auditor da stack (`npm audit`, `pip-audit`, `osv-scanner`, etc., se disponível) e liste vulnerabilidades conhecidas por severidade.
|
|
17
|
-
3. **Validação de entrada**: identifique inputs sem validação/sanitização — risco de injeção (SQL, comando, XSS), path traversal e desserialização insegura.
|
|
18
|
-
4. **AuthZ/AuthN**: rotas sem proteção, checagem de permissão ausente, segredos de sessão fracos, CORS permissivo demais.
|
|
19
|
-
5. **Configuração**: modo debug em produção, headers de segurança ausentes, TLS, exposição de stack traces.
|
|
20
|
-
6. Classifique cada achado em **CRÍTICO / ALTO / MÉDIO / BAIXO** (estilo CVSS), com evidência (`arquivo:linha`) e correção recomendada. Não exponha valores de segredos reais no relatório — referencie só a localização. Não altere código sem minha confirmação.
|
|
21
|
-
|
|
22
|
-
## Parte 2 — Conformidade com a LGPD
|
|
23
|
-
|
|
24
|
-
Use a skill **`lgpd-checker`**, instalada em `.claude/skills/lgpd-checker/`. Leia
|
|
25
|
-
`.claude/skills/lgpd-checker/SKILL.md` e siga as fases dela; consulte
|
|
26
|
-
`references/checklist.md` para a lista completa de verificações e `references/lgpd-artigos.md`
|
|
27
|
-
para citar o artigo correto. Em resumo:
|
|
28
|
-
|
|
29
|
-
- **Fase 1 — Reconhecimento**: tipo de aplicação, stack e se o sistema trata dados pessoais de
|
|
30
|
-
pessoa física. Se não tratar, registre isso com justificativa e pule a Parte 2.
|
|
31
|
-
- **Fase 2 — Análise por categoria** (CAT-1 a CAT-11): bases legais e consentimento, minimização,
|
|
32
|
-
dados sensíveis, segurança técnica, logs e auditoria, direitos dos titulares, retenção e
|
|
33
|
-
eliminação, privacy by design, transferência internacional, documentação e governança,
|
|
34
|
-
notificação de incidentes. Faça **busca ativa** no código — não presuma conformidade.
|
|
35
|
-
- **Fase 3 — Severidade e veredito**: classifique cada achado em
|
|
36
|
-
**CRÍTICO / ALTO / MÉDIO / BAIXO / INFO**, sempre citando o artigo da LGPD e uma recomendação
|
|
37
|
-
técnica concreta. Conclua o veredito de conformidade: ✅ CONFORME (nenhum CRÍTICO/ALTO),
|
|
38
|
-
⚠️ PARCIALMENTE CONFORME (só MÉDIO/BAIXO) ou ❌ NÃO CONFORME (algum CRÍTICO/ALTO).
|
|
39
|
-
|
|
40
|
-
CAT-4 (segurança técnica) se sobrepõe à Parte 1: **não duplique achados** — registre o achado uma
|
|
41
|
-
vez na Parte 1 e referencie-o na CAT-4 com o artigo da LGPD correspondente.
|
|
42
|
-
|
|
43
|
-
## Relatório
|
|
44
|
-
|
|
45
|
-
Entregue um relatório único com:
|
|
46
|
-
|
|
47
|
-
1. **Sumário executivo** — contagem de achados por severidade em cada frente e o veredito de
|
|
48
|
-
conformidade LGPD.
|
|
49
|
-
2. **Achados críticos primeiro**, para eu saber o que atacar antes.
|
|
50
|
-
3. **Segurança técnica** — achados da Parte 1 (severidade, `arquivo:linha`, correção).
|
|
51
|
-
4. **Conformidade LGPD** — achados por categoria, no formato de
|
|
52
|
-
`.claude/skills/lgpd-checker/references/report-template.md`, com artigo citado.
|
|
53
|
-
5. **Pontos positivos** — o que já está correto e conforme.
|
|
54
|
-
6. **Plano de ação** em ordem de prioridade.
|
|
55
|
-
|
|
56
|
-
Se faltar código para avaliar alguma categoria, diga explicitamente
|
|
57
|
-
("Não foi possível avaliar [CAT-X] — arquivos de [tipo] não encontrados") em vez de presumir.
|
|
58
|
-
|
|
59
|
-
## Onde gravar o relatório
|
|
60
|
-
|
|
61
|
-
Grave o relatório em `docs/investigacoes/<yyyy-mm-dd>-<slug>.md` — `<yyyy-mm-dd>` é a data atual e
|
|
62
|
-
`<slug>` resume o tema auditado. **Não** grave em `docs/bugs/`: aquela pasta é só para defeito com
|
|
63
|
-
sintoma reproduzível, causa-raiz e correção. Se a auditoria virar trabalho de correção, o plano
|
|
64
|
-
vai para `docs/plans/`.
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Navega a aplicação via Playwright MCP e audita UX/UI e/ou acessibilidade (a11y), gerando um relatório por tela e severidade.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Auditoria de interface via navegador
|
|
6
|
-
|
|
7
|
-
Usando o **MCP do Playwright**, abra o navegador **na minha tela** (para que eu acompanhe a navegação) e audite a aplicação.
|
|
8
|
-
|
|
9
|
-
## Parâmetros
|
|
10
|
-
|
|
11
|
-
Podem vir em `$ARGUMENTS`:
|
|
12
|
-
|
|
13
|
-
$ARGUMENTS
|
|
14
|
-
|
|
15
|
-
Preciso de quatro coisas. Para o que **não** veio em `$ARGUMENTS`, **pare e me pergunte antes de abrir o navegador**, oferecendo o exemplo como valor padrão que eu posso aceitar ou substituir:
|
|
16
|
-
|
|
17
|
-
- **Lente da auditoria:** `ux` (UX/UI), `a11y` (acessibilidade) ou `tudo` (as duas) — padrão: `tudo`.
|
|
18
|
-
- **URL** da aplicação (ex.: `http://localhost:3000`)
|
|
19
|
-
- **Usuário** para login (ex.: `admin@admin.com.br`)
|
|
20
|
-
- **Senha** para login (ex.: `admin`)
|
|
21
|
-
|
|
22
|
-
Só prossiga depois que eu confirmar. Se `$ARGUMENTS` já trouxer os dados, use-os diretamente sem perguntar.
|
|
23
|
-
|
|
24
|
-
## Passos
|
|
25
|
-
|
|
26
|
-
1. Faça login e navegue por **todas** as telas, clicando em todos os menus e botões.
|
|
27
|
-
2. Para cada tela, audite conforme a lente escolhida:
|
|
28
|
-
- **UX/UI** — clareza e consistência visual, hierarquia, feedback das ações, estados de vazio/erro/carregamento, fluxos confusos, responsividade.
|
|
29
|
-
- **a11y (WCAG AA)** — contraste de cores, uso correto de ARIA e roles, navegação por teclado (tab order, foco visível, atalhos), textos alternativos em imagens, labels em formulários, hierarquia de headings e foco em modais.
|
|
30
|
-
3. Classifique cada achado por severidade — **CRÍTICO** (bloqueia o uso), **SÉRIO**, **MODERADO**, **MENOR** — citando o critério **WCAG** quando for um achado de a11y.
|
|
31
|
-
4. Compile um **relatório único**, agrupado por **tela** e **severidade**, com a correção recomendada de cada item. Não altere código — apenas reporte o que precisa ser criado ou melhorado.
|
|
32
|
-
|
|
33
|
-
## Onde gravar o relatório
|
|
34
|
-
|
|
35
|
-
Grave o relatório em `docs/investigacoes/<yyyy-mm-dd>-<slug>.md` — `<yyyy-mm-dd>` é a data atual e
|
|
36
|
-
`<slug>` resume o tema auditado. **Não** grave em `docs/bugs/`: aquela pasta é só para defeito com
|
|
37
|
-
sintoma reproduzível, causa-raiz e correção. Se a auditoria virar trabalho de correção, o plano
|
|
38
|
-
vai para `docs/plans/`.
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Varre o projeto em busca de código morto (imports, exports, funções e arquivos não usados) e propõe remoção.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Caça ao código morto
|
|
6
|
-
|
|
7
|
-
Escopo (opcional — pasta ou módulo): $ARGUMENTS
|
|
8
|
-
|
|
9
|
-
Passos:
|
|
10
|
-
|
|
11
|
-
1. Varra o projeto procurando: imports não utilizados, exports sem consumidores, funções/variáveis/classes nunca referenciadas, arquivos órfãos e dependências declaradas mas não usadas.
|
|
12
|
-
2. Prefira ferramentas já disponíveis na stack (ex.: linter, `knip`, `ts-prune`, `depcheck`, `vulture`, analisadores nativos). **Não instale nada novo** sem me perguntar.
|
|
13
|
-
3. Para cada achado, classifique a confiança: **ALTA** (claramente morto), **MÉDIA** (pode ser usado via reflexão/dinâmica/rota/teste), **BAIXA** (suspeito). Cuidado com APIs públicas, entrypoints, plugins e código acessado por string.
|
|
14
|
-
4. Apresente a lista agrupada por confiança e **pergunte o que devo remover**. Não apague nada de **MÉDIA/BAIXA** sem confirmação.
|
|
15
|
-
5. Após remover, rode build e testes para garantir que nada quebrou.
|
|
16
|
-
|
|
17
|
-
## Onde gravar o relatório
|
|
18
|
-
|
|
19
|
-
Grave o relatório em `docs/investigacoes/<yyyy-mm-dd>-<slug>.md` — `<yyyy-mm-dd>` é a data atual e
|
|
20
|
-
`<slug>` resume o tema auditado. **Não** grave em `docs/bugs/`: aquela pasta é só para defeito com
|
|
21
|
-
sintoma reproduzível, causa-raiz e correção. Se a auditoria virar trabalho de correção, o plano
|
|
22
|
-
vai para `docs/plans/`.
|