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.
@@ -0,0 +1,172 @@
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.runHealth = runHealth;
40
+ const chalk_1 = __importDefault(require("chalk"));
41
+ const ora_1 = __importDefault(require("ora"));
42
+ const fs = __importStar(require("fs"));
43
+ const path = __importStar(require("path"));
44
+ async function runHealth() {
45
+ console.log(chalk_1.default.hex('#2D7DD2').bold('\n Vireum Spec — Health Check\n'));
46
+ const specDir = path.join(process.cwd(), '.spec');
47
+ const vireumDir = path.join(process.cwd(), '.vireum');
48
+ const spinner = (0, ora_1.default)('Verificando spec...').start();
49
+ await sleep(600);
50
+ spinner.stop();
51
+ const problemas = [];
52
+ const avisos = [];
53
+ const ok = [];
54
+ // ── Arquivos obrigatórios ──────────────────────────────────────────────────
55
+ const obrigatorios = [
56
+ { path: path.join(specDir, 'briefing.md'), nome: '.spec/briefing.md' },
57
+ { path: path.join(specDir, 'INDEX.md'), nome: '.spec/INDEX.md' },
58
+ { path: path.join(specDir, 'requirements.md'), nome: '.spec/requirements.md' },
59
+ { path: path.join(specDir, 'architecture.md'), nome: '.spec/architecture.md' },
60
+ { path: path.join(specDir, 'users.md'), nome: '.spec/users.md' },
61
+ { path: path.join(specDir, 'risks.md'), nome: '.spec/risks.md' },
62
+ { path: path.join(specDir, 'rules.md'), nome: '.spec/rules.md' },
63
+ { path: path.join(specDir, 'changelog.md'), nome: '.spec/changelog.md' },
64
+ { path: path.join(specDir, 'tasks', 'active.md'), nome: '.spec/tasks/active.md' },
65
+ { path: path.join(specDir, 'tasks', 'backlog.md'), nome: '.spec/tasks/backlog.md' },
66
+ { path: path.join(specDir, 'tasks', 'done.md'), nome: '.spec/tasks/done.md' },
67
+ { path: path.join(vireumDir, 'rules.md'), nome: '.vireum/rules.md' },
68
+ { path: path.join(process.cwd(), 'CLAUDE.md'), nome: 'CLAUDE.md' },
69
+ { path: path.join(process.cwd(), 'AGENTS.md'), nome: 'AGENTS.md' },
70
+ ];
71
+ for (const arq of obrigatorios) {
72
+ if (fs.existsSync(arq.path)) {
73
+ ok.push(`${arq.nome} existe`);
74
+ }
75
+ else {
76
+ problemas.push(`${arq.nome} não encontrado`);
77
+ }
78
+ }
79
+ // ── Tasks sem critérios ────────────────────────────────────────────────────
80
+ const activePath = path.join(specDir, 'tasks', 'active.md');
81
+ if (fs.existsSync(activePath)) {
82
+ const active = fs.readFileSync(activePath, 'utf-8');
83
+ const semCriterios = (active.match(/definir antes de implementar/g) || []).length;
84
+ if (semCriterios > 0) {
85
+ avisos.push(`${semCriterios} task(s) em active.md sem critérios de aceitação definidos`);
86
+ }
87
+ else {
88
+ ok.push('Todas as tasks têm critérios de aceitação');
89
+ }
90
+ const tasksTotal = (active.match(/## \[/g) || []).length;
91
+ if (tasksTotal === 0) {
92
+ avisos.push('Nenhuma task em active.md — execute vireum-spec prioritize');
93
+ }
94
+ else {
95
+ ok.push(`${tasksTotal} task(s) ativa(s) no MVP`);
96
+ }
97
+ }
98
+ // ── Architecture sem decisões ──────────────────────────────────────────────
99
+ const archPath = path.join(specDir, 'architecture.md');
100
+ if (fs.existsSync(archPath)) {
101
+ const arch = fs.readFileSync(archPath, 'utf-8');
102
+ const semStack = arch.includes('Frontend: \n') || arch.includes('Backend: \n');
103
+ if (semStack) {
104
+ avisos.push('architecture.md com stack incompleta — execute vireum-spec setup');
105
+ }
106
+ else {
107
+ ok.push('Stack definida em architecture.md');
108
+ }
109
+ }
110
+ // ── INDEX desatualizado ────────────────────────────────────────────────────
111
+ const indexPath = path.join(specDir, 'INDEX.md');
112
+ if (fs.existsSync(indexPath)) {
113
+ const index = fs.readFileSync(indexPath, 'utf-8');
114
+ if (index.includes('Nenhuma task concluída ainda') && fs.existsSync(activePath)) {
115
+ const active = fs.readFileSync(activePath, 'utf-8');
116
+ const temTasks = (active.match(/## \[/g) || []).length > 0;
117
+ if (temTasks) {
118
+ avisos.push('INDEX.md pode estar desatualizado — verifique estado do MVP');
119
+ }
120
+ }
121
+ else {
122
+ ok.push('INDEX.md com estado do MVP');
123
+ }
124
+ }
125
+ // ── Requirements sem features ──────────────────────────────────────────────
126
+ const reqPath = path.join(specDir, 'requirements.md');
127
+ if (fs.existsSync(reqPath)) {
128
+ const req = fs.readFileSync(reqPath, 'utf-8');
129
+ const temFeatures = req.includes('- [ ] R-');
130
+ if (!temFeatures) {
131
+ avisos.push('requirements.md sem features mapeadas — verifique o briefing');
132
+ }
133
+ else {
134
+ ok.push('Features mapeadas em requirements.md');
135
+ }
136
+ }
137
+ // ── Cursor rules ───────────────────────────────────────────────────────────
138
+ const cursorPath = path.join(process.cwd(), '.cursor', 'rules', 'vireum.mdc');
139
+ if (fs.existsSync(cursorPath)) {
140
+ ok.push('.cursor/rules/vireum.mdc configurado');
141
+ }
142
+ else {
143
+ avisos.push('.cursor/rules/vireum.mdc não encontrado — execute vireum-spec setup');
144
+ }
145
+ // ── Output ─────────────────────────────────────────────────────────────────
146
+ console.log('');
147
+ if (ok.length > 0) {
148
+ console.log(chalk_1.default.green.bold(' ✓ OK\n'));
149
+ ok.forEach(msg => console.log(chalk_1.default.green(` ✓ ${msg}`)));
150
+ }
151
+ if (avisos.length > 0) {
152
+ console.log(chalk_1.default.yellow.bold('\n ⚠ Avisos\n'));
153
+ avisos.forEach(msg => console.log(chalk_1.default.yellow(` ⚠ ${msg}`)));
154
+ }
155
+ if (problemas.length > 0) {
156
+ console.log(chalk_1.default.red.bold('\n ✗ Problemas\n'));
157
+ problemas.forEach(msg => console.log(chalk_1.default.red(` ✗ ${msg}`)));
158
+ }
159
+ console.log('');
160
+ if (problemas.length === 0 && avisos.length === 0) {
161
+ console.log(chalk_1.default.green.bold(' Spec em ótimo estado. Pode desenvolver.\n'));
162
+ }
163
+ else if (problemas.length === 0) {
164
+ console.log(chalk_1.default.yellow(` ${avisos.length} aviso(s) encontrado(s). Nenhum problema crítico.\n`));
165
+ }
166
+ else {
167
+ console.log(chalk_1.default.red(` ${problemas.length} problema(s) crítico(s) encontrado(s). Resolva antes de continuar.\n`));
168
+ }
169
+ }
170
+ function sleep(ms) {
171
+ return new Promise(r => setTimeout(r, ms));
172
+ }
@@ -0,0 +1,261 @@
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.runInit = runInit;
40
+ const chalk_1 = __importDefault(require("chalk"));
41
+ const prompts_1 = require("@inquirer/prompts");
42
+ const fs = __importStar(require("fs"));
43
+ const path = __importStar(require("path"));
44
+ async function runInit() {
45
+ console.log(chalk_1.default.hex('#2D7DD2').bold('\n Vireum Spec — Briefing Interativo\n'));
46
+ console.log(chalk_1.default.gray(' Responda as perguntas abaixo. As respostas serão salvas em .spec/briefing.md\n'));
47
+ // ── 1. Informações Gerais ──────────────────────────────────────────────────
48
+ console.log(chalk_1.default.hex('#2D7DD2').bold('📌 1. Informações Gerais\n'));
49
+ const geral = {
50
+ projeto: await (0, prompts_1.input)({ message: 'Nome do projeto:' }),
51
+ cliente: await (0, prompts_1.input)({ message: 'Nome do cliente:' }),
52
+ responsavel: await (0, prompts_1.input)({ message: 'Responsável pelo projeto (Vireum):' }),
53
+ data: await (0, prompts_1.input)({ message: 'Data da reunião:', default: new Date().toLocaleDateString('pt-BR') }),
54
+ };
55
+ // ── 2. Objetivo ────────────────────────────────────────────────────────────
56
+ console.log(chalk_1.default.hex('#2D7DD2').bold('\n🎯 2. Objetivo do Projeto\n'));
57
+ const objetivo = {
58
+ objetivo: await (0, prompts_1.input)({ message: 'Qual é o objetivo principal da plataforma?' }),
59
+ problema: await (0, prompts_1.input)({ message: 'Qual problema o sistema resolve?' }),
60
+ curto_prazo: await (0, prompts_1.input)({ message: 'Resultado esperado no curto prazo:' }),
61
+ medio_prazo: await (0, prompts_1.input)({ message: 'Resultado esperado no médio prazo:' }),
62
+ longo_prazo: await (0, prompts_1.input)({ message: 'Resultado esperado no longo prazo:' }),
63
+ prioridade_cliente: await (0, prompts_1.input)({ message: 'O que o cliente precisa que funcione primeiro?' }),
64
+ };
65
+ // ── 3. Escopo Funcional ────────────────────────────────────────────────────
66
+ console.log(chalk_1.default.hex('#2D7DD2').bold('\n🧩 3. Escopo Funcional\n'));
67
+ const escopo = {
68
+ usuarios: await (0, prompts_1.input)({ message: 'Quem usará o sistema?' }),
69
+ multi_usuario: await (0, prompts_1.confirm)({ message: 'Existem diferentes tipos de usuários?', default: false }),
70
+ niveis_acesso: await (0, prompts_1.confirm)({ message: 'Existem níveis de acesso diferentes?', default: false }),
71
+ features_obrigatorias: await (0, prompts_1.input)({ message: 'Funcionalidades obrigatórias (separadas por vírgula):' }),
72
+ features_desejaveis: await (0, prompts_1.input)({ message: 'Funcionalidades desejáveis no MVP (separadas por vírgula):' }),
73
+ integracoes: await (0, prompts_1.input)({ message: 'Integrações externas? (CRM, ERP, WhatsApp, etc.)' }),
74
+ };
75
+ // ── 4. Regras de Negócio ───────────────────────────────────────────────────
76
+ console.log(chalk_1.default.hex('#2D7DD2').bold('\n🏗️ 4. Regras de Negócio\n'));
77
+ const regras = {
78
+ regras: await (0, prompts_1.input)({ message: 'Principais regras que o sistema deve obedecer:' }),
79
+ excecoes: await (0, prompts_1.input)({ message: 'Exceções importantes:' }),
80
+ };
81
+ // ── 5. Financeiro ──────────────────────────────────────────────────────────
82
+ console.log(chalk_1.default.hex('#2D7DD2').bold('\n💰 5. Modelo Financeiro\n'));
83
+ const financeiro = {
84
+ pagamento: await (0, prompts_1.confirm)({ message: 'Haverá integração com meio de pagamento?', default: false }),
85
+ cobranca: await (0, prompts_1.select)({
86
+ message: 'Modelo de cobrança:',
87
+ choices: [
88
+ { name: 'Não aplicável', value: 'Não aplicável' },
89
+ { name: 'Assinatura recorrente', value: 'Assinatura recorrente' },
90
+ { name: 'Compra única', value: 'Compra única' },
91
+ { name: 'Ambos', value: 'Ambos' },
92
+ ],
93
+ }),
94
+ estorno: await (0, prompts_1.confirm)({ message: 'Existem regras de estorno ou cancelamento?', default: false }),
95
+ };
96
+ // ── 6. Métricas ────────────────────────────────────────────────────────────
97
+ console.log(chalk_1.default.hex('#2D7DD2').bold('\n📊 6. Métricas e Indicadores\n'));
98
+ const metricas = {
99
+ kpis: await (0, prompts_1.input)({ message: 'Quais KPIs devem ser acompanhados?' }),
100
+ dashboard: await (0, prompts_1.confirm)({ message: 'Precisa de dashboard administrativo?', default: false }),
101
+ relatorios: await (0, prompts_1.confirm)({ message: 'Precisa exportar relatórios?', default: false }),
102
+ };
103
+ // ── 7. Plataforma e DevOps ─────────────────────────────────────────────────
104
+ console.log(chalk_1.default.hex('#2D7DD2').bold('\n📱 7. Plataforma e Infraestrutura\n'));
105
+ const plataforma = {
106
+ tipo: await (0, prompts_1.select)({
107
+ message: 'O sistema será:',
108
+ choices: [
109
+ { name: 'Apenas Web', value: 'Apenas Web' },
110
+ { name: 'Web + App', value: 'Web + App' },
111
+ { name: 'Apenas App', value: 'Apenas App' },
112
+ ],
113
+ }),
114
+ app_futuro: await (0, prompts_1.confirm)({ message: 'Pretende lançar aplicativo futuramente?', default: false }),
115
+ push: await (0, prompts_1.confirm)({ message: 'Precisa de notificações push?', default: false }),
116
+ hospedagem: await (0, prompts_1.input)({ message: 'Hospedagem preferida ou orçamento de infra:' }),
117
+ cicd: await (0, prompts_1.confirm)({ message: 'Precisa de CI/CD desde o início?', default: false }),
118
+ staging: await (0, prompts_1.confirm)({ message: 'Precisa de ambiente de staging?', default: false }),
119
+ dominio: await (0, prompts_1.confirm)({ message: 'Já tem domínio/DNS configurado?', default: false }),
120
+ backup_sla: await (0, prompts_1.confirm)({ message: 'Backups e SLA são requisito do cliente?', default: false }),
121
+ };
122
+ // ── 8. Segurança e Jurídico ────────────────────────────────────────────────
123
+ console.log(chalk_1.default.hex('#2D7DD2').bold('\n🔐 8. Segurança e Jurídico\n'));
124
+ const seguranca = {
125
+ dados_sensiveis: await (0, prompts_1.confirm)({ message: 'Dados sensíveis serão armazenados?', default: false }),
126
+ lgpd: await (0, prompts_1.confirm)({ message: 'Precisa de conformidade com LGPD?', default: true }),
127
+ termos: await (0, prompts_1.confirm)({ message: 'Precisa de termos de uso?', default: false }),
128
+ acesso_avancado: await (0, prompts_1.confirm)({ message: 'Haverá controle de acesso avançado?', default: false }),
129
+ };
130
+ // ── 9. Escala ──────────────────────────────────────────────────────────────
131
+ console.log(chalk_1.default.hex('#2D7DD2').bold('\n📈 9. Escala e Crescimento\n'));
132
+ const escala = {
133
+ usuarios_lancamento: await (0, prompts_1.input)({ message: 'Número esperado de usuários no lançamento:' }),
134
+ crescimento_1ano: await (0, prompts_1.input)({ message: 'Crescimento estimado em 1 ano:' }),
135
+ uso: await (0, prompts_1.select)({
136
+ message: 'Padrão de uso:',
137
+ choices: [
138
+ { name: 'Diário intenso', value: 'Diário intenso' },
139
+ { name: 'Diário moderado', value: 'Diário moderado' },
140
+ { name: 'Esporádico', value: 'Esporádico' },
141
+ ],
142
+ }),
143
+ };
144
+ // ── 10. Operacional ────────────────────────────────────────────────────────
145
+ console.log(chalk_1.default.hex('#2D7DD2').bold('\n⚙️ 10. Operacional\n'));
146
+ const operacional = {
147
+ operador: await (0, prompts_1.input)({ message: 'Quem vai operar o sistema?' }),
148
+ equipe: await (0, prompts_1.confirm)({ message: 'Haverá equipe interna dedicada?', default: false }),
149
+ treinamento: await (0, prompts_1.confirm)({ message: 'Necessita treinamento?', default: false }),
150
+ suporte: await (0, prompts_1.confirm)({ message: 'Necessita suporte mensal?', default: false }),
151
+ };
152
+ // ── 11. Riscos ─────────────────────────────────────────────────────────────
153
+ console.log(chalk_1.default.hex('#2D7DD2').bold('\n🧠 11. Riscos Identificados\n'));
154
+ const riscos = {
155
+ risco_tecnico: await (0, prompts_1.input)({ message: 'Risco técnico identificado:' }),
156
+ risco_juridico: await (0, prompts_1.input)({ message: 'Risco jurídico identificado:' }),
157
+ risco_operacional: await (0, prompts_1.input)({ message: 'Risco operacional identificado:' }),
158
+ };
159
+ // ── Gerar briefing.md ──────────────────────────────────────────────────────
160
+ const briefing = gerarBriefing({ geral, objetivo, escopo, regras, financeiro, metricas, plataforma, seguranca, escala, operacional, riscos });
161
+ const specDir = path.join(process.cwd(), '.spec');
162
+ if (!fs.existsSync(specDir))
163
+ fs.mkdirSync(specDir, { recursive: true });
164
+ const tasksDir = path.join(specDir, 'tasks');
165
+ if (!fs.existsSync(tasksDir))
166
+ fs.mkdirSync(tasksDir, { recursive: true });
167
+ fs.writeFileSync(path.join(specDir, 'briefing.md'), briefing, 'utf-8');
168
+ console.log(chalk_1.default.green.bold('\n✅ Briefing salvo em .spec/briefing.md\n'));
169
+ console.log(chalk_1.default.gray(' Próximo passo: ') + chalk_1.default.white('vireum-spec distill') + chalk_1.default.gray(' para gerar os arquivos de spec\n'));
170
+ }
171
+ function gerarBriefing(data) {
172
+ const { geral, objetivo, escopo, regras, financeiro, metricas, plataforma, seguranca, escala, operacional, riscos } = data;
173
+ const features = escopo.features_obrigatorias
174
+ .split(',').map((f) => `- [ ] ${f.trim()}`).join('\n');
175
+ const featuresDesejaveis = escopo.features_desejaveis
176
+ .split(',').map((f) => `- [ ] ${f.trim()}`).join('\n');
177
+ return `# Briefing — ${geral.projeto}
178
+
179
+ ## 📌 1. Informações Gerais
180
+ - **Projeto:** ${geral.projeto}
181
+ - **Cliente:** ${geral.cliente}
182
+ - **Responsável:** ${geral.responsavel}
183
+ - **Data da reunião:** ${geral.data}
184
+ - **Versão:** 1.0
185
+
186
+ ## 🎯 2. Objetivo do Projeto
187
+ **Objetivo principal:** ${objetivo.objetivo}
188
+
189
+ **Problema que o sistema resolve:** ${objetivo.problema}
190
+
191
+ **Resultados esperados:**
192
+ - Curto prazo: ${objetivo.curto_prazo}
193
+ - Médio prazo: ${objetivo.medio_prazo}
194
+ - Longo prazo: ${objetivo.longo_prazo}
195
+
196
+ **Prioridade do cliente (o que precisa funcionar primeiro):** ${objetivo.prioridade_cliente}
197
+
198
+ ## 🧩 3. Escopo Funcional
199
+
200
+ ### Público do Sistema
201
+ - Quem usará: ${escopo.usuarios}
202
+ - Diferentes tipos de usuários: ${escopo.multi_usuario ? 'Sim' : 'Não'}
203
+ - Níveis de acesso: ${escopo.niveis_acesso ? 'Sim' : 'Não'}
204
+
205
+ ### Funcionalidades Obrigatórias
206
+ ${features}
207
+
208
+ ### Funcionalidades Desejáveis (não obrigatórias no MVP)
209
+ ${featuresDesejaveis}
210
+
211
+ ### Integrações Externas
212
+ ${escopo.integracoes || 'Nenhuma identificada'}
213
+
214
+ ## 🏗️ 4. Regras de Negócio
215
+ ${regras.regras}
216
+
217
+ **Exceções:** ${regras.excecoes || 'Nenhuma'}
218
+
219
+ ## 💰 5. Modelo Financeiro
220
+ - Integração com pagamento: ${financeiro.pagamento ? 'Sim' : 'Não'}
221
+ - Modelo de cobrança: ${financeiro.cobranca}
222
+ - Regras de estorno/cancelamento: ${financeiro.estorno ? 'Sim' : 'Não'}
223
+
224
+ ## 📊 6. Métricas e Indicadores
225
+ - KPIs: ${metricas.kpis}
226
+ - Dashboard administrativo: ${metricas.dashboard ? 'Sim' : 'Não'}
227
+ - Exportação de relatórios: ${metricas.relatorios ? 'Sim' : 'Não'}
228
+
229
+ ## 📱 7. Plataforma e Infraestrutura
230
+ - Tipo: ${plataforma.tipo}
231
+ - App futuro: ${plataforma.app_futuro ? 'Sim' : 'Não'}
232
+ - Notificações push: ${plataforma.push ? 'Sim' : 'Não'}
233
+ - Hospedagem: ${plataforma.hospedagem || 'A definir'}
234
+ - CI/CD desde o início: ${plataforma.cicd ? 'Sim' : 'Não'}
235
+ - Ambiente de staging: ${plataforma.staging ? 'Sim' : 'Não'}
236
+ - Domínio configurado: ${plataforma.dominio ? 'Sim' : 'Não'}
237
+ - Backup e SLA: ${plataforma.backup_sla ? 'Sim' : 'Não'}
238
+
239
+ ## 🔐 8. Segurança e Jurídico
240
+ - Dados sensíveis: ${seguranca.dados_sensiveis ? 'Sim' : 'Não'}
241
+ - LGPD: ${seguranca.lgpd ? 'Sim' : 'Não'}
242
+ - Termos de uso: ${seguranca.termos ? 'Sim' : 'Não'}
243
+ - Controle de acesso avançado: ${seguranca.acesso_avancado ? 'Sim' : 'Não'}
244
+
245
+ ## 📈 9. Escala e Crescimento
246
+ - Usuários no lançamento: ${escala.usuarios_lancamento}
247
+ - Crescimento em 1 ano: ${escala.crescimento_1ano}
248
+ - Padrão de uso: ${escala.uso}
249
+
250
+ ## ⚙️ 10. Operacional
251
+ - Operador: ${operacional.operador}
252
+ - Equipe interna: ${operacional.equipe ? 'Sim' : 'Não'}
253
+ - Treinamento: ${operacional.treinamento ? 'Sim' : 'Não'}
254
+ - Suporte mensal: ${operacional.suporte ? 'Sim' : 'Não'}
255
+
256
+ ## 🧠 11. Riscos Identificados
257
+ - Risco técnico: ${riscos.risco_tecnico || 'Nenhum identificado'}
258
+ - Risco jurídico: ${riscos.risco_juridico || 'Nenhum identificado'}
259
+ - Risco operacional: ${riscos.risco_operacional || 'Nenhum identificado'}
260
+ `;
261
+ }
@@ -0,0 +1,202 @@
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.runPrioritize = runPrioritize;
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 runPrioritize() {
46
+ console.log(chalk_1.default.hex('#2D7DD2').bold('\n Vireum Spec — Prioritize\n'));
47
+ console.log(chalk_1.default.gray(' Classifique cada feature e defina o que entra no MVP\n'));
48
+ const specDir = path.join(process.cwd(), '.spec');
49
+ const tasksDir = path.join(specDir, 'tasks');
50
+ const backlogPath = path.join(tasksDir, 'backlog.md');
51
+ const activePath = path.join(tasksDir, 'active.md');
52
+ const indexPath = path.join(specDir, 'INDEX.md');
53
+ if (!fs.existsSync(backlogPath)) {
54
+ console.log(chalk_1.default.red('\n❌ tasks/backlog.md não encontrado.'));
55
+ console.log(chalk_1.default.gray(' Execute primeiro: ') + chalk_1.default.white('vireum-spec distill\n'));
56
+ process.exit(1);
57
+ }
58
+ const backlog = fs.readFileSync(backlogPath, 'utf-8');
59
+ const features = extrairFeatures(backlog);
60
+ if (features.length === 0) {
61
+ console.log(chalk_1.default.yellow('\n⚠️ Nenhuma feature encontrada no backlog.\n'));
62
+ process.exit(0);
63
+ }
64
+ console.log(chalk_1.default.gray(` ${features.length} feature(s) encontrada(s) no backlog\n`));
65
+ console.log(chalk_1.default.gray(' Para cada feature defina: fase, complexidade e camada\n'));
66
+ console.log(chalk_1.default.gray(' ─────────────────────────────────────────────────────\n'));
67
+ const mvp = [];
68
+ const fase2 = [];
69
+ const fora = [];
70
+ for (const feature of features) {
71
+ console.log(chalk_1.default.white.bold(` Feature: ${feature.nome}`));
72
+ const fase = await (0, prompts_1.select)({
73
+ message: 'Fase:',
74
+ choices: [
75
+ { name: 'MVP — entra na primeira versão', value: 'mvp' },
76
+ { name: 'Fase 2 — próxima versão', value: 'fase2' },
77
+ { name: 'Descartada — fora do escopo', value: 'fora' },
78
+ ],
79
+ });
80
+ let complexidade = '';
81
+ let camada = '';
82
+ let criterios = '';
83
+ if (fase !== 'fora') {
84
+ complexidade = await (0, prompts_1.select)({
85
+ message: 'Complexidade:',
86
+ choices: [
87
+ { value: 'Simples' }, { value: 'Média' }, { value: 'Complexa' },
88
+ ],
89
+ });
90
+ camada = await (0, prompts_1.select)({
91
+ message: 'Camada:',
92
+ choices: [
93
+ { value: 'Backend' }, { value: 'Frontend' },
94
+ { value: 'Backend + Frontend' }, { value: 'Integração' },
95
+ ],
96
+ });
97
+ }
98
+ if (fase === 'mvp') {
99
+ criterios = await (0, prompts_1.input)({
100
+ message: 'Critérios de aceitação (o que deve funcionar para considerar done):',
101
+ });
102
+ }
103
+ const item = {
104
+ id: feature.id, nome: feature.nome,
105
+ fase, complexidade, camada, criterios,
106
+ };
107
+ if (fase === 'mvp')
108
+ mvp.push(item);
109
+ if (fase === 'fase2')
110
+ fase2.push(item);
111
+ if (fase === 'fora')
112
+ fora.push(item);
113
+ console.log('');
114
+ }
115
+ const s1 = (0, ora_1.default)('Gerando tasks/active.md...').start();
116
+ await sleep(400);
117
+ fs.writeFileSync(activePath, gerarActive(mvp), 'utf-8');
118
+ s1.succeed('tasks/active.md gerado');
119
+ const s2 = (0, ora_1.default)('Atualizando tasks/backlog.md...').start();
120
+ await sleep(400);
121
+ fs.writeFileSync(backlogPath, gerarBacklog(fase2), 'utf-8');
122
+ s2.succeed('tasks/backlog.md atualizado');
123
+ const s3 = (0, ora_1.default)('Atualizando INDEX.md...').start();
124
+ await sleep(400);
125
+ atualizarIndex(indexPath, mvp);
126
+ s3.succeed('INDEX.md atualizado');
127
+ console.log(chalk_1.default.green.bold('\n✅ Priorização concluída!\n'));
128
+ console.log(chalk_1.default.white(' Resumo:'));
129
+ console.log(chalk_1.default.green(` ✓ MVP: ${mvp.length} feature(s)`));
130
+ console.log(chalk_1.default.yellow(` ○ Fase 2: ${fase2.length} feature(s)`));
131
+ console.log(chalk_1.default.gray(` ✗ Descartadas: ${fora.length} feature(s)`));
132
+ if (mvp.length > 0) {
133
+ console.log(chalk_1.default.gray('\n Tasks geradas em ') + chalk_1.default.white('tasks/active.md'));
134
+ console.log(chalk_1.default.gray('\n Próximo passo: abra o projeto no Claude Code e comece a desenvolver\n'));
135
+ console.log(chalk_1.default.hex('#2D7DD2')(' O protocolo está ativo. A IA já sabe o que fazer.\n'));
136
+ }
137
+ }
138
+ // ─── HELPERS ──────────────────────────────────────────────────────────────────
139
+ function extrairFeatures(backlog) {
140
+ const linhas = backlog.split('\n').filter(l => l.includes('[FEATURE-'));
141
+ return linhas.map(linha => {
142
+ const idMatch = linha.match(/\[FEATURE-(T\d+)\]/);
143
+ const nomeMatch = linha.match(/\[FEATURE-T\d+\] (.+?) \[/);
144
+ return {
145
+ id: idMatch ? idMatch[1] : 'T000',
146
+ nome: nomeMatch ? nomeMatch[1].trim() : 'feature',
147
+ };
148
+ }).filter((f) => f.nome);
149
+ }
150
+ function gerarActive(mvp) {
151
+ if (mvp.length === 0) {
152
+ return `# Tasks — Active\n\n> Nenhuma task no MVP ainda.\n> Execute vireum-spec prioritize para classificar as features.\n`;
153
+ }
154
+ const tasks = mvp.map((item, i) => {
155
+ const prefix = item.nome.replace(/\s+/g, '_').toUpperCase().slice(0, 8);
156
+ const num = String(i + 1).padStart(3, '0');
157
+ return `## [${prefix}-T${num}] ${item.nome}
158
+ - **Origem:** tasks/backlog.md → FEATURE-${item.id}
159
+ - **Camada:** ${item.camada}
160
+ - **Complexidade:** ${item.complexidade}
161
+ - **Critérios de aceitação:**
162
+ ${item.criterios ? item.criterios.split(',').map((c) => ` - ${c.trim()}`).join('\n') : ' - (definir antes de implementar)'}
163
+ - **Status:** [ ] Não iniciada
164
+ `;
165
+ }).join('\n');
166
+ return `# Tasks — Active
167
+
168
+ > Tarefas do MVP prontas para desenvolvimento.
169
+ > A IA só implementa tasks desta lista.
170
+ > Ao concluir uma task: marcar status, mover para done.md, atualizar INDEX.md
171
+
172
+ ---
173
+
174
+ ${tasks}`;
175
+ }
176
+ function gerarBacklog(fase2) {
177
+ if (fase2.length === 0) {
178
+ return `# Tasks — Backlog\n\n> Nenhuma feature na Fase 2 no momento.\n`;
179
+ }
180
+ const items = fase2.map(item => `- [ ] [FEATURE-${item.id}] ${item.nome} — ${item.complexidade} — ${item.camada} [FASE 2]`).join('\n');
181
+ return `# Tasks — Backlog
182
+
183
+ > Features da Fase 2. Aguardando conclusão do MVP para priorização.
184
+
185
+ ${items}
186
+ `;
187
+ }
188
+ function atualizarIndex(indexPath, mvp) {
189
+ if (!fs.existsSync(indexPath))
190
+ return;
191
+ const content = fs.readFileSync(indexPath, 'utf-8');
192
+ const tasks = mvp.map((item, i) => {
193
+ const prefix = item.nome.replace(/\s+/g, '_').toUpperCase().slice(0, 8);
194
+ const num = String(i + 1).padStart(3, '0');
195
+ return `- [ ] [${prefix}-T${num}] ${item.nome}`;
196
+ }).join('\n');
197
+ const updated = content.replace(/## Estado do MVP[\s\S]*?(?=\n## )/, `## Estado do MVP\n${tasks}\n\n`);
198
+ fs.writeFileSync(indexPath, updated, 'utf-8');
199
+ }
200
+ function sleep(ms) {
201
+ return new Promise(r => setTimeout(r, ms));
202
+ }