sdd-es 2.0.0 → 2.6.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/settings.json +29 -29
- package/.claude/settings.local.json +10 -0
- package/.claude-plugin/marketplace.json +10 -7
- package/.claude-plugin/plugin.json +59 -37
- package/.gitignore +20 -0
- package/.mcp.json +8 -0
- package/LICENSE +21 -0
- package/README.md +77 -40
- package/agents/architecture-designer.md +211 -0
- package/agents/arquitecto.md +16 -1
- package/agents/asesor-datos.md +15 -1
- package/agents/critico.md +37 -1
- package/agents/desarrollador-backend.md +3 -1
- package/agents/desarrollador-frontend.md +11 -16
- package/agents/disenador-api.md +13 -1
- package/agents/documentador.md +3 -1
- package/agents/investigador.md +3 -1
- package/agents/operaciones.md +3 -1
- package/agents/product-designer.md +268 -0
- package/agents/revisor.md +25 -1
- package/agents/seguridad.md +5 -1
- package/agents/tester.md +3 -1
- package/claude-hooks/agent-memory.js +288 -0
- package/claude-hooks/pre-tool-guard.js +61 -9
- package/cli/index.js +1 -2
- package/commands/sdd.adr.md +196 -0
- package/commands/sdd.analizar.md +23 -2
- package/commands/sdd.ayuda.md +13 -0
- package/commands/sdd.compliance.md +521 -0
- package/commands/sdd.configurar.md +34 -1
- package/commands/sdd.constitucion.md +198 -23
- package/commands/sdd.construir.md +210 -0
- package/commands/sdd.crear-mcp.md +2 -0
- package/commands/sdd.defect-report.md +134 -0
- package/commands/sdd.descubrir.md +19 -0
- package/commands/sdd.dise/303/261ar.md +188 -0
- package/commands/sdd.estado.md +120 -3
- package/commands/sdd.exportar.md +344 -0
- package/commands/sdd.implementar.md +272 -52
- package/commands/sdd.interpretar.md +239 -0
- package/commands/sdd.md +93 -4
- package/commands/sdd.optimizar-memoria.md +47 -0
- package/commands/sdd.optimizar.md +164 -0
- package/commands/sdd.planificar.md +64 -0
- package/commands/sdd.retro.md +74 -0
- package/commands/sdd.verificar.md +81 -0
- package/configuracion-ejemplo/.claude/CLAUDE.md +106 -0
- package/configuracion-ejemplo/sdd.config.yaml +10 -0
- package/craft/accessibility-baseline.md +216 -0
- package/craft/anti-ai-slop.md +158 -0
- package/craft/color.md +160 -0
- package/craft/typography.md +121 -0
- package/design-systems/bold-brutalist/DESIGN.md +239 -0
- package/design-systems/editorial-minimal/DESIGN.md +205 -0
- package/design-systems/neutral-modern/DESIGN.md +227 -0
- package/design-systems/vibrant-consumer/DESIGN.md +257 -0
- package/design-systems/warm-editorial/DESIGN.md +221 -0
- package/docs/AGENTES.md +4 -1
- package/docs/CASO-COMPLETO.md +206 -0
- package/docs/EJEMPLOS.md +61 -185
- package/docs/FABRICA.md +163 -115
- package/docs/INICIO-RAPIDO.md +27 -79
- package/docs/MEMORIA-Y-OBSERVABILIDAD.md +239 -0
- package/docs/MODELOS.md +3 -0
- package/docs/QUE-PASA-SI-FALLA.md +404 -0
- package/docs/README.md +43 -0
- package/docs/RELACION-CON-CLAUDE-CODE.md +38 -0
- package/docs/SEGURIDAD-PARA-NOTECNICOS.md +280 -0
- package/package.json +15 -10
- package/plantillas/job-story-mejorar-prompt.md +107 -0
- package/presets/enterprise.yaml +6 -0
- package/presets/lean.yaml +4 -0
- package/presets/startup.yaml +6 -0
- package/skills/adr-indexer/SKILL.md +181 -0
- package/skills/cache-audit/SKILL.md +163 -0
- package/skills/critica-diseno/SKILL.md +193 -0
- package/skills/descubrir-idea/SKILL.md +133 -0
- package/skills/effort-router/SKILL.md +128 -0
- package/skills/elegir-direccion/SKILL.md +184 -0
- package/skills/github-connect/IMPLEMENTATION-CHECKLIST.md +297 -0
- package/skills/github-connect/INDEX.md +223 -0
- package/skills/github-connect/INTEGRATION.md +361 -0
- package/skills/github-connect/QUICK-START.md +168 -0
- package/skills/github-connect/README.md +414 -0
- package/skills/github-connect/RESUMEN_IMPLEMENTACION.txt +374 -0
- package/skills/github-connect/SKILL.md +343 -0
- package/skills/github-connect/STRUCTURE.txt +252 -0
- package/skills/github-connect/example-config.yaml +41 -0
- package/skills/github-connect/github-connect.sh +419 -0
- package/skills/interpretar-idea/SKILL.md +254 -0
- package/skills/mejorar-prompt/SKILL.md +237 -0
- package/skills/memory-compactor/SKILL.md +68 -0
- package/skills/modo-guiado/SKILL.md +12 -2
- package/skills/mutation-detector/SKILL.md +134 -0
- package/skills/observabilidad-consumo/SKILL.md +164 -0
- package/skills/token-budget/SKILL.md +177 -0
- package/skills/vercel-deploy/00-START-HERE.txt +364 -0
- package/skills/vercel-deploy/CHECKLIST.md +205 -0
- package/skills/vercel-deploy/EXEC-SUMMARY.txt +322 -0
- package/skills/vercel-deploy/FLOW.txt +334 -0
- package/skills/vercel-deploy/INDEX.md +276 -0
- package/skills/vercel-deploy/INTEGRATION.md +328 -0
- package/skills/vercel-deploy/MANIFEST.md +310 -0
- package/skills/vercel-deploy/README.md +65 -0
- package/skills/vercel-deploy/SKILL.md +356 -0
- package/skills/vercel-deploy/deploy.sh +298 -0
- package/skills/vercel-deploy/estado.json.example +205 -0
- package/skills/vercel-deploy/skill.yaml +323 -0
- package/skills/vercel-deploy/vercel-deploy.sh +216 -0
- package/skills/wireframe-mvp/SKILL.md +157 -0
- package/docs/EJEMPLO-PRACTICA.md +0 -383
- package/mcp-figma/README.md +0 -158
- package/mcp-figma/package.json +0 -7
- package/mcp-figma/src/component-generator.js +0 -162
- package/mcp-figma/src/design-system-analyzer.js +0 -247
- package/mcp-figma/src/figma-client.js +0 -75
- package/mcp-figma/src/index.js +0 -114
- package/mcp-figma/src/mcp.js +0 -97
- package/mcp-figma/src/style-mapper.js +0 -85
- /package/skills/{compresion-tokens.md → compresion-tokens/SKILL.md} +0 -0
- /package/skills/{constitucion-constraint.md → constitucion-constraint/SKILL.md} +0 -0
- /package/skills/{deteccion-stack.md → deteccion-stack/SKILL.md} +0 -0
- /package/skills/{enrutador-agentes.md → enrutador-agentes/SKILL.md} +0 -0
- /package/skills/{gestion-estado.md → gestion-estado/SKILL.md} +0 -0
- /package/skills/{indexador.md → indexador/SKILL.md} +0 -0
- /package/skills/{validacion-spec.md → validacion-spec/SKILL.md} +0 -0
- /package/skills/{verificador-implementacion.md → verificador-implementacion/SKILL.md} +0 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vercel-deploy
|
|
3
|
+
description: Despliega automáticamente a Vercel. Pre-checks, build, health checks, rollback si falla.
|
|
4
|
+
tools: ["Bash"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Skill: Despliegue Automático en Vercel
|
|
8
|
+
|
|
9
|
+
## Propósito
|
|
10
|
+
|
|
11
|
+
Cerrar el ciclo idea→producción sin salir del flujo. Diferenciador vs Bolt/v0: verificación independiente PRE-deploy, no post-deploy.
|
|
12
|
+
|
|
13
|
+
Ejecución **sincrónica bloqueante**: el usuario ve al instante si funcionó o no.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Entrada requerida
|
|
18
|
+
|
|
19
|
+
- **`VERCEL_TOKEN`** (variable de entorno) — token de autenticación
|
|
20
|
+
- **`VERCEL_PROJECT_ID`** (variable de entorno, opcional) — si el proyecto ya existe en Vercel
|
|
21
|
+
- **`deploy.framework`** (detectado automáticamente: nextjs, react, vue, astro, flask, fastapi, etc.)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Flujo de 6 pasos
|
|
26
|
+
|
|
27
|
+
### PASO 1: Pre-checks (bloquea si alguno falla)
|
|
28
|
+
|
|
29
|
+
Validaciones preliminares que impiden proseguir con deploy si hay problemas:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
#!/bin/bash
|
|
33
|
+
set -e # Detener en cualquier error
|
|
34
|
+
|
|
35
|
+
echo "🔍 PASO 1: Pre-checks"
|
|
36
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
37
|
+
|
|
38
|
+
# Check 1: VERCEL_TOKEN presente
|
|
39
|
+
if [ -z "$VERCEL_TOKEN" ]; then
|
|
40
|
+
echo "❌ Error: VERCEL_TOKEN no configurado"
|
|
41
|
+
echo ""
|
|
42
|
+
echo "Instrucciones para generar:"
|
|
43
|
+
echo " 1. Ve a https://vercel.com/account/tokens"
|
|
44
|
+
echo " 2. Crea un nuevo token con scope 'full'"
|
|
45
|
+
echo " 3. Guárdalo:"
|
|
46
|
+
echo " export VERCEL_TOKEN='xxx_tu_token_aqui_xxx'"
|
|
47
|
+
echo " # O en .env:"
|
|
48
|
+
echo " echo 'VERCEL_TOKEN=xxx_tu_token_aqui_xxx' >> .env.local"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
echo "✅ VERCEL_TOKEN presente"
|
|
52
|
+
|
|
53
|
+
# Check 2: Rama limpia (sin cambios sin stagear)
|
|
54
|
+
if ! git diff-files --quiet; then
|
|
55
|
+
echo "❌ Error: Cambios sin stagear detectados"
|
|
56
|
+
echo ""
|
|
57
|
+
echo "Acción requerida:"
|
|
58
|
+
echo " git add ."
|
|
59
|
+
echo " git commit -m 'descripción de cambios'"
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
echo "✅ Rama limpia (sin cambios sin stagear)"
|
|
63
|
+
|
|
64
|
+
# Check 3: Sin secretos en código
|
|
65
|
+
echo "🔐 Escaneando por secretos en src/..."
|
|
66
|
+
SECRETOS=$(grep -r "VERCEL_TOKEN\|API_KEY\|SECRET" src/ 2>/dev/null || true)
|
|
67
|
+
if [ ! -z "$SECRETOS" ]; then
|
|
68
|
+
echo "❌ Error: Secretos detectados en código:"
|
|
69
|
+
echo "$SECRETOS"
|
|
70
|
+
echo ""
|
|
71
|
+
echo "Acción: Mueve secretos a .env.local o variables de entorno en Vercel"
|
|
72
|
+
exit 1
|
|
73
|
+
fi
|
|
74
|
+
echo "✅ Sin secretos hardcodeados en src/"
|
|
75
|
+
|
|
76
|
+
# Check 4: Tests verdes
|
|
77
|
+
echo "🧪 Ejecutando tests..."
|
|
78
|
+
if ! npm test -- --passWithNoTests 2>/dev/null; then
|
|
79
|
+
echo "❌ Error: Tests fallando"
|
|
80
|
+
echo ""
|
|
81
|
+
echo "Acción: Ejecuta `/sdd.implementar` nuevamente para arreglar issues"
|
|
82
|
+
exit 1
|
|
83
|
+
fi
|
|
84
|
+
echo "✅ Tests pasando"
|
|
85
|
+
|
|
86
|
+
echo ""
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### PASO 2: Auto-generar vercel.json si no existe
|
|
92
|
+
|
|
93
|
+
Detección automática del framework e inyección de configuración mínima válida:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
echo "⚙️ PASO 2: Configurar vercel.json"
|
|
97
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
98
|
+
|
|
99
|
+
# Detectar framework leyendo package.json
|
|
100
|
+
if [ -f package.json ]; then
|
|
101
|
+
FRAMEWORK="unknown"
|
|
102
|
+
|
|
103
|
+
if grep -q '"next"' package.json; then
|
|
104
|
+
FRAMEWORK="nextjs"
|
|
105
|
+
BUILD_CMD="npm run build"
|
|
106
|
+
OUTPUT_DIR=".next"
|
|
107
|
+
elif grep -q '"react"' package.json && ! grep -q '"next"' package.json; then
|
|
108
|
+
FRAMEWORK="react"
|
|
109
|
+
BUILD_CMD="npm run build"
|
|
110
|
+
OUTPUT_DIR="build"
|
|
111
|
+
elif grep -q '"vue"' package.json; then
|
|
112
|
+
FRAMEWORK="vue"
|
|
113
|
+
BUILD_CMD="npm run build"
|
|
114
|
+
OUTPUT_DIR="dist"
|
|
115
|
+
elif grep -q '"astro"' package.json; then
|
|
116
|
+
FRAMEWORK="astro"
|
|
117
|
+
BUILD_CMD="npm run build"
|
|
118
|
+
OUTPUT_DIR="dist"
|
|
119
|
+
elif grep -q '"fastapi\|flask"' package.json; then
|
|
120
|
+
FRAMEWORK="python"
|
|
121
|
+
BUILD_CMD="pip install -r requirements.txt"
|
|
122
|
+
OUTPUT_DIR="."
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
echo "📦 Framework detectado: $FRAMEWORK"
|
|
126
|
+
|
|
127
|
+
# Si vercel.json no existe, crearlo
|
|
128
|
+
if [ ! -f vercel.json ]; then
|
|
129
|
+
echo "Generando vercel.json..."
|
|
130
|
+
cat > vercel.json << EOF
|
|
131
|
+
{
|
|
132
|
+
"buildCommand": "$BUILD_CMD",
|
|
133
|
+
"outputDirectory": "$OUTPUT_DIR",
|
|
134
|
+
"framework": "$FRAMEWORK"
|
|
135
|
+
}
|
|
136
|
+
EOF
|
|
137
|
+
echo "✅ vercel.json creado automáticamente"
|
|
138
|
+
else
|
|
139
|
+
echo "✅ vercel.json ya existe"
|
|
140
|
+
fi
|
|
141
|
+
else
|
|
142
|
+
echo "⚠️ No se encontró package.json"
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
echo ""
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
### PASO 3: Build y Deploy a Vercel (bloqueante)
|
|
151
|
+
|
|
152
|
+
Ejecución del build local y envío a Vercel:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
echo "🚀 PASO 3: Deploy a Vercel"
|
|
156
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
157
|
+
|
|
158
|
+
# Ejecutar build local
|
|
159
|
+
echo "🔨 Compilando localmente..."
|
|
160
|
+
if ! npm run build 2>&1; then
|
|
161
|
+
echo "❌ Error: Build local falló"
|
|
162
|
+
echo ""
|
|
163
|
+
echo "Acción: Revisa los errores arriba y ejecuta `/sdd.implementar`"
|
|
164
|
+
exit 1
|
|
165
|
+
fi
|
|
166
|
+
echo "✅ Build local exitoso"
|
|
167
|
+
|
|
168
|
+
# Deploy a Vercel
|
|
169
|
+
echo "📤 Enviando a Vercel..."
|
|
170
|
+
DEPLOY_OUTPUT=$(vercel deploy --prod --token="$VERCEL_TOKEN" 2>&1)
|
|
171
|
+
DEPLOY_URL=$(echo "$DEPLOY_OUTPUT" | grep -oP 'https://[^\s]+' | head -1)
|
|
172
|
+
|
|
173
|
+
if [ -z "$DEPLOY_URL" ]; then
|
|
174
|
+
echo "❌ Error: No se pudo obtener URL de despliegue"
|
|
175
|
+
echo "Salida de Vercel:"
|
|
176
|
+
echo "$DEPLOY_OUTPUT"
|
|
177
|
+
exit 1
|
|
178
|
+
fi
|
|
179
|
+
|
|
180
|
+
echo "✅ Deploy enviado a Vercel"
|
|
181
|
+
echo " URL: $DEPLOY_URL"
|
|
182
|
+
|
|
183
|
+
echo ""
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
### PASO 4: Health Check (retry con backoff)
|
|
189
|
+
|
|
190
|
+
Validación de que la URL está respondiendo correctamente:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
echo "🏥 PASO 4: Health Check"
|
|
194
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
195
|
+
|
|
196
|
+
HEALTH_CHECK_PASSED=0
|
|
197
|
+
MAX_RETRIES=3
|
|
198
|
+
RETRY_DELAY=5
|
|
199
|
+
|
|
200
|
+
for i in $(seq 1 $MAX_RETRIES); do
|
|
201
|
+
echo "Intento $i/$MAX_RETRIES: GET $DEPLOY_URL"
|
|
202
|
+
|
|
203
|
+
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$DEPLOY_URL" --max-time 10)
|
|
204
|
+
|
|
205
|
+
if [ "$HTTP_CODE" = "200" ]; then
|
|
206
|
+
echo "✅ Health check exitoso (HTTP $HTTP_CODE)"
|
|
207
|
+
HEALTH_CHECK_PASSED=1
|
|
208
|
+
break
|
|
209
|
+
else
|
|
210
|
+
echo "⚠️ HTTP $HTTP_CODE — esperando ${RETRY_DELAY}s antes de reintentar..."
|
|
211
|
+
if [ $i -lt $MAX_RETRIES ]; then
|
|
212
|
+
sleep $RETRY_DELAY
|
|
213
|
+
fi
|
|
214
|
+
fi
|
|
215
|
+
done
|
|
216
|
+
|
|
217
|
+
if [ $HEALTH_CHECK_PASSED -eq 0 ]; then
|
|
218
|
+
echo "❌ Health check falló después de $MAX_RETRIES intentos"
|
|
219
|
+
HEALTH_STATUS="FAILED"
|
|
220
|
+
else
|
|
221
|
+
HEALTH_STATUS="OK"
|
|
222
|
+
fi
|
|
223
|
+
|
|
224
|
+
echo ""
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
### PASO 5: Rollback automático si health check falla
|
|
230
|
+
|
|
231
|
+
Reversión al despliegue anterior si la app no responde:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
echo "⏮️ PASO 5: Rollback (si es necesario)"
|
|
235
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
236
|
+
|
|
237
|
+
if [ "$HEALTH_STATUS" != "OK" ]; then
|
|
238
|
+
echo "🔄 Ejecutando rollback..."
|
|
239
|
+
|
|
240
|
+
if vercel rollback --token="$VERCEL_TOKEN" --yes 2>&1; then
|
|
241
|
+
echo "✅ Rollback completado — versión anterior está en vivo"
|
|
242
|
+
echo ""
|
|
243
|
+
echo "⚠️ ACCIÓN REQUERIDA:"
|
|
244
|
+
echo " • Revisa los logs de Vercel para diagnosticar el error"
|
|
245
|
+
echo " • Corrije el problema y ejecuta /sdd.desplegar nuevamente"
|
|
246
|
+
else
|
|
247
|
+
echo "❌ Rollback falló — contacta al equipo de DevOps"
|
|
248
|
+
exit 1
|
|
249
|
+
fi
|
|
250
|
+
else
|
|
251
|
+
echo "✅ Health check OK — sin rollback necesario"
|
|
252
|
+
fi
|
|
253
|
+
|
|
254
|
+
echo ""
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
### PASO 6: Registrar resultado
|
|
260
|
+
|
|
261
|
+
Guardar metadatos del despliegue para auditoría y monitoring:
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
echo "📊 PASO 6: Registrar Resultado"
|
|
265
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
266
|
+
|
|
267
|
+
# Crear directorio .sdd si no existe
|
|
268
|
+
mkdir -p .sdd
|
|
269
|
+
|
|
270
|
+
# Generar timestamp ISO 8601
|
|
271
|
+
TIMESTAMP=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
|
272
|
+
|
|
273
|
+
# Escribir a estado.json
|
|
274
|
+
cat > .sdd/estado.json << EOF
|
|
275
|
+
{
|
|
276
|
+
"ultimo_despliegue": {
|
|
277
|
+
"timestamp": "$TIMESTAMP",
|
|
278
|
+
"url": "$DEPLOY_URL",
|
|
279
|
+
"status": "$([ "$HEALTH_STATUS" = "OK" ] && echo "OK" || echo "ROLLED_BACK")",
|
|
280
|
+
"health_check": "$([ "$HEALTH_CHECK_PASSED" -eq 1 ] && echo "200 OK" || echo "FAILED")",
|
|
281
|
+
"framework": "$FRAMEWORK"
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
EOF
|
|
285
|
+
|
|
286
|
+
echo "✅ Estado registrado en .sdd/estado.json"
|
|
287
|
+
echo ""
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Output final para el usuario
|
|
293
|
+
|
|
294
|
+
Una vez completados todos los pasos exitosamente:
|
|
295
|
+
|
|
296
|
+
```
|
|
297
|
+
🚀 DESPLIEGUE A VERCEL — COMPLETADO
|
|
298
|
+
|
|
299
|
+
✅ Pre-checks completados
|
|
300
|
+
✅ Build exitoso
|
|
301
|
+
✅ Vercel deployment: https://mi-proyecto.vercel.app
|
|
302
|
+
✅ Health check: HTTP 200
|
|
303
|
+
|
|
304
|
+
Tu app está en vivo: https://mi-proyecto.vercel.app
|
|
305
|
+
Timestamp: 2026-06-13T14:30:00Z
|
|
306
|
+
Tiempo total: 3m 42s
|
|
307
|
+
|
|
308
|
+
Próximos pasos:
|
|
309
|
+
• Comparte la URL con testers y stakeholders
|
|
310
|
+
• Monitorea por anomalías en los próximos 15 minutos
|
|
311
|
+
• Ejecuta /sdd.snapshot para actualizar el estado del producto
|
|
312
|
+
• En caso de issues, /sdd.revertir ejecutará rollback manual
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Manejo de errores
|
|
318
|
+
|
|
319
|
+
| Error | Causa probable | Acción |
|
|
320
|
+
|-------|-----------------|--------|
|
|
321
|
+
| `VERCEL_TOKEN` ausente | No configurado en env | Mostrar instrucciones de generación (ver PASO 1) |
|
|
322
|
+
| Tests fallando | Código tiene issues | Usuario debe ejecutar `/sdd.implementar` nuevamente |
|
|
323
|
+
| Health check 502/503 | Cold start, env var faltante, o timeout | Reintenta 3 veces; si persiste, rollback automático |
|
|
324
|
+
| Build local falla | Dependencias rotas o código inválido | Usuario debe revisar errores y corregir |
|
|
325
|
+
| Cambios sin stagear | Usuario modificó código manualmente | Error: "Ejecuta `git add . && git commit` primero" |
|
|
326
|
+
| Rollback falla | Problemas con Vercel API | Contactar equipo de DevOps; escalar al SRE |
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Cuándo se invoca
|
|
331
|
+
|
|
332
|
+
1. **Automáticamente** en el PASO final de `sdd.implementar.md` si `deploy.plataforma: vercel` está configurado
|
|
333
|
+
- Con gate humano ANTES de ejecutar: "¿Despliego en Vercel?" [sí/no/después]
|
|
334
|
+
|
|
335
|
+
2. **Manualmente** ejecutando:
|
|
336
|
+
```bash
|
|
337
|
+
/sdd.desplegar
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
3. **Con promoción de entorno**:
|
|
341
|
+
```bash
|
|
342
|
+
/sdd.desplegar --environment staging
|
|
343
|
+
# o
|
|
344
|
+
/sdd.desplegar --environment production
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## Notas de implementación
|
|
350
|
+
|
|
351
|
+
- **Atomicidad**: O todo se despliega y pasa health check, o se revierte. Sin estados intermedios.
|
|
352
|
+
- **Idempotencia**: Ejecutar dos veces seguidas produce el mismo resultado (si no hay cambios de código).
|
|
353
|
+
- **Observabilidad**: Cada run deja trazas en `.sdd/estado.json` para auditoría y debugging.
|
|
354
|
+
- **Seguridad**: VERCEL_TOKEN nunca se loguea; los secretos se detectan antes de deploy.
|
|
355
|
+
- **UX**: Output visual con emojis, colores, y pasos claramente numerados.
|
|
356
|
+
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Skill: vercel-deploy
|
|
3
|
+
# Despliegue automático en Vercel con 6 pasos
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
# Colores
|
|
8
|
+
RED='\033[0;31m'
|
|
9
|
+
GREEN='\033[0;32m'
|
|
10
|
+
YELLOW='\033[1;33m'
|
|
11
|
+
BLUE='\033[0;34m'
|
|
12
|
+
NC='\033[0m' # No Color
|
|
13
|
+
|
|
14
|
+
# Funciones de utilidad
|
|
15
|
+
log_step() {
|
|
16
|
+
echo -e "${BLUE}📍 $1${NC}"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
log_success() {
|
|
20
|
+
echo -e "${GREEN}✅ $1${NC}"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
log_error() {
|
|
24
|
+
echo -e "${RED}❌ $1${NC}"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
log_warning() {
|
|
28
|
+
echo -e "${YELLOW}⚠️ $1${NC}"
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# ============================================================================
|
|
32
|
+
# PASO 1: Pre-checks
|
|
33
|
+
# ============================================================================
|
|
34
|
+
|
|
35
|
+
paso_1_prechecks() {
|
|
36
|
+
log_step "PASO 1: Pre-checks"
|
|
37
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
38
|
+
|
|
39
|
+
# Check 1: VERCEL_TOKEN
|
|
40
|
+
if [ -z "$VERCEL_TOKEN" ]; then
|
|
41
|
+
log_error "VERCEL_TOKEN no configurado"
|
|
42
|
+
echo ""
|
|
43
|
+
echo "Instrucciones para generar:"
|
|
44
|
+
echo " 1. Ve a https://vercel.com/account/tokens"
|
|
45
|
+
echo " 2. Crea un nuevo token con scope 'full'"
|
|
46
|
+
echo " 3. Guárdalo:"
|
|
47
|
+
echo " export VERCEL_TOKEN='vercel_xxx_...'"
|
|
48
|
+
exit 1
|
|
49
|
+
fi
|
|
50
|
+
log_success "VERCEL_TOKEN presente"
|
|
51
|
+
|
|
52
|
+
# Check 2: Rama limpia
|
|
53
|
+
if ! git diff-files --quiet; then
|
|
54
|
+
log_error "Cambios sin stagear detectados"
|
|
55
|
+
echo ""
|
|
56
|
+
echo "Acción requerida:"
|
|
57
|
+
echo " git add ."
|
|
58
|
+
echo " git commit -m 'Descripción de cambios'"
|
|
59
|
+
exit 1
|
|
60
|
+
fi
|
|
61
|
+
log_success "Rama limpia (sin cambios sin stagear)"
|
|
62
|
+
|
|
63
|
+
# Check 3: Sin secretos
|
|
64
|
+
log_warning "Escaneando por secretos en src/..."
|
|
65
|
+
SECRETOS=$(grep -r "VERCEL_TOKEN\|API_KEY\|SECRET\|password" src/ 2>/dev/null || true)
|
|
66
|
+
if [ ! -z "$SECRETOS" ]; then
|
|
67
|
+
log_error "Secretos detectados en código:"
|
|
68
|
+
echo "$SECRETOS"
|
|
69
|
+
exit 1
|
|
70
|
+
fi
|
|
71
|
+
log_success "Sin secretos hardcodeados"
|
|
72
|
+
|
|
73
|
+
# Check 4: Tests verdes
|
|
74
|
+
log_warning "Ejecutando tests..."
|
|
75
|
+
if ! npm test -- --passWithNoTests 2>/dev/null; then
|
|
76
|
+
log_error "Tests fallando"
|
|
77
|
+
echo ""
|
|
78
|
+
echo "Acción: Ejecuta /sdd.implementar para arreglar"
|
|
79
|
+
exit 1
|
|
80
|
+
fi
|
|
81
|
+
log_success "Tests pasando"
|
|
82
|
+
echo ""
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
# ============================================================================
|
|
86
|
+
# PASO 2: Auto-generar vercel.json
|
|
87
|
+
# ============================================================================
|
|
88
|
+
|
|
89
|
+
paso_2_vercel_config() {
|
|
90
|
+
log_step "PASO 2: Configurar vercel.json"
|
|
91
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
92
|
+
|
|
93
|
+
FRAMEWORK="unknown"
|
|
94
|
+
BUILD_CMD=""
|
|
95
|
+
OUTPUT_DIR=""
|
|
96
|
+
|
|
97
|
+
if [ -f package.json ]; then
|
|
98
|
+
if grep -q '"next"' package.json; then
|
|
99
|
+
FRAMEWORK="nextjs"
|
|
100
|
+
BUILD_CMD="npm run build"
|
|
101
|
+
OUTPUT_DIR=".next"
|
|
102
|
+
elif grep -q '"react"' package.json && ! grep -q '"next"' package.json; then
|
|
103
|
+
FRAMEWORK="react"
|
|
104
|
+
BUILD_CMD="npm run build"
|
|
105
|
+
OUTPUT_DIR="build"
|
|
106
|
+
elif grep -q '"vue"' package.json; then
|
|
107
|
+
FRAMEWORK="vue"
|
|
108
|
+
BUILD_CMD="npm run build"
|
|
109
|
+
OUTPUT_DIR="dist"
|
|
110
|
+
elif grep -q '"astro"' package.json; then
|
|
111
|
+
FRAMEWORK="astro"
|
|
112
|
+
BUILD_CMD="npm run build"
|
|
113
|
+
OUTPUT_DIR="dist"
|
|
114
|
+
elif grep -q '"fastapi\|flask"' package.json; then
|
|
115
|
+
FRAMEWORK="python"
|
|
116
|
+
BUILD_CMD="pip install -r requirements.txt"
|
|
117
|
+
OUTPUT_DIR="."
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
echo "📦 Framework detectado: $FRAMEWORK"
|
|
121
|
+
|
|
122
|
+
if [ ! -f vercel.json ]; then
|
|
123
|
+
cat > vercel.json << EOF
|
|
124
|
+
{
|
|
125
|
+
"buildCommand": "$BUILD_CMD",
|
|
126
|
+
"outputDirectory": "$OUTPUT_DIR",
|
|
127
|
+
"framework": "$FRAMEWORK"
|
|
128
|
+
}
|
|
129
|
+
EOF
|
|
130
|
+
log_success "vercel.json creado automáticamente"
|
|
131
|
+
else
|
|
132
|
+
log_success "vercel.json ya existe"
|
|
133
|
+
fi
|
|
134
|
+
else
|
|
135
|
+
log_warning "No se encontró package.json"
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
echo ""
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# ============================================================================
|
|
142
|
+
# PASO 3: Build y Deploy
|
|
143
|
+
# ============================================================================
|
|
144
|
+
|
|
145
|
+
paso_3_deploy() {
|
|
146
|
+
log_step "PASO 3: Build y Deploy a Vercel"
|
|
147
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
148
|
+
|
|
149
|
+
log_warning "Compilando localmente..."
|
|
150
|
+
if ! npm run build 2>&1; then
|
|
151
|
+
log_error "Build local falló"
|
|
152
|
+
exit 1
|
|
153
|
+
fi
|
|
154
|
+
log_success "Build local exitoso"
|
|
155
|
+
|
|
156
|
+
log_warning "Enviando a Vercel..."
|
|
157
|
+
DEPLOY_OUTPUT=$(vercel deploy --prod --token="$VERCEL_TOKEN" 2>&1)
|
|
158
|
+
DEPLOY_URL=$(echo "$DEPLOY_OUTPUT" | grep -oP 'https://[^\s]+' | head -1)
|
|
159
|
+
|
|
160
|
+
if [ -z "$DEPLOY_URL" ]; then
|
|
161
|
+
log_error "No se pudo obtener URL de despliegue"
|
|
162
|
+
echo "Salida de Vercel:"
|
|
163
|
+
echo "$DEPLOY_OUTPUT"
|
|
164
|
+
exit 1
|
|
165
|
+
fi
|
|
166
|
+
|
|
167
|
+
log_success "Deploy enviado a Vercel"
|
|
168
|
+
echo " URL: $DEPLOY_URL"
|
|
169
|
+
echo ""
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
# ============================================================================
|
|
173
|
+
# PASO 4: Health Check
|
|
174
|
+
# ============================================================================
|
|
175
|
+
|
|
176
|
+
paso_4_health_check() {
|
|
177
|
+
log_step "PASO 4: Health Check"
|
|
178
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
179
|
+
|
|
180
|
+
HEALTH_CHECK_PASSED=0
|
|
181
|
+
MAX_RETRIES=3
|
|
182
|
+
RETRY_DELAY=5
|
|
183
|
+
|
|
184
|
+
for i in $(seq 1 $MAX_RETRIES); do
|
|
185
|
+
echo "Intento $i/$MAX_RETRIES: GET $DEPLOY_URL"
|
|
186
|
+
|
|
187
|
+
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$DEPLOY_URL" --max-time 10)
|
|
188
|
+
|
|
189
|
+
if [ "$HTTP_CODE" = "200" ]; then
|
|
190
|
+
log_success "Health check exitoso (HTTP $HTTP_CODE)"
|
|
191
|
+
HEALTH_CHECK_PASSED=1
|
|
192
|
+
break
|
|
193
|
+
else
|
|
194
|
+
log_warning "HTTP $HTTP_CODE — esperando ${RETRY_DELAY}s..."
|
|
195
|
+
if [ $i -lt $MAX_RETRIES ]; then
|
|
196
|
+
sleep $RETRY_DELAY
|
|
197
|
+
fi
|
|
198
|
+
fi
|
|
199
|
+
done
|
|
200
|
+
|
|
201
|
+
if [ $HEALTH_CHECK_PASSED -eq 0 ]; then
|
|
202
|
+
log_error "Health check falló después de $MAX_RETRIES intentos"
|
|
203
|
+
HEALTH_STATUS="FAILED"
|
|
204
|
+
else
|
|
205
|
+
HEALTH_STATUS="OK"
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
echo ""
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
# ============================================================================
|
|
212
|
+
# PASO 5: Rollback (si es necesario)
|
|
213
|
+
# ============================================================================
|
|
214
|
+
|
|
215
|
+
paso_5_rollback() {
|
|
216
|
+
log_step "PASO 5: Rollback (si es necesario)"
|
|
217
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
218
|
+
|
|
219
|
+
if [ "$HEALTH_STATUS" != "OK" ]; then
|
|
220
|
+
log_warning "Ejecutando rollback..."
|
|
221
|
+
|
|
222
|
+
if vercel rollback --token="$VERCEL_TOKEN" --yes 2>&1; then
|
|
223
|
+
log_success "Rollback completado"
|
|
224
|
+
echo ""
|
|
225
|
+
log_error "Deployment was rolled back"
|
|
226
|
+
echo " • Revisa los logs de Vercel para diagnosticar"
|
|
227
|
+
echo " • Corrije el problema y ejecuta /sdd.desplegar nuevamente"
|
|
228
|
+
exit 1
|
|
229
|
+
else
|
|
230
|
+
log_error "Rollback falló"
|
|
231
|
+
exit 1
|
|
232
|
+
fi
|
|
233
|
+
else
|
|
234
|
+
log_success "Health check OK — sin rollback necesario"
|
|
235
|
+
fi
|
|
236
|
+
|
|
237
|
+
echo ""
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
# ============================================================================
|
|
241
|
+
# PASO 6: Registrar resultado
|
|
242
|
+
# ============================================================================
|
|
243
|
+
|
|
244
|
+
paso_6_register() {
|
|
245
|
+
log_step "PASO 6: Registrar Resultado"
|
|
246
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
247
|
+
|
|
248
|
+
mkdir -p .sdd
|
|
249
|
+
|
|
250
|
+
TIMESTAMP=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
|
|
251
|
+
|
|
252
|
+
cat > .sdd/estado.json << EOF
|
|
253
|
+
{
|
|
254
|
+
"ultimo_despliegue": {
|
|
255
|
+
"timestamp": "$TIMESTAMP",
|
|
256
|
+
"url": "$DEPLOY_URL",
|
|
257
|
+
"status": "$([ "$HEALTH_STATUS" = "OK" ] && echo "OK" || echo "ROLLED_BACK")",
|
|
258
|
+
"health_check": "$([ "$HEALTH_CHECK_PASSED" -eq 1 ] && echo "200 OK" || echo "FAILED")",
|
|
259
|
+
"framework": "$FRAMEWORK"
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
EOF
|
|
263
|
+
|
|
264
|
+
log_success "Estado registrado en .sdd/estado.json"
|
|
265
|
+
echo ""
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
# ============================================================================
|
|
269
|
+
# Main: Ejecutar todos los pasos
|
|
270
|
+
# ============================================================================
|
|
271
|
+
|
|
272
|
+
main() {
|
|
273
|
+
echo ""
|
|
274
|
+
echo "🚀 DESPLIEGUE A VERCEL"
|
|
275
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
276
|
+
echo ""
|
|
277
|
+
|
|
278
|
+
paso_1_prechecks
|
|
279
|
+
paso_2_vercel_config
|
|
280
|
+
paso_3_deploy
|
|
281
|
+
paso_4_health_check
|
|
282
|
+
paso_5_rollback
|
|
283
|
+
paso_6_register
|
|
284
|
+
|
|
285
|
+
# Output final
|
|
286
|
+
echo "✅ DESPLIEGUE COMPLETADO"
|
|
287
|
+
echo ""
|
|
288
|
+
echo "Tu app está en vivo:"
|
|
289
|
+
echo " 🌐 $DEPLOY_URL"
|
|
290
|
+
echo ""
|
|
291
|
+
echo "Próximos pasos:"
|
|
292
|
+
echo " • Comparte la URL con testers"
|
|
293
|
+
echo " • Monitorea por anomalías (15 minutos)"
|
|
294
|
+
echo " • Ejecuta /sdd.snapshot para actualizar estado del producto"
|
|
295
|
+
echo ""
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
main "$@"
|