specleap-framework 2.1.6 → 2.1.8
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/CHANGELOG.md +31 -0
- package/README.md +15 -1
- package/openspec/cli/apply.sh +37 -1
- package/openspec/cli/archive.sh +32 -1
- package/openspec/cli/code-review.sh +35 -1
- package/openspec/cli/common.sh +23 -0
- package/openspec/cli/enrich.sh +37 -1
- package/openspec/cli/ff.sh +35 -1
- package/openspec/cli/new.sh +39 -1
- package/openspec/cli/report.sh +35 -1
- package/openspec/cli/status.sh +29 -1
- package/openspec/cli/verify.sh +34 -1
- package/package.json +1 -1
- package/scripts/generate-contrato.sh +7 -2
- package/scripts/install-git-hooks.sh +68 -4
- package/scripts/lib/questions.en.json +831 -0
- package/setup.sh +157 -61
- /package/scripts/lib/{questions.json → questions.es.json} +0 -0
package/setup.sh
CHANGED
|
@@ -167,22 +167,70 @@ else
|
|
|
167
167
|
echo ""
|
|
168
168
|
fi
|
|
169
169
|
|
|
170
|
-
|
|
171
|
-
|
|
170
|
+
# Validación con reintentos: hasta 3 intentos antes de pedir abort/reintentar
|
|
171
|
+
GITHUB_USER=""
|
|
172
|
+
GITHUB_ATTEMPT=0
|
|
173
|
+
GITHUB_MAX_ATTEMPTS=3
|
|
172
174
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
exit 1
|
|
176
|
-
fi
|
|
175
|
+
while [ -z "$GITHUB_USER" ]; do
|
|
176
|
+
GITHUB_ATTEMPT=$((GITHUB_ATTEMPT + 1))
|
|
177
177
|
|
|
178
|
-
|
|
179
|
-
echo
|
|
180
|
-
GITHUB_USER=$(curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/user | grep -o '"login": "[^"]*' | cut -d'"' -f4)
|
|
178
|
+
read -p "$(echo -e ${YELLOW}GitHub Token:${NC} )" GITHUB_TOKEN
|
|
179
|
+
echo ""
|
|
181
180
|
|
|
182
|
-
if [ -z "$
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
181
|
+
if [ -z "$GITHUB_TOKEN" ]; then
|
|
182
|
+
if [ "$LANG" = "es" ]; then
|
|
183
|
+
echo -e "${RED}❌ Token vacío. Pega tu token de GitHub.${NC}"
|
|
184
|
+
else
|
|
185
|
+
echo -e "${RED}❌ Empty token. Paste your GitHub token.${NC}"
|
|
186
|
+
fi
|
|
187
|
+
echo ""
|
|
188
|
+
# No cuenta como intento si está vacío (probable typo / pegado mal)
|
|
189
|
+
GITHUB_ATTEMPT=$((GITHUB_ATTEMPT - 1))
|
|
190
|
+
continue
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
# Verificar token contra la API de GitHub
|
|
194
|
+
echo -ne "Verificando token... "
|
|
195
|
+
GITHUB_USER=$(curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/user | grep -o '"login": "[^"]*' | cut -d'"' -f4)
|
|
196
|
+
|
|
197
|
+
if [ -z "$GITHUB_USER" ]; then
|
|
198
|
+
echo -e "${RED}❌ Token inválido${NC}"
|
|
199
|
+
echo ""
|
|
200
|
+
|
|
201
|
+
if [ "$GITHUB_ATTEMPT" -ge "$GITHUB_MAX_ATTEMPTS" ]; then
|
|
202
|
+
if [ "$LANG" = "es" ]; then
|
|
203
|
+
echo -e "${YELLOW}⚠️ Has fallado $GITHUB_MAX_ATTEMPTS veces.${NC}"
|
|
204
|
+
read -p "$(echo -e ${YELLOW}¿[R]eintentar o [C]ancelar instalación? [R/c]:${NC} )" RETRY_CHOICE
|
|
205
|
+
else
|
|
206
|
+
echo -e "${YELLOW}⚠️ You've failed $GITHUB_MAX_ATTEMPTS times.${NC}"
|
|
207
|
+
read -p "$(echo -e ${YELLOW}[R]etry or [C]ancel installation? [R/c]:${NC} )" RETRY_CHOICE
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
if [[ "$RETRY_CHOICE" =~ ^[Cc]$ ]]; then
|
|
211
|
+
if [ "$LANG" = "es" ]; then
|
|
212
|
+
echo -e "${RED}Instalación cancelada por el usuario.${NC}"
|
|
213
|
+
else
|
|
214
|
+
echo -e "${RED}Installation cancelled by user.${NC}"
|
|
215
|
+
fi
|
|
216
|
+
exit 1
|
|
217
|
+
fi
|
|
218
|
+
# Reset contador para nueva ronda de 3 intentos
|
|
219
|
+
GITHUB_ATTEMPT=0
|
|
220
|
+
echo ""
|
|
221
|
+
continue
|
|
222
|
+
fi
|
|
223
|
+
|
|
224
|
+
if [ "$LANG" = "es" ]; then
|
|
225
|
+
echo "Intenta de nuevo (intento $((GITHUB_ATTEMPT + 1))/$GITHUB_MAX_ATTEMPTS)."
|
|
226
|
+
echo "Verifica que el token tenga los permisos: repo, workflow."
|
|
227
|
+
else
|
|
228
|
+
echo "Try again (attempt $((GITHUB_ATTEMPT + 1))/$GITHUB_MAX_ATTEMPTS)."
|
|
229
|
+
echo "Make sure the token has the scopes: repo, workflow."
|
|
230
|
+
fi
|
|
231
|
+
echo ""
|
|
232
|
+
fi
|
|
233
|
+
done
|
|
186
234
|
|
|
187
235
|
echo -e "${GREEN}✅ Token válido (Usuario: $GITHUB_USER)${NC}"
|
|
188
236
|
echo ""
|
|
@@ -227,65 +275,113 @@ else
|
|
|
227
275
|
echo ""
|
|
228
276
|
fi
|
|
229
277
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
echo -e "${RED}$MSG_ERROR Asana token is required${NC}"
|
|
235
|
-
exit 1
|
|
236
|
-
fi
|
|
278
|
+
# Validación con reintentos: hasta 3 intentos antes de pedir abort/reintentar
|
|
279
|
+
ASANA_VALID=""
|
|
280
|
+
ASANA_ATTEMPT=0
|
|
281
|
+
ASANA_MAX_ATTEMPTS=3
|
|
237
282
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
ASANA_RESPONSE=$(curl -s -H "Authorization: Bearer $ASANA_TOKEN" https://app.asana.com/api/1.0/workspaces)
|
|
283
|
+
while [ -z "$ASANA_VALID" ]; do
|
|
284
|
+
ASANA_ATTEMPT=$((ASANA_ATTEMPT + 1))
|
|
241
285
|
|
|
242
|
-
|
|
243
|
-
echo -e "${GREEN}✅ Token válido${NC}"
|
|
286
|
+
read -p "$(echo -e ${YELLOW}Asana Token:${NC} )" ASANA_TOKEN
|
|
244
287
|
echo ""
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
288
|
+
|
|
289
|
+
if [ -z "$ASANA_TOKEN" ]; then
|
|
290
|
+
if [ "$LANG" = "es" ]; then
|
|
291
|
+
echo -e "${RED}❌ Token vacío. Pega tu token de Asana (empieza con '0/' o '1/' o '2/').${NC}"
|
|
292
|
+
else
|
|
293
|
+
echo -e "${RED}❌ Empty token. Paste your Asana token (starts with '0/' or '1/' or '2/').${NC}"
|
|
294
|
+
fi
|
|
295
|
+
echo ""
|
|
296
|
+
ASANA_ATTEMPT=$((ASANA_ATTEMPT - 1))
|
|
297
|
+
continue
|
|
251
298
|
fi
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
299
|
+
|
|
300
|
+
# Verificar token y obtener workspace
|
|
301
|
+
echo -ne "Verificando token Asana... "
|
|
302
|
+
ASANA_RESPONSE=$(curl -s -H "Authorization: Bearer $ASANA_TOKEN" https://app.asana.com/api/1.0/workspaces)
|
|
303
|
+
|
|
304
|
+
if echo "$ASANA_RESPONSE" | grep -q '"gid"'; then
|
|
305
|
+
echo -e "${GREEN}✅ Token válido${NC}"
|
|
306
|
+
ASANA_VALID="yes"
|
|
307
|
+
else
|
|
308
|
+
echo -e "${RED}❌ Token inválido${NC}"
|
|
309
|
+
echo ""
|
|
310
|
+
|
|
311
|
+
if [ "$ASANA_ATTEMPT" -ge "$ASANA_MAX_ATTEMPTS" ]; then
|
|
312
|
+
if [ "$LANG" = "es" ]; then
|
|
313
|
+
echo -e "${YELLOW}⚠️ Has fallado $ASANA_MAX_ATTEMPTS veces.${NC}"
|
|
314
|
+
read -p "$(echo -e ${YELLOW}¿[R]eintentar o [C]ancelar instalación? [R/c]:${NC} )" RETRY_CHOICE
|
|
315
|
+
else
|
|
316
|
+
echo -e "${YELLOW}⚠️ You've failed $ASANA_MAX_ATTEMPTS times.${NC}"
|
|
317
|
+
read -p "$(echo -e ${YELLOW}[R]etry or [C]ancel installation? [R/c]:${NC} )" RETRY_CHOICE
|
|
318
|
+
fi
|
|
319
|
+
|
|
320
|
+
if [[ "$RETRY_CHOICE" =~ ^[Cc]$ ]]; then
|
|
321
|
+
if [ "$LANG" = "es" ]; then
|
|
322
|
+
echo -e "${RED}Instalación cancelada por el usuario.${NC}"
|
|
323
|
+
else
|
|
324
|
+
echo -e "${RED}Installation cancelled by user.${NC}"
|
|
325
|
+
fi
|
|
326
|
+
exit 1
|
|
266
327
|
fi
|
|
328
|
+
ASANA_ATTEMPT=0
|
|
329
|
+
echo ""
|
|
330
|
+
continue
|
|
267
331
|
fi
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
332
|
+
|
|
333
|
+
if [ "$LANG" = "es" ]; then
|
|
334
|
+
echo "Intenta de nuevo (intento $((ASANA_ATTEMPT + 1))/$ASANA_MAX_ATTEMPTS)."
|
|
335
|
+
echo "Verifica que el token sea Personal Access Token de Asana."
|
|
336
|
+
else
|
|
337
|
+
echo "Try again (attempt $((ASANA_ATTEMPT + 1))/$ASANA_MAX_ATTEMPTS)."
|
|
338
|
+
echo "Make sure the token is an Asana Personal Access Token."
|
|
339
|
+
fi
|
|
340
|
+
echo ""
|
|
275
341
|
fi
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
342
|
+
done
|
|
343
|
+
|
|
344
|
+
echo ""
|
|
345
|
+
|
|
346
|
+
# Listar workspaces disponibles
|
|
347
|
+
if [ "$LANG" = "es" ]; then
|
|
348
|
+
echo "Workspaces disponibles:"
|
|
349
|
+
else
|
|
350
|
+
echo "Available workspaces:"
|
|
351
|
+
fi
|
|
352
|
+
echo ""
|
|
353
|
+
|
|
354
|
+
# Extraer workspaces (simple parsing)
|
|
355
|
+
WORKSPACE_COUNT=0
|
|
356
|
+
while IFS= read -r line; do
|
|
357
|
+
if echo "$line" | grep -q '"gid"'; then
|
|
358
|
+
WORKSPACE_COUNT=$((WORKSPACE_COUNT + 1))
|
|
359
|
+
WS_GID=$(echo "$line" | grep -o '"gid":"[^"]*' | cut -d'"' -f4)
|
|
360
|
+
WS_NAME=$(echo "$ASANA_RESPONSE" | grep -A1 "\"gid\":\"$WS_GID\"" | grep '"name"' | grep -o '"name":"[^"]*' | cut -d'"' -f4)
|
|
361
|
+
echo " $WORKSPACE_COUNT) $WS_NAME (ID: $WS_GID)"
|
|
362
|
+
|
|
363
|
+
# Guardar primer workspace como default
|
|
364
|
+
if [ $WORKSPACE_COUNT -eq 1 ]; then
|
|
365
|
+
DEFAULT_WORKSPACE_ID="$WS_GID"
|
|
366
|
+
fi
|
|
281
367
|
fi
|
|
282
|
-
|
|
283
|
-
|
|
368
|
+
done < <(echo "$ASANA_RESPONSE" | grep '"gid"')
|
|
369
|
+
|
|
370
|
+
echo ""
|
|
371
|
+
if [ "$LANG" = "es" ]; then
|
|
372
|
+
read -p "$(echo -e ${YELLOW}Workspace ID [Enter para usar el primero]:${NC} )" ASANA_WORKSPACE_INPUT
|
|
284
373
|
else
|
|
285
|
-
echo -e
|
|
286
|
-
|
|
374
|
+
read -p "$(echo -e ${YELLOW}Workspace ID [Enter to use first]:${NC} )" ASANA_WORKSPACE_INPUT
|
|
375
|
+
fi
|
|
376
|
+
|
|
377
|
+
if [ -z "$ASANA_WORKSPACE_INPUT" ]; then
|
|
378
|
+
ASANA_WORKSPACE_ID="$DEFAULT_WORKSPACE_ID"
|
|
379
|
+
else
|
|
380
|
+
ASANA_WORKSPACE_ID="$ASANA_WORKSPACE_INPUT"
|
|
287
381
|
fi
|
|
288
382
|
|
|
383
|
+
echo -e "${GREEN}✅ Workspace seleccionado: $ASANA_WORKSPACE_ID${NC}"
|
|
384
|
+
|
|
289
385
|
echo ""
|
|
290
386
|
sleep 1
|
|
291
387
|
|
|
File without changes
|