vireum-spec-cli 0.1.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/dist/commands/brief.js +150 -0
- package/dist/commands/distill.js +372 -0
- package/dist/commands/health.js +172 -0
- package/dist/commands/init.js +261 -0
- package/dist/commands/prioritize.js +202 -0
- package/dist/commands/setup.js +436 -0
- package/dist/commands/skills.js +147 -0
- package/dist/commands/verify-mcps.js +148 -0
- package/dist/index.js +55 -0
- package/package.json +39 -0
- package/src/skills/bug-fix.md +14 -0
- package/src/skills/contract-first.md +21 -0
- package/src/skills/new-demand.md +14 -0
- package/src/skills/scope-check.md +21 -0
- package/src/skills/spec-update.md +30 -0
- package/src/skills/task-implement.md +14 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.runSetup = runSetup;
|
|
40
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
41
|
+
const prompts_1 = require("@inquirer/prompts");
|
|
42
|
+
const ora_1 = __importDefault(require("ora"));
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
async function runSetup() {
|
|
46
|
+
console.log(chalk_1.default.hex('#2D7DD2').bold('\n Vireum Spec — Setup\n'));
|
|
47
|
+
console.log(chalk_1.default.gray(' Configure a stack e o protocolo da IA para este projeto\n'));
|
|
48
|
+
const specDir = path.join(process.cwd(), '.spec');
|
|
49
|
+
const vireumDir = path.join(process.cwd(), '.vireum');
|
|
50
|
+
const cursorDir = path.join(process.cwd(), '.cursor', 'rules');
|
|
51
|
+
if (!fs.existsSync(path.join(specDir, 'briefing.md'))) {
|
|
52
|
+
console.log(chalk_1.default.red('\n❌ briefing.md não encontrado.'));
|
|
53
|
+
console.log(chalk_1.default.gray(' Execute primeiro: ') + chalk_1.default.white('vireum-spec init\n'));
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
if (!fs.existsSync(path.join(specDir, 'INDEX.md'))) {
|
|
57
|
+
console.log(chalk_1.default.red('\n❌ Spec não gerado ainda.'));
|
|
58
|
+
console.log(chalk_1.default.gray(' Execute primeiro: ') + chalk_1.default.white('vireum-spec distill\n'));
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
// ── Stack ──────────────────────────────────────────────────────────────────
|
|
62
|
+
console.log(chalk_1.default.hex('#2D7DD2').bold('⚙️ Stack do Projeto\n'));
|
|
63
|
+
const stack = {
|
|
64
|
+
frontend: await (0, prompts_1.select)({
|
|
65
|
+
message: 'Frontend:',
|
|
66
|
+
choices: [
|
|
67
|
+
{ value: 'Next.js' }, { value: 'React' }, { value: 'Vue' },
|
|
68
|
+
{ value: 'Nuxt' }, { value: 'Outro' }, { value: 'Nenhum' },
|
|
69
|
+
],
|
|
70
|
+
}),
|
|
71
|
+
backend: await (0, prompts_1.select)({
|
|
72
|
+
message: 'Backend:',
|
|
73
|
+
choices: [
|
|
74
|
+
{ value: 'Node.js + Express' }, { value: 'Node.js + Fastify' },
|
|
75
|
+
{ value: 'NestJS' }, { value: 'Python + FastAPI' },
|
|
76
|
+
{ value: 'Outro' }, { value: 'Nenhum' },
|
|
77
|
+
],
|
|
78
|
+
}),
|
|
79
|
+
banco: await (0, prompts_1.select)({
|
|
80
|
+
message: 'Banco de dados:',
|
|
81
|
+
choices: [
|
|
82
|
+
{ value: 'PostgreSQL' }, { value: 'MySQL' },
|
|
83
|
+
{ value: 'SQLite' }, { value: 'MongoDB' }, { value: 'Outro' },
|
|
84
|
+
],
|
|
85
|
+
}),
|
|
86
|
+
orm: await (0, prompts_1.select)({
|
|
87
|
+
message: 'ORM / Query Builder:',
|
|
88
|
+
choices: [
|
|
89
|
+
{ value: 'Prisma' }, { value: 'TypeORM' }, { value: 'Drizzle' },
|
|
90
|
+
{ value: 'Sequelize' }, { value: 'Nenhum' }, { value: 'Outro' },
|
|
91
|
+
],
|
|
92
|
+
}),
|
|
93
|
+
cache: await (0, prompts_1.select)({
|
|
94
|
+
message: 'Cache / Filas:',
|
|
95
|
+
choices: [
|
|
96
|
+
{ value: 'Redis + BullMQ' }, { value: 'Redis simples' },
|
|
97
|
+
{ value: 'Nenhum' }, { value: 'Outro' },
|
|
98
|
+
],
|
|
99
|
+
}),
|
|
100
|
+
auth: await (0, prompts_1.select)({
|
|
101
|
+
message: 'Autenticação:',
|
|
102
|
+
choices: [
|
|
103
|
+
{ value: 'JWT + Refresh Token' }, { value: 'NextAuth' },
|
|
104
|
+
{ value: 'Supabase Auth' }, { value: 'Clerk' }, { value: 'Outro' },
|
|
105
|
+
],
|
|
106
|
+
}),
|
|
107
|
+
multiTenant: await (0, prompts_1.confirm)({ message: 'Projeto multi-tenant?', default: false }),
|
|
108
|
+
};
|
|
109
|
+
stack.tenantStrategy = stack.multiTenant
|
|
110
|
+
? await (0, prompts_1.select)({
|
|
111
|
+
message: 'Estratégia de multi-tenancy:',
|
|
112
|
+
choices: [
|
|
113
|
+
{ value: 'Row-level (tenantId)' },
|
|
114
|
+
{ value: 'Schema separado por tenant' },
|
|
115
|
+
{ value: 'Banco separado por tenant' },
|
|
116
|
+
],
|
|
117
|
+
})
|
|
118
|
+
: '';
|
|
119
|
+
// ── Infra ──────────────────────────────────────────────────────────────────
|
|
120
|
+
console.log(chalk_1.default.hex('#2D7DD2').bold('\n🏗️ Infraestrutura\n'));
|
|
121
|
+
const infra = {
|
|
122
|
+
hospedagem: await (0, prompts_1.select)({
|
|
123
|
+
message: 'Hospedagem:',
|
|
124
|
+
choices: [
|
|
125
|
+
{ value: 'DigitalOcean' }, { value: 'Hetzner' }, { value: 'AWS' },
|
|
126
|
+
{ value: 'Vercel + Railway' }, { value: 'Outro' },
|
|
127
|
+
],
|
|
128
|
+
}),
|
|
129
|
+
containerizacao: await (0, prompts_1.select)({
|
|
130
|
+
message: 'Containerização:',
|
|
131
|
+
choices: [
|
|
132
|
+
{ value: 'Docker + Docker Compose' },
|
|
133
|
+
{ value: 'Docker simples' },
|
|
134
|
+
{ value: 'Nenhum' },
|
|
135
|
+
],
|
|
136
|
+
}),
|
|
137
|
+
cicd: await (0, prompts_1.confirm)({ message: 'CI/CD ativo desde o início?', default: false }),
|
|
138
|
+
};
|
|
139
|
+
infra.cicdFerramenta = infra.cicd
|
|
140
|
+
? await (0, prompts_1.select)({
|
|
141
|
+
message: 'Ferramenta de CI/CD:',
|
|
142
|
+
choices: [
|
|
143
|
+
{ value: 'GitHub Actions' }, { value: 'GitLab CI' }, { value: 'Outro' },
|
|
144
|
+
],
|
|
145
|
+
})
|
|
146
|
+
: '';
|
|
147
|
+
// ── MCPs ───────────────────────────────────────────────────────────────────
|
|
148
|
+
console.log(chalk_1.default.hex('#2D7DD2').bold('\n🔌 MCPs — Ferramentas da IA\n'));
|
|
149
|
+
const mcpsSelecionados = await (0, prompts_1.checkbox)({
|
|
150
|
+
message: 'Selecione os MCPs para este projeto:',
|
|
151
|
+
choices: [
|
|
152
|
+
{ name: 'github — PRs, issues, branches', value: 'github', checked: true },
|
|
153
|
+
{ name: 'database — consultar banco em dev', value: 'database', checked: true },
|
|
154
|
+
{ name: 'browser — testar endpoints e fluxos', value: 'browser', checked: true },
|
|
155
|
+
{ name: 'puppeteer — testes de UI', value: 'puppeteer', checked: false },
|
|
156
|
+
{ name: 'docker — gerenciar containers', value: 'docker', checked: false },
|
|
157
|
+
{ name: 'redis — inspecionar cache e filas', value: 'redis', checked: false },
|
|
158
|
+
],
|
|
159
|
+
});
|
|
160
|
+
// ── Gerar arquivos ─────────────────────────────────────────────────────────
|
|
161
|
+
console.log('');
|
|
162
|
+
const projeto = extrairProjeto(path.join(specDir, 'INDEX.md'));
|
|
163
|
+
const dados = { stack, infra, mcps: mcpsSelecionados, projeto };
|
|
164
|
+
for (const dir of [vireumDir, cursorDir]) {
|
|
165
|
+
if (!fs.existsSync(dir))
|
|
166
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
167
|
+
}
|
|
168
|
+
const arquivos = [
|
|
169
|
+
{ path: path.join(specDir, 'architecture.md'), conteudo: gerarArchitecture(dados), msg: 'Atualizando architecture.md...' },
|
|
170
|
+
{ path: path.join(specDir, 'mcp-setup.md'), conteudo: gerarMcpSetup(dados), msg: 'Gerando mcp-setup.md...' },
|
|
171
|
+
{ path: path.join(vireumDir, 'rules.md'), conteudo: gerarRulesGlobal(), msg: 'Gerando .vireum/rules.md...' },
|
|
172
|
+
{ path: path.join(vireumDir, 'mcps.md'), conteudo: gerarMcpsGlobal(dados), msg: 'Gerando .vireum/mcps.md...' },
|
|
173
|
+
{ path: path.join(process.cwd(), 'CLAUDE.md'), conteudo: gerarClaudeMd(dados), msg: 'Gerando CLAUDE.md...' },
|
|
174
|
+
{ path: path.join(process.cwd(), 'AGENTS.md'), conteudo: gerarAgentsMd(dados), msg: 'Gerando AGENTS.md...' },
|
|
175
|
+
{ path: path.join(cursorDir, 'vireum.mdc'), conteudo: gerarCursorRules(dados), msg: 'Gerando .cursor/rules/vireum.mdc...' },
|
|
176
|
+
];
|
|
177
|
+
for (const arq of arquivos) {
|
|
178
|
+
const s = (0, ora_1.default)(arq.msg).start();
|
|
179
|
+
await sleep(400);
|
|
180
|
+
fs.writeFileSync(arq.path, arq.conteudo, 'utf-8');
|
|
181
|
+
s.succeed(path.relative(process.cwd(), arq.path));
|
|
182
|
+
}
|
|
183
|
+
console.log(chalk_1.default.green.bold('\n✅ Setup concluído!\n'));
|
|
184
|
+
console.log(chalk_1.default.gray(' Protocolo da IA configurado para Claude Code, Codex CLI e Cursor\n'));
|
|
185
|
+
console.log(chalk_1.default.gray(' Próximo passo: ') + chalk_1.default.white('vireum-spec prioritize') + chalk_1.default.gray(' para classificar as features\n'));
|
|
186
|
+
}
|
|
187
|
+
// ─── HELPERS ──────────────────────────────────────────────────────────────────
|
|
188
|
+
function extrairProjeto(indexPath) {
|
|
189
|
+
try {
|
|
190
|
+
const content = fs.readFileSync(indexPath, 'utf-8');
|
|
191
|
+
const match = content.match(/# INDEX — (.+)/);
|
|
192
|
+
return match ? match[1].trim() : 'projeto';
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return 'projeto';
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function sleep(ms) {
|
|
199
|
+
return new Promise(r => setTimeout(r, ms));
|
|
200
|
+
}
|
|
201
|
+
// ─── GERADORES ────────────────────────────────────────────────────────────────
|
|
202
|
+
function gerarArchitecture(d) {
|
|
203
|
+
const { stack, infra, mcps, projeto } = d;
|
|
204
|
+
const tenant = stack.multiTenant
|
|
205
|
+
? `\n## Multi-Tenancy\n- Estratégia: ${stack.tenantStrategy}\n- Nunca fazer query sem filtro de tenantId`
|
|
206
|
+
: '';
|
|
207
|
+
return `# Architecture — ${projeto}
|
|
208
|
+
|
|
209
|
+
> Atualizado via vireum-spec setup
|
|
210
|
+
> A IA deve registrar aqui cada decisão técnica relevante
|
|
211
|
+
|
|
212
|
+
## Stack
|
|
213
|
+
- Frontend: ${stack.frontend}
|
|
214
|
+
- Backend: ${stack.backend}
|
|
215
|
+
- Banco de dados: ${stack.banco}
|
|
216
|
+
- ORM: ${stack.orm}
|
|
217
|
+
- Cache / Filas: ${stack.cache}
|
|
218
|
+
- Auth: ${stack.auth}
|
|
219
|
+
${tenant}
|
|
220
|
+
|
|
221
|
+
## Infraestrutura
|
|
222
|
+
- Hospedagem: ${infra.hospedagem}
|
|
223
|
+
- Containerização: ${infra.containerizacao}
|
|
224
|
+
- CI/CD: ${infra.cicd ? infra.cicdFerramenta : 'Não configurado'}
|
|
225
|
+
|
|
226
|
+
## MCPs Ativos
|
|
227
|
+
${mcps.map((m) => `- ${m}`).join('\n')}
|
|
228
|
+
|
|
229
|
+
## Decisões Arquiteturais
|
|
230
|
+
> A IA deve registrar aqui cada decisão técnica com justificativa
|
|
231
|
+
|
|
232
|
+
| Data | Decisão | Alternativas descartadas | Motivo |
|
|
233
|
+
|------|---------|--------------------------|--------|
|
|
234
|
+
| | | | |
|
|
235
|
+
`;
|
|
236
|
+
}
|
|
237
|
+
function gerarMcpSetup(d) {
|
|
238
|
+
const mcpInfo = {
|
|
239
|
+
github: 'https://github.com/modelcontextprotocol/servers/tree/main/src/github',
|
|
240
|
+
database: 'https://github.com/modelcontextprotocol/servers/tree/main/src/postgres',
|
|
241
|
+
browser: 'https://github.com/modelcontextprotocol/servers/tree/main/src/puppeteer',
|
|
242
|
+
puppeteer: 'https://github.com/modelcontextprotocol/servers/tree/main/src/puppeteer',
|
|
243
|
+
docker: 'https://github.com/modelcontextprotocol/servers',
|
|
244
|
+
redis: 'https://github.com/modelcontextprotocol/servers',
|
|
245
|
+
};
|
|
246
|
+
const lista = d.mcps.map((m) => `### ${m}\n- Instalação: ${mcpInfo[m] || 'Ver documentação oficial'}\n- Credenciais: configurar manualmente após instalação`).join('\n\n');
|
|
247
|
+
return `# MCP Setup — ${d.projeto}
|
|
248
|
+
|
|
249
|
+
> MCPs necessários para este projeto.
|
|
250
|
+
> Instalação é feita manualmente — o framework não acessa credenciais.
|
|
251
|
+
|
|
252
|
+
## MCPs do Projeto
|
|
253
|
+
${lista}
|
|
254
|
+
|
|
255
|
+
## Como instalar
|
|
256
|
+
1. Acesse o link de cada MCP acima
|
|
257
|
+
2. Siga as instruções de instalação
|
|
258
|
+
3. Configure as credenciais manualmente no seu cliente (Claude Code / Cursor)
|
|
259
|
+
4. Execute: vireum-spec verify-mcps (em breve)
|
|
260
|
+
`;
|
|
261
|
+
}
|
|
262
|
+
function gerarRulesGlobal() {
|
|
263
|
+
return `# Rules — Global Vireum
|
|
264
|
+
|
|
265
|
+
> Regras globais que se aplicam a TODOS os projetos Vireum.
|
|
266
|
+
> Nunca editar por projeto. Em conflito com .spec/rules.md, estas prevalecem.
|
|
267
|
+
|
|
268
|
+
## Regras de Escopo
|
|
269
|
+
- Nunca implementar funcionalidade fora do requirements.md sem criar task [PENDING]
|
|
270
|
+
- Nunca puxar task do backlog para active sem validação humana explícita
|
|
271
|
+
- Sempre avisar escopo creep antes de implementar — parar e perguntar
|
|
272
|
+
|
|
273
|
+
## Regras de Spec
|
|
274
|
+
- Nunca marcar task como done sem validar os critérios de aceitação
|
|
275
|
+
- Nunca tomar decisão de arquitetura sem registrar em architecture.md com justificativa
|
|
276
|
+
- Sempre definir contrato de interface antes de implementar features com frontend e backend
|
|
277
|
+
- Ao identificar risco novo, adicionar em risks.md antes de continuar
|
|
278
|
+
|
|
279
|
+
## Regras de Contexto
|
|
280
|
+
- Sempre ler INDEX.md no início de cada sessão
|
|
281
|
+
- Carregar outros arquivos de spec apenas quando a task exigir
|
|
282
|
+
- Registrar decisões relevantes em changelog.md com data
|
|
283
|
+
|
|
284
|
+
## Regras de Tasks
|
|
285
|
+
- Bugs viram hotfix com tag [H] — nunca são tratados como tasks normais
|
|
286
|
+
- Demandas novas do cliente viram [PENDING] no backlog — nunca vão direto para active
|
|
287
|
+
- Task só é done quando critérios de aceitação estão validados
|
|
288
|
+
|
|
289
|
+
## Nunca
|
|
290
|
+
- Implementar sem ler o spec primeiro
|
|
291
|
+
- Tomar decisão de lib ou stack sem documentar o porquê
|
|
292
|
+
- Responder dúvida de escopo sem consultar requirements.md
|
|
293
|
+
- Comunicar diretamente com o cliente — isso é papel do dev
|
|
294
|
+
`;
|
|
295
|
+
}
|
|
296
|
+
function gerarMcpsGlobal(d) {
|
|
297
|
+
return `# MCPs — Global Vireum
|
|
298
|
+
|
|
299
|
+
> MCPs padrão disponíveis nos projetos Vireum.
|
|
300
|
+
> MCPs ativos por projeto estão em .spec/architecture.md
|
|
301
|
+
|
|
302
|
+
## Stack Padrão
|
|
303
|
+
- filesystem — leitura e escrita no projeto (nativo)
|
|
304
|
+
- github — PRs, issues, branches referenciando tasks
|
|
305
|
+
- database — validar schema e dados em desenvolvimento
|
|
306
|
+
- browser — testar endpoints e validar fluxos
|
|
307
|
+
- puppeteer — testes de jornada de UI
|
|
308
|
+
- docker — gerenciar containers em desenvolvimento
|
|
309
|
+
- redis — inspecionar cache e filas (quando aplicável)
|
|
310
|
+
|
|
311
|
+
## MCPs Ativos Neste Projeto
|
|
312
|
+
${d.mcps.map((m) => `- ${m}`).join('\n')}
|
|
313
|
+
|
|
314
|
+
## Quando usar cada MCP
|
|
315
|
+
- Task concluída → github: criar PR referenciando a task
|
|
316
|
+
- Bug identificado → github: abrir issue com contexto
|
|
317
|
+
- Decisão de schema → database: validar antes de implementar
|
|
318
|
+
- Feature implementada → browser: testar endpoint ou fluxo
|
|
319
|
+
- Jornada de UI → puppeteer: validar fluxo completo
|
|
320
|
+
`;
|
|
321
|
+
}
|
|
322
|
+
function gerarClaudeMd(d) {
|
|
323
|
+
const { projeto, stack, mcps } = d;
|
|
324
|
+
const tenant = stack.multiTenant
|
|
325
|
+
? '\n- NUNCA fazer query sem filtro de tenantId — projeto multi-tenant' : '';
|
|
326
|
+
return `# ${projeto} — Vireum Spec Protocol
|
|
327
|
+
|
|
328
|
+
> Este projeto usa Spec Driven Development pela Vireum Desenvolvimento.
|
|
329
|
+
> Leia este arquivo completamente antes de qualquer ação.
|
|
330
|
+
|
|
331
|
+
## Início de cada sessão
|
|
332
|
+
1. Leia \`.spec/INDEX.md\` — estado atual do projeto
|
|
333
|
+
2. Identifique o modo da sessão pela solicitação do dev
|
|
334
|
+
3. Carregue arquivos adicionais apenas se a task exigir
|
|
335
|
+
|
|
336
|
+
## Modos de operação
|
|
337
|
+
|
|
338
|
+
### Modo 1 — Implementar
|
|
339
|
+
Acionado por: "desenvolve", "implementa", "cria", + nome de task
|
|
340
|
+
1. Leia \`.spec/tasks/active.md\`
|
|
341
|
+
2. Leia \`.spec/requirements.md\` para contexto da feature
|
|
342
|
+
3. Implemente seguindo os critérios de aceitação da task
|
|
343
|
+
4. Ao concluir: marque como done, mova para \`tasks/done.md\`, atualize \`INDEX.md\`
|
|
344
|
+
5. Se decisão arquitetural tomada: registre em \`architecture.md\`
|
|
345
|
+
|
|
346
|
+
### Modo 2 — Bug
|
|
347
|
+
Acionado por: "erro", "bug", "quebrou", "não funciona"
|
|
348
|
+
1. Crie hotfix em \`tasks/active.md\` com tag [H] e prioridade crítica
|
|
349
|
+
2. Identifique e resolva a causa raiz
|
|
350
|
+
3. Registre causa raiz em \`changelog.md\`
|
|
351
|
+
4. Verifique se o bug afeta outras tasks em \`tasks/active.md\`
|
|
352
|
+
|
|
353
|
+
### Modo 3 — Nova demanda
|
|
354
|
+
Acionado por: "cliente pediu", "adiciona", "quero incluir" (fora do spec)
|
|
355
|
+
1. Verifique se já existe em \`.spec/requirements.md\`
|
|
356
|
+
2. Se não existir: crie task com tag [PENDING] em \`tasks/backlog.md\`
|
|
357
|
+
3. Informe o impacto estimado e aguarde decisão do dev
|
|
358
|
+
4. NUNCA implemente demanda nova sem aprovação explícita
|
|
359
|
+
|
|
360
|
+
### Modo 4 — Dúvida de escopo
|
|
361
|
+
Acionado por: "como deve funcionar", "o que foi combinado", "qual o comportamento"
|
|
362
|
+
1. Leia \`.spec/requirements.md\`
|
|
363
|
+
2. Responda com base no spec — não invente comportamento
|
|
364
|
+
|
|
365
|
+
## Regras globais
|
|
366
|
+
Leia \`.vireum/rules.md\` — aplicam-se a todas as sessões.
|
|
367
|
+
|
|
368
|
+
## Regras do projeto
|
|
369
|
+
Leia \`.spec/rules.md\` — regras específicas deste projeto.
|
|
370
|
+
|
|
371
|
+
## Stack
|
|
372
|
+
- Frontend: ${stack.frontend}
|
|
373
|
+
- Backend: ${stack.backend}
|
|
374
|
+
- Banco: ${stack.banco}
|
|
375
|
+
- Auth: ${stack.auth}${tenant}
|
|
376
|
+
|
|
377
|
+
## MCPs ativos
|
|
378
|
+
${mcps.map((m) => `- ${m}`).join('\n')}
|
|
379
|
+
|
|
380
|
+
## Alertas
|
|
381
|
+
- Escopo creep: se a solicitação não está em requirements.md → PARAR e avisar
|
|
382
|
+
- Decisão de lib nova: registrar em architecture.md antes de usar
|
|
383
|
+
- Risco identificado: adicionar em risks.md antes de continuar
|
|
384
|
+
`;
|
|
385
|
+
}
|
|
386
|
+
function gerarAgentsMd(d) {
|
|
387
|
+
return `# ${d.projeto} — Vireum Spec Protocol (Codex CLI / Agents)
|
|
388
|
+
|
|
389
|
+
> Mesmo protocolo do CLAUDE.md adaptado para Codex CLI e outros agentes.
|
|
390
|
+
> Leia CLAUDE.md para o protocolo completo.
|
|
391
|
+
|
|
392
|
+
## Início de cada sessão
|
|
393
|
+
1. Leia \`.spec/INDEX.md\`
|
|
394
|
+
2. Identifique o modo pela solicitação
|
|
395
|
+
3. Siga o protocolo em CLAUDE.md
|
|
396
|
+
|
|
397
|
+
## Regras globais
|
|
398
|
+
Ver \`.vireum/rules.md\`
|
|
399
|
+
|
|
400
|
+
## Regras do projeto
|
|
401
|
+
Ver \`.spec/rules.md\`
|
|
402
|
+
|
|
403
|
+
## Stack
|
|
404
|
+
- Frontend: ${d.stack.frontend}
|
|
405
|
+
- Backend: ${d.stack.backend}
|
|
406
|
+
- Banco: ${d.stack.banco}
|
|
407
|
+
`;
|
|
408
|
+
}
|
|
409
|
+
function gerarCursorRules(d) {
|
|
410
|
+
return `---
|
|
411
|
+
description: Vireum Spec Protocol — ${d.projeto}
|
|
412
|
+
globs: ["**/*"]
|
|
413
|
+
alwaysApply: true
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
# Vireum Spec Protocol
|
|
417
|
+
|
|
418
|
+
Este projeto usa Spec Driven Development pela Vireum Desenvolvimento.
|
|
419
|
+
|
|
420
|
+
## Início de sessão
|
|
421
|
+
- Sempre leia \`.spec/INDEX.md\` primeiro
|
|
422
|
+
- Carregue outros arquivos de spec apenas quando necessário
|
|
423
|
+
|
|
424
|
+
## Modos
|
|
425
|
+
- Implementar → leia tasks/active.md, siga critérios de aceitação
|
|
426
|
+
- Bug → crie hotfix [H] em active.md, registre causa raiz em changelog.md
|
|
427
|
+
- Nova demanda → crie [PENDING] em backlog.md, aguarde aprovação
|
|
428
|
+
- Dúvida de escopo → consulte requirements.md
|
|
429
|
+
|
|
430
|
+
## Regras
|
|
431
|
+
- Ver \`.vireum/rules.md\` — regras globais
|
|
432
|
+
- Ver \`.spec/rules.md\` — regras do projeto
|
|
433
|
+
- Nunca implementar fora do spec sem [PENDING] aprovado
|
|
434
|
+
- Nunca marcar done sem critérios validados
|
|
435
|
+
`;
|
|
436
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.runSkills = runSkills;
|
|
40
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
41
|
+
const prompts_1 = require("@inquirer/prompts");
|
|
42
|
+
const ora_1 = __importDefault(require("ora"));
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const os = __importStar(require("os"));
|
|
46
|
+
const SKILLS = [
|
|
47
|
+
'task-implement',
|
|
48
|
+
'bug-fix',
|
|
49
|
+
'new-demand',
|
|
50
|
+
'spec-update',
|
|
51
|
+
'contract-first',
|
|
52
|
+
'scope-check',
|
|
53
|
+
];
|
|
54
|
+
async function runSkills() {
|
|
55
|
+
console.log(chalk_1.default.hex('#2D7DD2').bold('\n Vireum Spec — Skills\n'));
|
|
56
|
+
console.log(chalk_1.default.gray(' Instala as skills do framework no seu cliente de IA\n'));
|
|
57
|
+
const cliente = await (0, prompts_1.select)({
|
|
58
|
+
message: 'Instalar skills para qual cliente:',
|
|
59
|
+
choices: [
|
|
60
|
+
{ name: 'Claude Code — ~/.claude/skills/', value: 'claude' },
|
|
61
|
+
{ name: 'Cursor — .cursor/rules/ (no projeto)', value: 'cursor' },
|
|
62
|
+
{ name: 'Codex CLI — ~/.codex/skills/', value: 'codex' },
|
|
63
|
+
{ name: 'Todos', value: 'todos' },
|
|
64
|
+
],
|
|
65
|
+
});
|
|
66
|
+
console.log('');
|
|
67
|
+
if (cliente === 'claude' || cliente === 'todos') {
|
|
68
|
+
await instalarClaudeCode();
|
|
69
|
+
}
|
|
70
|
+
if (cliente === 'cursor' || cliente === 'todos') {
|
|
71
|
+
await instalarCursor();
|
|
72
|
+
}
|
|
73
|
+
if (cliente === 'codex' || cliente === 'todos') {
|
|
74
|
+
await instalarCodex();
|
|
75
|
+
}
|
|
76
|
+
console.log(chalk_1.default.green.bold('\n✅ Skills instaladas!\n'));
|
|
77
|
+
console.log(chalk_1.default.gray(' A IA agora conhece o protocolo Vireum para tarefas específicas\n'));
|
|
78
|
+
}
|
|
79
|
+
// ─── INSTALADORES ─────────────────────────────────────────────────────────────
|
|
80
|
+
async function instalarClaudeCode() {
|
|
81
|
+
console.log(chalk_1.default.white.bold(' Claude Code\n'));
|
|
82
|
+
const skillsDir = path.join(os.homedir(), '.claude', 'skills', 'vireum');
|
|
83
|
+
if (!fs.existsSync(skillsDir)) {
|
|
84
|
+
fs.mkdirSync(skillsDir, { recursive: true });
|
|
85
|
+
}
|
|
86
|
+
for (const skill of SKILLS) {
|
|
87
|
+
const s = (0, ora_1.default)(` Instalando ${skill}...`).start();
|
|
88
|
+
await sleep(300);
|
|
89
|
+
const origem = path.join(__dirname, '..', 'skills', `${skill}.md`);
|
|
90
|
+
const destino = path.join(skillsDir, `${skill}.md`);
|
|
91
|
+
if (fs.existsSync(origem)) {
|
|
92
|
+
fs.copyFileSync(origem, destino);
|
|
93
|
+
s.succeed(` ${skill}.md → ~/.claude/skills/vireum/`);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
s.warn(` ${skill}.md não encontrado no framework`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
console.log('');
|
|
100
|
+
}
|
|
101
|
+
async function instalarCursor() {
|
|
102
|
+
console.log(chalk_1.default.white.bold(' Cursor\n'));
|
|
103
|
+
const cursorDir = path.join(process.cwd(), '.cursor', 'rules', 'skills');
|
|
104
|
+
if (!fs.existsSync(cursorDir)) {
|
|
105
|
+
fs.mkdirSync(cursorDir, { recursive: true });
|
|
106
|
+
}
|
|
107
|
+
for (const skill of SKILLS) {
|
|
108
|
+
const s = (0, ora_1.default)(` Instalando ${skill}...`).start();
|
|
109
|
+
await sleep(300);
|
|
110
|
+
const origem = path.join(__dirname, '..', 'skills', `${skill}.md`);
|
|
111
|
+
const destino = path.join(cursorDir, `${skill}.mdc`);
|
|
112
|
+
if (fs.existsSync(origem)) {
|
|
113
|
+
const conteudo = fs.readFileSync(origem, 'utf-8');
|
|
114
|
+
const comHeader = `---\ndescription: Vireum Skill — ${skill}\nglobs: ["**/*"]\nalwaysApply: false\n---\n\n${conteudo}`;
|
|
115
|
+
fs.writeFileSync(destino, comHeader, 'utf-8');
|
|
116
|
+
s.succeed(` ${skill}.mdc → .cursor/rules/skills/`);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
s.warn(` ${skill}.md não encontrado no framework`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
console.log('');
|
|
123
|
+
}
|
|
124
|
+
async function instalarCodex() {
|
|
125
|
+
console.log(chalk_1.default.white.bold(' Codex CLI\n'));
|
|
126
|
+
const skillsDir = path.join(os.homedir(), '.codex', 'skills', 'vireum');
|
|
127
|
+
if (!fs.existsSync(skillsDir)) {
|
|
128
|
+
fs.mkdirSync(skillsDir, { recursive: true });
|
|
129
|
+
}
|
|
130
|
+
for (const skill of SKILLS) {
|
|
131
|
+
const s = (0, ora_1.default)(` Instalando ${skill}...`).start();
|
|
132
|
+
await sleep(300);
|
|
133
|
+
const origem = path.join(__dirname, '..', 'skills', `${skill}.md`);
|
|
134
|
+
const destino = path.join(skillsDir, `${skill}.md`);
|
|
135
|
+
if (fs.existsSync(origem)) {
|
|
136
|
+
fs.copyFileSync(origem, destino);
|
|
137
|
+
s.succeed(` ${skill}.md → ~/.codex/skills/vireum/`);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
s.warn(` ${skill}.md não encontrado no framework`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
console.log('');
|
|
144
|
+
}
|
|
145
|
+
function sleep(ms) {
|
|
146
|
+
return new Promise(r => setTimeout(r, ms));
|
|
147
|
+
}
|