vireum-spec-cli 0.1.0 → 0.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.
@@ -0,0 +1,540 @@
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.runRetrofit = runRetrofit;
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 runRetrofit() {
46
+ console.log(chalk_1.default.hex('#2D7DD2').bold('\n Vireum Spec — Retrofit\n'));
47
+ console.log(chalk_1.default.gray(' Gera o spec a partir de um projeto ja em andamento\n'));
48
+ const cwd = process.cwd();
49
+ const specDir = path.join(cwd, '.spec');
50
+ if (fs.existsSync(path.join(specDir, 'briefing.md'))) {
51
+ const sobrescrever = await (0, prompts_1.confirm)({
52
+ message: 'Ja existe um spec neste projeto. Deseja sobrescrever?',
53
+ default: false,
54
+ });
55
+ if (!sobrescrever)
56
+ process.exit(0);
57
+ }
58
+ // ── Analise automatica ─────────────────────────────────────────────────────
59
+ const spinner = (0, ora_1.default)('Analisando projeto...').start();
60
+ await sleep(800);
61
+ const analise = analisarProjeto(cwd);
62
+ spinner.succeed(`Projeto analisado — ${analise.arquivos} arquivos encontrados`);
63
+ console.log('');
64
+ console.log(chalk_1.default.hex('#2D7DD2').bold(' O que foi detectado automaticamente:\n'));
65
+ if (analise.stack.frontend)
66
+ console.log(chalk_1.default.green(` ✓ Frontend: ${analise.stack.frontend}`));
67
+ if (analise.stack.backend)
68
+ console.log(chalk_1.default.green(` ✓ Backend: ${analise.stack.backend}`));
69
+ if (analise.stack.banco)
70
+ console.log(chalk_1.default.green(` ✓ Banco: ${analise.stack.banco}`));
71
+ if (analise.stack.orm)
72
+ console.log(chalk_1.default.green(` ✓ ORM: ${analise.stack.orm}`));
73
+ if (analise.stack.auth)
74
+ console.log(chalk_1.default.green(` ✓ Auth: ${analise.stack.auth}`));
75
+ if (analise.features.length)
76
+ console.log(chalk_1.default.green(` ✓ ${analise.features.length} rota(s)/feature(s) detectada(s)`));
77
+ if (analise.readme)
78
+ console.log(chalk_1.default.green(` ✓ README encontrado`));
79
+ console.log('');
80
+ // ── Perguntas sobre o que nao foi inferido ─────────────────────────────────
81
+ console.log(chalk_1.default.hex('#2D7DD2').bold(' Perguntas sobre o que nao foi possivel inferir:\n'));
82
+ const projeto = await (0, prompts_1.input)({
83
+ message: 'Nome do projeto:',
84
+ default: analise.nome || path.basename(cwd),
85
+ });
86
+ const cliente = await (0, prompts_1.input)({ message: 'Nome do cliente:' });
87
+ const objetivo = await (0, prompts_1.input)({
88
+ message: 'Objetivo principal do projeto:',
89
+ default: analise.descricao || '',
90
+ });
91
+ const problema = await (0, prompts_1.input)({ message: 'Qual problema o sistema resolve?' });
92
+ const prioridade = await (0, prompts_1.input)({
93
+ message: 'O que ja esta funcionando / qual e a prioridade atual?',
94
+ });
95
+ const usuarios = await (0, prompts_1.input)({ message: 'Quem usa o sistema?' });
96
+ const regras = await (0, prompts_1.input)({
97
+ message: 'Principais regras de negocio (separadas por virgula):',
98
+ });
99
+ const fase = await (0, prompts_1.select)({
100
+ message: 'Em qual fase o projeto esta?',
101
+ choices: [
102
+ { name: 'MVP em desenvolvimento', value: 'MVP em desenvolvimento' },
103
+ { name: 'MVP concluido', value: 'MVP concluido' },
104
+ { name: 'Producao — evolucao ativa', value: 'Producao — evolucao ativa' },
105
+ { name: 'Manutencao', value: 'Manutencao' },
106
+ ],
107
+ });
108
+ const multiTenant = await (0, prompts_1.confirm)({
109
+ message: 'Projeto multi-tenant?',
110
+ default: false,
111
+ });
112
+ const lgpd = await (0, prompts_1.confirm)({
113
+ message: 'Requer conformidade com LGPD?',
114
+ default: false,
115
+ });
116
+ const featuresAtivas = await (0, prompts_1.input)({
117
+ message: 'Liste as funcionalidades JA implementadas (separadas por virgula):',
118
+ default: analise.features.join(', '),
119
+ });
120
+ const featuresPendentes = await (0, prompts_1.input)({
121
+ message: 'Liste as funcionalidades PENDENTES ou em desenvolvimento:',
122
+ });
123
+ const riscos = await (0, prompts_1.input)({
124
+ message: 'Riscos tecnicos identificados:',
125
+ });
126
+ // ── Gerar arquivos ─────────────────────────────────────────────────────────
127
+ console.log('');
128
+ const dados = {
129
+ projeto, cliente, objetivo, problema, prioridade,
130
+ usuarios, regras, fase, multiTenant, lgpd,
131
+ featuresAtivas: featuresAtivas.split(',').map(f => f.trim()).filter(Boolean),
132
+ featuresPendentes: featuresPendentes.split(',').map(f => f.trim()).filter(Boolean),
133
+ riscos, analise,
134
+ data: new Date().toLocaleDateString('pt-BR'),
135
+ };
136
+ if (!fs.existsSync(specDir))
137
+ fs.mkdirSync(specDir, { recursive: true });
138
+ const tasksDir = path.join(specDir, 'tasks');
139
+ if (!fs.existsSync(tasksDir))
140
+ fs.mkdirSync(tasksDir, { recursive: true });
141
+ const arquivos = [
142
+ { nome: 'briefing.md', conteudo: gerarBriefing(dados), msg: 'Gerando briefing.md...' },
143
+ { nome: 'requirements.md', conteudo: gerarRequirements(dados), msg: 'Gerando requirements.md...' },
144
+ { nome: 'architecture.md', conteudo: gerarArchitecture(dados), msg: 'Gerando architecture.md...' },
145
+ { nome: 'users.md', conteudo: gerarUsers(dados), msg: 'Gerando users.md...' },
146
+ { nome: 'risks.md', conteudo: gerarRisks(dados), msg: 'Gerando risks.md...' },
147
+ { nome: 'rules.md', conteudo: gerarRules(dados), msg: 'Gerando rules.md...' },
148
+ { nome: 'INDEX.md', conteudo: gerarIndex(dados), msg: 'Gerando INDEX.md...' },
149
+ { nome: 'changelog.md', conteudo: gerarChangelog(dados), msg: 'Gerando changelog.md...' },
150
+ ];
151
+ for (const arq of arquivos) {
152
+ const s = (0, ora_1.default)(arq.msg).start();
153
+ await sleep(400);
154
+ fs.writeFileSync(path.join(specDir, arq.nome), arq.conteudo, 'utf-8');
155
+ s.succeed(arq.nome);
156
+ }
157
+ // tasks
158
+ const s1 = (0, ora_1.default)('Gerando tasks...').start();
159
+ await sleep(400);
160
+ fs.writeFileSync(path.join(tasksDir, 'active.md'), gerarTasksActive(dados), 'utf-8');
161
+ fs.writeFileSync(path.join(tasksDir, 'backlog.md'), gerarTasksBacklog(dados), 'utf-8');
162
+ fs.writeFileSync(path.join(tasksDir, 'done.md'), gerarTasksDone(dados), 'utf-8');
163
+ s1.succeed('tasks/ gerado');
164
+ console.log(chalk_1.default.green.bold('\n✅ Retrofit concluido!\n'));
165
+ console.log(chalk_1.default.gray(' Spec gerado em .spec/ a partir do projeto existente\n'));
166
+ console.log(chalk_1.default.gray(' Proximos passos:'));
167
+ console.log(chalk_1.default.gray(' 1. Revise os arquivos gerados em .spec/'));
168
+ console.log(chalk_1.default.gray(' 2. Execute: ') + chalk_1.default.white('vireum-spec setup') + chalk_1.default.gray(' para configurar o protocolo da IA'));
169
+ console.log(chalk_1.default.gray(' 3. Execute: ') + chalk_1.default.white('vireum-spec prioritize') + chalk_1.default.gray(' para organizar as tasks pendentes\n'));
170
+ }
171
+ // ── ANALISADOR ────────────────────────────────────────────────────────────────
172
+ function analisarProjeto(cwd) {
173
+ const resultado = {
174
+ nome: '',
175
+ descricao: '',
176
+ arquivos: 0,
177
+ readme: false,
178
+ features: [],
179
+ stack: {
180
+ frontend: '',
181
+ backend: '',
182
+ banco: '',
183
+ orm: '',
184
+ auth: '',
185
+ cache: '',
186
+ },
187
+ };
188
+ // package.json
189
+ const pkgPath = path.join(cwd, 'package.json');
190
+ if (fs.existsSync(pkgPath)) {
191
+ try {
192
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
193
+ resultado.nome = pkg.name || '';
194
+ resultado.descricao = pkg.description || '';
195
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
196
+ // Frontend
197
+ if (deps['next'])
198
+ resultado.stack.frontend = 'Next.js';
199
+ else if (deps['react'])
200
+ resultado.stack.frontend = 'React';
201
+ else if (deps['vue'])
202
+ resultado.stack.frontend = 'Vue';
203
+ else if (deps['nuxt'])
204
+ resultado.stack.frontend = 'Nuxt';
205
+ // Backend
206
+ if (deps['fastify'])
207
+ resultado.stack.backend = 'Node.js + Fastify';
208
+ else if (deps['express'])
209
+ resultado.stack.backend = 'Node.js + Express';
210
+ else if (deps['@nestjs/core'])
211
+ resultado.stack.backend = 'NestJS';
212
+ // Banco
213
+ if (deps['pg'] || deps['postgres'])
214
+ resultado.stack.banco = 'PostgreSQL';
215
+ else if (deps['mysql2'])
216
+ resultado.stack.banco = 'MySQL';
217
+ else if (deps['better-sqlite3'])
218
+ resultado.stack.banco = 'SQLite';
219
+ else if (deps['mongoose'])
220
+ resultado.stack.banco = 'MongoDB';
221
+ // ORM
222
+ if (deps['prisma'] || deps['@prisma/client'])
223
+ resultado.stack.orm = 'Prisma';
224
+ else if (deps['typeorm'])
225
+ resultado.stack.orm = 'TypeORM';
226
+ else if (deps['drizzle-orm'])
227
+ resultado.stack.orm = 'Drizzle';
228
+ // Auth
229
+ if (deps['jsonwebtoken'])
230
+ resultado.stack.auth = 'JWT';
231
+ else if (deps['next-auth'])
232
+ resultado.stack.auth = 'NextAuth';
233
+ else if (deps['@clerk/nextjs'])
234
+ resultado.stack.auth = 'Clerk';
235
+ // Cache
236
+ if (deps['ioredis'] || deps['redis'])
237
+ resultado.stack.cache = 'Redis';
238
+ if (deps['bullmq'])
239
+ resultado.stack.cache = 'Redis + BullMQ';
240
+ }
241
+ catch { }
242
+ }
243
+ // README
244
+ const readmePath = path.join(cwd, 'README.md');
245
+ if (fs.existsSync(readmePath)) {
246
+ resultado.readme = true;
247
+ const readme = fs.readFileSync(readmePath, 'utf-8');
248
+ const desc = readme.split('\n').find(l => l.trim() && !l.startsWith('#'));
249
+ if (desc)
250
+ resultado.descricao = resultado.descricao || desc.trim();
251
+ }
252
+ // Rotas — procura em src/
253
+ const srcDir = path.join(cwd, 'src');
254
+ if (fs.existsSync(srcDir)) {
255
+ resultado.features = extrairRotas(srcDir);
256
+ resultado.arquivos = contarArquivos(srcDir);
257
+ }
258
+ return resultado;
259
+ }
260
+ function extrairRotas(dir) {
261
+ const rotas = [];
262
+ const exts = ['.ts', '.js'];
263
+ function walk(d) {
264
+ if (!fs.existsSync(d))
265
+ return;
266
+ for (const entry of fs.readdirSync(d)) {
267
+ const full = path.join(d, entry);
268
+ const stat = fs.statSync(full);
269
+ if (stat.isDirectory() && !entry.includes('node_modules')) {
270
+ walk(full);
271
+ }
272
+ else if (exts.includes(path.extname(entry))) {
273
+ const content = fs.readFileSync(full, 'utf-8');
274
+ const matches = content.match(/\.(get|post|put|patch|delete|route)\(['"`]([^'"`]+)/gi);
275
+ if (matches) {
276
+ matches.forEach(m => {
277
+ const rota = m.replace(/\.(get|post|put|patch|delete|route)\(['"`]/i, '').trim();
278
+ if (rota && !rotas.includes(rota))
279
+ rotas.push(rota);
280
+ });
281
+ }
282
+ }
283
+ }
284
+ }
285
+ walk(dir);
286
+ return rotas.slice(0, 20);
287
+ }
288
+ function contarArquivos(dir) {
289
+ let count = 0;
290
+ function walk(d) {
291
+ if (!fs.existsSync(d))
292
+ return;
293
+ for (const entry of fs.readdirSync(d)) {
294
+ const full = path.join(d, entry);
295
+ if (fs.statSync(full).isDirectory() && !entry.includes('node_modules'))
296
+ walk(full);
297
+ else
298
+ count++;
299
+ }
300
+ }
301
+ walk(dir);
302
+ return count;
303
+ }
304
+ // ── GERADORES ─────────────────────────────────────────────────────────────────
305
+ function gerarBriefing(d) {
306
+ return `# Briefing — ${d.projeto}
307
+
308
+ > Gerado via vireum-spec retrofit em ${d.data}
309
+ > Projeto pre-existente — informacoes inferidas e complementadas
310
+
311
+ ## Informacoes Gerais
312
+ - **Projeto:** ${d.projeto}
313
+ - **Cliente:** ${d.cliente}
314
+ - **Data do retrofit:** ${d.data}
315
+ - **Fase:** ${d.fase}
316
+
317
+ ## Objetivo
318
+ **Objetivo principal:** ${d.objetivo}
319
+ **Problema que resolve:** ${d.problema}
320
+ **Estado atual / prioridade:** ${d.prioridade}
321
+
322
+ ## Usuarios
323
+ ${d.usuarios}
324
+
325
+ ## Funcionalidades Implementadas
326
+ ${d.featuresAtivas.map((f) => `- [x] ${f}`).join('\n') || '- (nao informado)'}
327
+
328
+ ## Funcionalidades Pendentes
329
+ ${d.featuresPendentes.map((f) => `- [ ] ${f}`).join('\n') || '- (nao informado)'}
330
+
331
+ ## Regras de Negocio
332
+ ${d.regras || '(nao informado)'}
333
+
334
+ ## Stack Detectada
335
+ - Frontend: ${d.analise.stack.frontend || 'nao detectado'}
336
+ - Backend: ${d.analise.stack.backend || 'nao detectado'}
337
+ - Banco: ${d.analise.stack.banco || 'nao detectado'}
338
+ - ORM: ${d.analise.stack.orm || 'nao detectado'}
339
+ - Auth: ${d.analise.stack.auth || 'nao detectado'}
340
+
341
+ ## Riscos
342
+ ${d.riscos || '(nenhum identificado)'}
343
+
344
+ ## Conformidade
345
+ - Multi-tenant: ${d.multiTenant ? 'Sim' : 'Nao'}
346
+ - LGPD: ${d.lgpd ? 'Sim' : 'Nao'}
347
+ `;
348
+ }
349
+ function gerarRequirements(d) {
350
+ const implementadas = d.featuresAtivas.map((f, i) => `- [x] R-${String(i + 1).padStart(3, '0')} ${f} — JA IMPLEMENTADO`).join('\n');
351
+ const pendentes = d.featuresPendentes.map((f, i) => `- [ ] R-${String(d.featuresAtivas.length + i + 1).padStart(3, '0')} ${f}`).join('\n');
352
+ return `# Requirements — ${d.projeto}
353
+
354
+ > Gerado via vireum-spec retrofit em ${d.data}
355
+
356
+ ## Objetivo
357
+ ${d.objetivo}
358
+
359
+ ## Funcionalidades Implementadas
360
+ ${implementadas || '- (nao informado)'}
361
+
362
+ ## Funcionalidades Pendentes (MVP)
363
+ ${pendentes || '- (nao informado)'}
364
+
365
+ ## Funcionalidades Fase 2
366
+ > Preencher apos vireum-spec prioritize
367
+
368
+ ## Regras de Negocio
369
+ ${d.regras || '> A detalhar'}
370
+
371
+ ## Rotas Detectadas Automaticamente
372
+ ${d.analise.features.map((r) => `- ${r}`).join('\n') || '- (nenhuma detectada)'}
373
+ `;
374
+ }
375
+ function gerarArchitecture(d) {
376
+ const tenant = d.multiTenant
377
+ ? '\n## Multi-Tenancy\n- Ativo — nunca fazer query sem filtro de tenantId' : '';
378
+ return `# Architecture — ${d.projeto}
379
+
380
+ > Gerado via vireum-spec retrofit em ${d.data}
381
+ > Stack inferida automaticamente — revisar e complementar
382
+
383
+ ## Stack
384
+ - Frontend: ${d.analise.stack.frontend || 'A confirmar'}
385
+ - Backend: ${d.analise.stack.backend || 'A confirmar'}
386
+ - Banco de dados: ${d.analise.stack.banco || 'A confirmar'}
387
+ - ORM: ${d.analise.stack.orm || 'A confirmar'}
388
+ - Cache / Filas: ${d.analise.stack.cache || 'A confirmar'}
389
+ - Auth: ${d.analise.stack.auth || 'A confirmar'}
390
+ ${tenant}
391
+
392
+ ## Decisoes Arquiteturais
393
+ > Registre aqui decisoes tomadas antes do retrofit
394
+
395
+ | Data | Decisao | Alternativas descartadas | Motivo |
396
+ |------|---------|--------------------------|--------|
397
+ | | | | |
398
+
399
+ ## MCPs Ativos
400
+ > Configurar via vireum-spec setup
401
+ `;
402
+ }
403
+ function gerarUsers(d) {
404
+ return `# Users — ${d.projeto}
405
+
406
+ > Gerado via vireum-spec retrofit em ${d.data}
407
+
408
+ ## Publico Principal
409
+ ${d.usuarios}
410
+
411
+ ## Tipos de Usuario e Acesso
412
+ > Detalhar apos analise do codigo existente
413
+
414
+ ## Jornadas Principais
415
+ > A mapear com base nas rotas detectadas
416
+ `;
417
+ }
418
+ function gerarRisks(d) {
419
+ return `# Risks — ${d.projeto}
420
+
421
+ > Gerado via vireum-spec retrofit em ${d.data}
422
+
423
+ ## Riscos Identificados
424
+ - Tecnico: ${d.riscos || 'Nenhum informado'}
425
+ ${d.lgpd ? '- LGPD requerida — revisar tratamento de dados pessoais existente' : ''}
426
+ ${d.multiTenant ? '- Multi-tenant — auditar queries existentes para garantir isolamento' : ''}
427
+
428
+ ## Riscos de Retrofit
429
+ - Spec gerado pode nao refletir 100% da realidade do codigo — revisar arquivos gerados
430
+ - Funcionalidades nao listadas no briefing podem existir no codigo — auditar
431
+
432
+ ## Riscos Identificados Durante o Desenvolvimento
433
+ | Data | Risco | Impacto | Mitigacao |
434
+ |------|-------|---------|-----------|
435
+ | | | | |
436
+ `;
437
+ }
438
+ function gerarRules(d) {
439
+ const extras = [];
440
+ if (d.lgpd)
441
+ extras.push('- Nunca armazenar dados pessoais sem consentimento (LGPD)');
442
+ if (d.multiTenant)
443
+ extras.push('- Nunca fazer query sem filtro de tenantId');
444
+ return `# Rules — ${d.projeto}
445
+
446
+ > Gerado via vireum-spec retrofit em ${d.data}
447
+ > Complementar com regras especificas do projeto apos revisao do codigo
448
+
449
+ ## Regras do Projeto
450
+ ${extras.length ? extras.join('\n') : '- A definir apos revisao do codigo existente'}
451
+ `;
452
+ }
453
+ function gerarIndex(d) {
454
+ const pendentes = d.featuresPendentes.map((f, i) => {
455
+ const prefix = f.replace(/\s+/g, '_').toUpperCase().slice(0, 8);
456
+ return `- [ ] [${prefix}-T${String(i + 1).padStart(3, '0')}] ${f}`;
457
+ }).join('\n');
458
+ return `# INDEX — ${d.projeto}
459
+
460
+ > Gerado via vireum-spec retrofit em ${d.data}
461
+ > Arquivo de entrada — sempre carregado pela IA no inicio de cada sessao
462
+
463
+ ## Projeto
464
+ - **Cliente:** ${d.cliente}
465
+ - **Fase atual:** ${d.fase}
466
+ - **Retrofit em:** ${d.data}
467
+
468
+ ## Estado Atual
469
+ ${pendentes || '- Nenhuma task pendente mapeada ainda'}
470
+
471
+ ## Arquivos de contexto disponiveis
472
+ Nao carregue automaticamente. Carregue apenas quando a task exigir:
473
+
474
+ - Escopo e features → leia \`.spec/requirements.md\`
475
+ - Decisoes tecnicas → leia \`.spec/architecture.md\`
476
+ - Perfis e permissoes → leia \`.spec/users.md\`
477
+ - Riscos → leia \`.spec/risks.md\`
478
+ - Tarefas ativas → leia \`.spec/tasks/active.md\`
479
+ - Historico → leia \`.spec/changelog.md\`
480
+
481
+ ## Resumo do Objetivo
482
+ ${d.objetivo}
483
+ `;
484
+ }
485
+ function gerarChangelog(d) {
486
+ return `# Changelog — ${d.projeto}
487
+
488
+ > Registro de decisoes, mudancas e causa raiz de bugs.
489
+
490
+ ## ${d.data} — Retrofit realizado
491
+ - Spec gerado a partir de projeto pre-existente via vireum-spec retrofit
492
+ - Stack detectada automaticamente: ${[
493
+ d.analise.stack.frontend,
494
+ d.analise.stack.backend,
495
+ d.analise.stack.banco,
496
+ ].filter(Boolean).join(', ') || 'a confirmar'}
497
+ - Fase no momento do retrofit: ${d.fase}
498
+ `;
499
+ }
500
+ function gerarTasksActive(d) {
501
+ if (d.featuresPendentes.length === 0) {
502
+ return `# Tasks — Active\n\n> Nenhuma task pendente mapeada no retrofit.\n> Execute vireum-spec prioritize para organizar.\n`;
503
+ }
504
+ const tasks = d.featuresPendentes.map((f, i) => {
505
+ const prefix = f.replace(/\s+/g, '_').toUpperCase().slice(0, 8);
506
+ const num = String(i + 1).padStart(3, '0');
507
+ return `## [${prefix}-T${num}] ${f}
508
+ - **Origem:** retrofit — funcionalidade pendente
509
+ - **Camada:** A definir
510
+ - **Complexidade:** A definir
511
+ - **Criterios de aceitacao:**
512
+ - (definir antes de implementar)
513
+ - **Status:** [ ] Nao iniciada
514
+ `;
515
+ }).join('\n');
516
+ return `# Tasks — Active
517
+
518
+ > Tasks pendentes identificadas no retrofit.
519
+ > Revise e complemente os criterios de aceitacao antes de comecar.
520
+
521
+ ---
522
+
523
+ ${tasks}`;
524
+ }
525
+ function gerarTasksBacklog(d) {
526
+ return `# Tasks — Backlog\n\n> Preencher apos priorizacao via vireum-spec prioritize.\n`;
527
+ }
528
+ function gerarTasksDone(d) {
529
+ const done = d.featuresAtivas.map((f) => `- [x] ${f} — pre-existente ao retrofit`).join('\n');
530
+ return `# Tasks — Done
531
+
532
+ > Funcionalidades ja implementadas antes do retrofit.
533
+
534
+ ## ${d.data} — Retrofit
535
+ ${done || '- (nenhuma listada)'}
536
+ `;
537
+ }
538
+ function sleep(ms) {
539
+ return new Promise(r => setTimeout(r, ms));
540
+ }
package/dist/index.js CHANGED
@@ -14,6 +14,7 @@ const health_1 = require("./commands/health");
14
14
  const brief_1 = require("./commands/brief");
15
15
  const verify_mcps_1 = require("./commands/verify-mcps");
16
16
  const skills_1 = require("./commands/skills");
17
+ const retrofit_1 = require("./commands/retrofit");
17
18
  const program = new commander_1.Command();
18
19
  program
19
20
  .name('vireum-spec')
@@ -51,5 +52,9 @@ program
51
52
  .command('skills')
52
53
  .description('Instala as skills do framework no cliente de IA')
53
54
  .action(async () => { await (0, skills_1.runSkills)(); });
55
+ program
56
+ .command('retrofit')
57
+ .description('Gera o spec a partir de um projeto ja em andamento')
58
+ .action(async () => { await (0, retrofit_1.runRetrofit)(); });
54
59
  console.log(chalk_1.default.hex('#2D7DD2').bold('\n Vireum Spec Framework\n'));
55
60
  program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vireum-spec-cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Spec Driven Development framework by Vireum Desenvolvimento",
5
5
  "main": "dist/index.js",
6
6
  "bin": {