create-quiver 0.4.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/.github/ISSUE_TEMPLATE/bug_report.md +15 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +15 -0
- package/.github/pull_request_template.md +4 -0
- package/.github/workflows/ci.yml +74 -0
- package/CHANGELOG.md +24 -0
- package/CODE_OF_CONDUCT.md +12 -0
- package/CONTRIBUTING.md +15 -0
- package/LICENSE +21 -0
- package/README.md +118 -0
- package/README_FOR_AI.md +90 -0
- package/ROADMAP.md +20 -0
- package/SECURITY.md +12 -0
- package/TEMPLATE.md +108 -0
- package/bin/create-quiver.js +8 -0
- package/docs/CONTEXTO.md.template +45 -0
- package/docs/DOCUMENTATION_GUIDE.md.template +34 -0
- package/docs/GITFLOW_PR_GUIDE.md.template +52 -0
- package/docs/INDEX.md.template +41 -0
- package/docs/MOCK_DATA_GUIDE.md.template +31 -0
- package/docs/MULTI_AGENT_WORKFLOW.md.template +31 -0
- package/docs/STATUS.md.template +26 -0
- package/docs/SUPPORT_MATRIX.md.template +31 -0
- package/docs/TESTING_GUIDE_FOR_AI.md.template +42 -0
- package/docs/TROUBLESHOOTING.md.template +70 -0
- package/docs/UI_STANDARDS.md.template +31 -0
- package/docs/WORKFLOW.md.template +56 -0
- package/docs/ai/LESSONS.md.template +24 -0
- package/docs/ai/PRINCIPLES.md +25 -0
- package/docs/ai/RULES.yaml +33 -0
- package/i18n/es/README.md +15 -0
- package/i18n/es/README_FOR_AI.md +6 -0
- package/i18n/es/TEMPLATE.md +18 -0
- package/i18n/es/docs/CONTEXTO.md.template +9 -0
- package/i18n/es/docs/DOCUMENTATION_GUIDE.md.template +4 -0
- package/i18n/es/docs/GITFLOW_PR_GUIDE.md.template +4 -0
- package/i18n/es/docs/INDEX.md.template +10 -0
- package/i18n/es/docs/MOCK_DATA_GUIDE.md.template +4 -0
- package/i18n/es/docs/MULTI_AGENT_WORKFLOW.md.template +4 -0
- package/i18n/es/docs/STATUS.md.template +9 -0
- package/i18n/es/docs/TESTING_GUIDE_FOR_AI.md.template +7 -0
- package/i18n/es/docs/UI_STANDARDS.md.template +4 -0
- package/i18n/es/docs/WORKFLOW.md.template +6 -0
- package/i18n/es/docs/ai/LESSONS.md.template +3 -0
- package/i18n/es/docs/ai/PRINCIPLES.md +7 -0
- package/i18n/es/docs/ai/RULES.yaml +7 -0
- package/package.json +19 -0
- package/package.template.json +10 -0
- package/scripts/check-pr-readiness.sh +138 -0
- package/scripts/check-scope.sh +150 -0
- package/scripts/check-slice-readiness.sh +319 -0
- package/scripts/cleanup-slice.sh +177 -0
- package/scripts/init-docs.sh +368 -0
- package/scripts/migrate-project.sh +218 -0
- package/scripts/package-quiver.sh +124 -0
- package/scripts/refresh-active-slices.sh +232 -0
- package/scripts/release-quiver.sh +77 -0
- package/scripts/start-slice.sh +429 -0
- package/specs/[project-name]/EVIDENCE_REPORT.md.template +15 -0
- package/specs/[project-name]/SPEC.md.template +39 -0
- package/specs/[project-name]/STATUS.md.template +22 -0
- package/specs/[project-name]/slices/pr.md.template +97 -0
- package/specs/[project-name]/slices/slice-template/slice.json +69 -0
- package/specs/quiver-v05-readme-adoption-contract/EVIDENCE_REPORT.md +21 -0
- package/specs/quiver-v05-readme-adoption-contract/SPEC.md +40 -0
- package/specs/quiver-v05-readme-adoption-contract/STATUS.md +24 -0
- package/specs/quiver-v05-readme-adoption-contract/slices/slice-01-readme-adoption-contract/slice.json +68 -0
- package/specs/quiver-v06-release-readiness/EVIDENCE_REPORT.md +23 -0
- package/specs/quiver-v06-release-readiness/SPEC.md +40 -0
- package/specs/quiver-v06-release-readiness/STATUS.md +24 -0
- package/specs/quiver-v06-release-readiness/slices/slice-01-first-npm-release-readiness/slice.json +71 -0
- package/src/create-quiver/index.js +329 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Script de Migración de Proyecto Existente
|
|
4
|
+
# Uso: ./migrate-project.sh
|
|
5
|
+
# Propósito: Migrar proyecto existente a la nueva estructura de docs-template
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
# Colores para output
|
|
10
|
+
RED='\033[0;31m'
|
|
11
|
+
GREEN='\033[0;32m'
|
|
12
|
+
YELLOW='\033[1;33m'
|
|
13
|
+
BLUE='\033[0;34m'
|
|
14
|
+
NC='\033[0m' # No Color
|
|
15
|
+
|
|
16
|
+
# Función para imprimir mensajes
|
|
17
|
+
print_info() {
|
|
18
|
+
echo -e "${BLUE}ℹ️ $1${NC}"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
print_success() {
|
|
22
|
+
echo -e "${GREEN}✅ $1${NC}"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
print_warning() {
|
|
26
|
+
echo -e "${YELLOW}⚠️ $1${NC}"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
print_error() {
|
|
30
|
+
echo -e "${RED}❌ $1${NC}"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# Verificar que existe docs/ y docs-template/
|
|
34
|
+
if [ ! -d "docs" ]; then
|
|
35
|
+
print_error "No se encontró docs/"
|
|
36
|
+
print_error "Este script es para migrar proyectos existentes"
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
if [ ! -d "docs-template" ]; then
|
|
41
|
+
print_error "No se encontró docs-template/"
|
|
42
|
+
print_error "Asegurate de estar en el directorio correcto"
|
|
43
|
+
exit 1
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
print_info "Iniciando migración de documentación..."
|
|
47
|
+
|
|
48
|
+
# Crear backup
|
|
49
|
+
BACKUP_DIR="docs-backup-$(date +%Y%m%d-%H%M%S)"
|
|
50
|
+
print_info "Creando backup en: $BACKUP_DIR"
|
|
51
|
+
cp -r docs "$BACKUP_DIR"
|
|
52
|
+
print_success "Backup creado: $BACKUP_DIR"
|
|
53
|
+
|
|
54
|
+
# Crear directorios necesarios
|
|
55
|
+
print_info "Creando nueva estructura..."
|
|
56
|
+
mkdir -p "docs/tools/playwright"
|
|
57
|
+
mkdir -p "docs/archive"
|
|
58
|
+
mkdir -p "docs/archive/analysis"
|
|
59
|
+
|
|
60
|
+
# ==========================================
|
|
61
|
+
# FASE 1: Mover documentación de herramientas a docs/tools/
|
|
62
|
+
# ==========================================
|
|
63
|
+
print_info "Fase 1: Moviendo documentación de herramientas..."
|
|
64
|
+
|
|
65
|
+
# Mover archivos de Playwright
|
|
66
|
+
if [ -f "docs/PLAYWRIGHT_CLI_COMMANDS.md" ]; then
|
|
67
|
+
mv "docs/PLAYWRIGHT_CLI_COMMANDS.md" "docs/tools/playwright/CLI_COMMANDS.md"
|
|
68
|
+
print_success "Movido: PLAYWRIGHT_CLI_COMMANDS.md → tools/playwright/CLI_COMMANDS.md"
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
if [ -f "docs/PLAYWRIGHT_CLI_QWEN_CODE.md" ]; then
|
|
72
|
+
mv "docs/PLAYWRIGHT_CLI_QWEN_CODE.md" "docs/tools/playwright/QWEN_CODE.md"
|
|
73
|
+
print_success "Movido: PLAYWRIGHT_CLI_QWEN_CODE.md → tools/playwright/QWEN_CODE.md"
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
if [ -f "docs/PLAYWRIGHT_CLI_SKILL.md" ]; then
|
|
77
|
+
mv "docs/PLAYWRIGHT_CLI_SKILL.md" "docs/tools/playwright/SKILL.md"
|
|
78
|
+
print_success "Movido: PLAYWRIGHT_CLI_SKILL.md → tools/playwright/SKILL.md"
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
if [ -f "docs/PLAYWRIGHT_BEST_PRACTICES.md" ]; then
|
|
82
|
+
mv "docs/PLAYWRIGHT_BEST_PRACTICES.md" "docs/tools/playwright/BEST_PRACTICES.md"
|
|
83
|
+
print_success "Movido: PLAYWRIGHT_BEST_PRACTICES.md → tools/playwright/BEST_PRACTICES.md"
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
if [ -f "docs/PLAYWRIGHT_CLI_IMPLEMENTATION_PLAN.md" ]; then
|
|
87
|
+
mv "docs/PLAYWRIGHT_CLI_IMPLEMENTATION_PLAN.md" "docs/archive/PLAYWRIGHT_CLI_IMPLEMENTATION_PLAN.md"
|
|
88
|
+
print_success "Movido: PLAYWRIGHT_CLI_IMPLEMENTATION_PLAN.md → archive/"
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
if [ -f "docs/PLAYWRIGHT_CLI_STATUS.md" ]; then
|
|
92
|
+
mv "docs/PLAYWRIGHT_CLI_STATUS.md" "docs/archive/PLAYWRIGHT_CLI_STATUS.md"
|
|
93
|
+
print_success "Movido: PLAYWRIGHT_CLI_STATUS.md → archive/"
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# ==========================================
|
|
97
|
+
# FASE 2: Mover archivos históricos a archive/
|
|
98
|
+
# ==========================================
|
|
99
|
+
print_info "Fase 2: Moviendo archivos históricos a archive/..."
|
|
100
|
+
|
|
101
|
+
if [ -f "docs/DOCUMENTATION_AUDIT.md" ]; then
|
|
102
|
+
mv "docs/DOCUMENTATION_AUDIT.md" "docs/archive/DOCUMENTATION_AUDIT.md"
|
|
103
|
+
print_success "Movido: DOCUMENTATION_AUDIT.md → archive/"
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
if [ -f "docs/CLEANUP_SUMMARY.md" ]; then
|
|
107
|
+
mv "docs/CLEANUP_SUMMARY.md" "docs/archive/CLEANUP_SUMMARY.md"
|
|
108
|
+
print_success "Movido: CLEANUP_SUMMARY.md → archive/"
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
# ==========================================
|
|
112
|
+
# FASE 3: Actualizar INDEX.md con nueva estructura
|
|
113
|
+
# ==========================================
|
|
114
|
+
print_info "Fase 3: Actualizando INDEX.md..."
|
|
115
|
+
|
|
116
|
+
if [ -f "docs/INDEX.md" ]; then
|
|
117
|
+
# Agregar sección de tools si no existe
|
|
118
|
+
if ! grep -q "Tools" "docs/INDEX.md"; then
|
|
119
|
+
# Buscar la línea de "Histórico" y agregar Tools antes
|
|
120
|
+
sed -i.bak '/Histórico/i\
|
|
121
|
+
### Herramientas\
|
|
122
|
+
\
|
|
123
|
+
- **[Tools](./tools/)** - Documentación de herramientas (Playwright, ESLint, etc.)\
|
|
124
|
+
' "docs/INDEX.md"
|
|
125
|
+
rm "docs/INDEX.md.bak" 2>/dev/null || true
|
|
126
|
+
print_success "Actualizado: INDEX.md (agregada sección Tools)"
|
|
127
|
+
fi
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# ==========================================
|
|
131
|
+
# FASE 4: Crear README en tools/
|
|
132
|
+
# ==========================================
|
|
133
|
+
print_info "Fase 4: Creando README en tools/..."
|
|
134
|
+
|
|
135
|
+
if [ ! -f "docs/tools/README.md" ]; then
|
|
136
|
+
cat > "docs/tools/README.md" << 'EOF'
|
|
137
|
+
# Tools Documentation
|
|
138
|
+
|
|
139
|
+
Documentación de herramientas específicas del proyecto.
|
|
140
|
+
|
|
141
|
+
## Herramientas
|
|
142
|
+
|
|
143
|
+
- **[Playwright](./playwright/)** - Testing E2E
|
|
144
|
+
|
|
145
|
+
## Agregar Nueva Herramienta
|
|
146
|
+
|
|
147
|
+
1. Crear directorio: `mkdir docs/tools/[nombre]`
|
|
148
|
+
2. Agregar README.md con documentación
|
|
149
|
+
3. Actualizar este archivo
|
|
150
|
+
|
|
151
|
+
EOF
|
|
152
|
+
print_success "Creado: docs/tools/README.md"
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
# ==========================================
|
|
156
|
+
# FASE 5: Crear README en archive/
|
|
157
|
+
# ==========================================
|
|
158
|
+
print_info "Fase 5: Creando README en archive/..."
|
|
159
|
+
|
|
160
|
+
if [ ! -f "docs/archive/README.md" ]; then
|
|
161
|
+
cat > "docs/archive/README.md" << 'EOF'
|
|
162
|
+
# Archive
|
|
163
|
+
|
|
164
|
+
Documentación histórica y planes que ya no están activos.
|
|
165
|
+
|
|
166
|
+
**No leer a menos que sea necesario para contexto histórico.**
|
|
167
|
+
|
|
168
|
+
## Contenido
|
|
169
|
+
|
|
170
|
+
- **Analysis** - Análisis y auditorías históricas
|
|
171
|
+
- **Plans** - Planes que ya se ejecutaron o cancelaron
|
|
172
|
+
- **Old Specs** - Specs viejos reemplazados
|
|
173
|
+
|
|
174
|
+
EOF
|
|
175
|
+
print_success "Creado: docs/archive/README.md"
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
# ==========================================
|
|
179
|
+
# FASE 6: Validar estructura
|
|
180
|
+
# ==========================================
|
|
181
|
+
print_info "Fase 6: Validando estructura..."
|
|
182
|
+
|
|
183
|
+
echo ""
|
|
184
|
+
print_info "Estructura final:"
|
|
185
|
+
echo ""
|
|
186
|
+
echo "docs/"
|
|
187
|
+
echo "├── Core (activos)"
|
|
188
|
+
echo "│ ├── INDEX.md"
|
|
189
|
+
echo "│ ├── CONTEXTO.md"
|
|
190
|
+
echo "│ ├── STATUS.md"
|
|
191
|
+
echo "│ ├── WORKFLOW.md"
|
|
192
|
+
echo "│ └── ai/"
|
|
193
|
+
echo "├── Tools (herramientas)"
|
|
194
|
+
echo "│ └── playwright/"
|
|
195
|
+
echo "├── Archive (histórico)"
|
|
196
|
+
echo "│ ├── analysis/"
|
|
197
|
+
echo "│ └── [archivos históricos]"
|
|
198
|
+
echo "└── [otros archivos específicos del proyecto]"
|
|
199
|
+
echo ""
|
|
200
|
+
|
|
201
|
+
# ==========================================
|
|
202
|
+
# Resumen
|
|
203
|
+
# ==========================================
|
|
204
|
+
echo ""
|
|
205
|
+
print_success "¡Migración completada!"
|
|
206
|
+
echo ""
|
|
207
|
+
echo "📁 Resumen de cambios:"
|
|
208
|
+
echo " - Documentación de herramientas → docs/tools/"
|
|
209
|
+
echo " - Archivos históricos → docs/archive/"
|
|
210
|
+
echo " - Backup creado → $BACKUP_DIR"
|
|
211
|
+
echo ""
|
|
212
|
+
echo "📝 Próximos pasos:"
|
|
213
|
+
echo " 1. Verificar que todos los links en INDEX.md funcionen"
|
|
214
|
+
echo " 2. Actualizar referencias a archivos movidos"
|
|
215
|
+
echo " 3. Eliminar backup cuando estés seguro: rm -rf $BACKUP_DIR"
|
|
216
|
+
echo ""
|
|
217
|
+
print_warning "Importante: Verificar que no haya links rotos"
|
|
218
|
+
echo ""
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
repo_root="$(git rev-parse --show-toplevel)"
|
|
6
|
+
temp_root="$(mktemp -d "${TMPDIR:-/tmp}/quiver-pack.XXXXXX")"
|
|
7
|
+
pack_dir="$temp_root/pack"
|
|
8
|
+
npm_cache="$temp_root/npm-cache"
|
|
9
|
+
|
|
10
|
+
cleanup() {
|
|
11
|
+
rm -rf "$temp_root"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
trap cleanup EXIT
|
|
15
|
+
|
|
16
|
+
mkdir -p "$pack_dir"
|
|
17
|
+
mkdir -p "$npm_cache"
|
|
18
|
+
|
|
19
|
+
pack_json="$(
|
|
20
|
+
cd "$repo_root" && npm_config_cache="$npm_cache" npm pack --json --pack-destination "$pack_dir"
|
|
21
|
+
)"
|
|
22
|
+
|
|
23
|
+
tarball_name="$(
|
|
24
|
+
node -e 'const data = JSON.parse(process.argv[1]); process.stdout.write(data[0].filename);' "$pack_json"
|
|
25
|
+
)"
|
|
26
|
+
tarball_path="$pack_dir/$tarball_name"
|
|
27
|
+
|
|
28
|
+
if [[ ! -f "$tarball_path" ]]; then
|
|
29
|
+
echo "FAIL: no se encontró el tarball generado en $tarball_path" >&2
|
|
30
|
+
exit 1
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
contents="$(
|
|
34
|
+
tar -tzf "$tarball_path"
|
|
35
|
+
)"
|
|
36
|
+
|
|
37
|
+
require_present() {
|
|
38
|
+
local path="$1"
|
|
39
|
+
|
|
40
|
+
if ! printf '%s\n' "$contents" | grep -Fxq "$path"; then
|
|
41
|
+
echo "FAIL: falta '$path' en el paquete" >&2
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
require_absent() {
|
|
47
|
+
local path="$1"
|
|
48
|
+
|
|
49
|
+
if printf '%s\n' "$contents" | grep -Fxq "$path"; then
|
|
50
|
+
echo "FAIL: '$path' no debería publicarse en el paquete" >&2
|
|
51
|
+
exit 1
|
|
52
|
+
fi
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
required_paths=(
|
|
56
|
+
"package/package.json"
|
|
57
|
+
"package/bin/create-quiver.js"
|
|
58
|
+
"package/src/create-quiver/index.js"
|
|
59
|
+
"package/README.md"
|
|
60
|
+
"package/README_FOR_AI.md"
|
|
61
|
+
"package/TEMPLATE.md"
|
|
62
|
+
"package/LICENSE"
|
|
63
|
+
"package/CONTRIBUTING.md"
|
|
64
|
+
"package/CODE_OF_CONDUCT.md"
|
|
65
|
+
"package/SECURITY.md"
|
|
66
|
+
"package/CHANGELOG.md"
|
|
67
|
+
"package/ROADMAP.md"
|
|
68
|
+
"package/.github/pull_request_template.md"
|
|
69
|
+
"package/.github/ISSUE_TEMPLATE/bug_report.md"
|
|
70
|
+
"package/.github/ISSUE_TEMPLATE/feature_request.md"
|
|
71
|
+
"package/.github/workflows/ci.yml"
|
|
72
|
+
"package/docs/INDEX.md.template"
|
|
73
|
+
"package/docs/DOCUMENTATION_GUIDE.md.template"
|
|
74
|
+
"package/docs/WORKFLOW.md.template"
|
|
75
|
+
"package/docs/SUPPORT_MATRIX.md.template"
|
|
76
|
+
"package/docs/TROUBLESHOOTING.md.template"
|
|
77
|
+
"package/docs/TESTING_GUIDE_FOR_AI.md.template"
|
|
78
|
+
"package/docs/ai/PRINCIPLES.md"
|
|
79
|
+
"package/docs/ai/RULES.yaml"
|
|
80
|
+
"package/docs/ai/LESSONS.md.template"
|
|
81
|
+
"package/specs/[project-name]/SPEC.md.template"
|
|
82
|
+
"package/specs/[project-name]/STATUS.md.template"
|
|
83
|
+
"package/specs/[project-name]/EVIDENCE_REPORT.md.template"
|
|
84
|
+
"package/specs/[project-name]/slices/pr.md.template"
|
|
85
|
+
"package/specs/[project-name]/slices/slice-template/slice.json"
|
|
86
|
+
"package/scripts/init-docs.sh"
|
|
87
|
+
"package/scripts/start-slice.sh"
|
|
88
|
+
"package/scripts/check-slice-readiness.sh"
|
|
89
|
+
"package/scripts/check-pr-readiness.sh"
|
|
90
|
+
"package/scripts/check-scope.sh"
|
|
91
|
+
"package/scripts/cleanup-slice.sh"
|
|
92
|
+
"package/scripts/release-quiver.sh"
|
|
93
|
+
"package/scripts/refresh-active-slices.sh"
|
|
94
|
+
"package/scripts/migrate-project.sh"
|
|
95
|
+
"package/scripts/package-quiver.sh"
|
|
96
|
+
"package/i18n/es/README.md"
|
|
97
|
+
"package/i18n/es/README_FOR_AI.md"
|
|
98
|
+
"package/i18n/es/TEMPLATE.md"
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
for path in "${required_paths[@]}"; do
|
|
102
|
+
require_present "$path"
|
|
103
|
+
done
|
|
104
|
+
|
|
105
|
+
excluded_paths=(
|
|
106
|
+
"package/package-lock.json"
|
|
107
|
+
"package/tests/"
|
|
108
|
+
"package/examples/"
|
|
109
|
+
"package/.worktrees/"
|
|
110
|
+
"package/specs/quiver-v01/"
|
|
111
|
+
"package/specs/quiver-v02-bootstrap-hardening/"
|
|
112
|
+
"package/specs/quiver-v03-adoption-verification/"
|
|
113
|
+
"package/specs/quiver-v04-zero-friction-installation/"
|
|
114
|
+
"package/scripts/ci/"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
for path in "${excluded_paths[@]}"; do
|
|
118
|
+
if printf '%s\n' "$contents" | grep -Fq "$path"; then
|
|
119
|
+
echo "FAIL: el paquete incluye contenido fuera del contrato: $path" >&2
|
|
120
|
+
exit 1
|
|
121
|
+
fi
|
|
122
|
+
done
|
|
123
|
+
|
|
124
|
+
printf 'Package smoke passed: %s\n' "$tarball_name"
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
repo_root="$(git rev-parse --show-toplevel)"
|
|
6
|
+
output_path="$repo_root/ACTIVE_SLICES.md"
|
|
7
|
+
|
|
8
|
+
append_unique_line() {
|
|
9
|
+
local file_path="$1"
|
|
10
|
+
local line="$2"
|
|
11
|
+
|
|
12
|
+
touch "$file_path"
|
|
13
|
+
|
|
14
|
+
if ! grep -Fxq "$line" "$file_path"; then
|
|
15
|
+
printf '%s\n' "$line" >> "$file_path"
|
|
16
|
+
fi
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
exclude_path="$(git -C "$repo_root" rev-parse --git-path info/exclude)"
|
|
20
|
+
append_unique_line "$exclude_path" "ACTIVE_SLICES.md"
|
|
21
|
+
|
|
22
|
+
node - "$repo_root" "$output_path" <<'NODE'
|
|
23
|
+
const fs = require('fs');
|
|
24
|
+
const path = require('path');
|
|
25
|
+
const cp = require('child_process');
|
|
26
|
+
|
|
27
|
+
const [repoRoot, outputPath] = process.argv.slice(2);
|
|
28
|
+
|
|
29
|
+
function run(cmd) {
|
|
30
|
+
return cp.execSync(cmd, {
|
|
31
|
+
cwd: repoRoot,
|
|
32
|
+
encoding: 'utf8',
|
|
33
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function walkSlices(rootDir, acc) {
|
|
38
|
+
if (!fs.existsSync(rootDir)) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for (const entry of fs.readdirSync(rootDir, { withFileTypes: true })) {
|
|
43
|
+
const fullPath = path.join(rootDir, entry.name);
|
|
44
|
+
if (entry.isDirectory()) {
|
|
45
|
+
walkSlices(fullPath, acc);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (entry.isFile() && entry.name === 'slice.json' && fullPath.includes(`${path.sep}slices${path.sep}`)) {
|
|
50
|
+
const json = JSON.parse(fs.readFileSync(fullPath, 'utf8'));
|
|
51
|
+
const relPath = path.relative(repoRoot, fullPath);
|
|
52
|
+
const parts = relPath.split(path.sep);
|
|
53
|
+
const specFamily = parts[0];
|
|
54
|
+
const specSlug = parts[1];
|
|
55
|
+
const branchName = json.git?.branch_name;
|
|
56
|
+
if (!branchName) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
acc.set(branchName, {
|
|
61
|
+
specFamily,
|
|
62
|
+
specSlug,
|
|
63
|
+
relPath,
|
|
64
|
+
sliceId: json.slice_id || path.basename(path.dirname(fullPath)),
|
|
65
|
+
title: json.title || json.slice_id || path.basename(path.dirname(fullPath)),
|
|
66
|
+
ticket: json.ticket || '',
|
|
67
|
+
status: json.status || 'pending'
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function parseWorktrees(text) {
|
|
74
|
+
const entries = [];
|
|
75
|
+
const chunks = text.trim().split('\n\n').filter(Boolean);
|
|
76
|
+
for (const chunk of chunks) {
|
|
77
|
+
const lines = chunk.split('\n');
|
|
78
|
+
const entry = {};
|
|
79
|
+
for (const line of lines) {
|
|
80
|
+
const idx = line.indexOf(' ');
|
|
81
|
+
if (idx === -1) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const key = line.slice(0, idx);
|
|
85
|
+
const value = line.slice(idx + 1);
|
|
86
|
+
entry[key] = value;
|
|
87
|
+
}
|
|
88
|
+
entries.push(entry);
|
|
89
|
+
}
|
|
90
|
+
return entries;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function toAlias(ticket) {
|
|
94
|
+
const parts = String(ticket || '').split('-').filter(Boolean);
|
|
95
|
+
const prefix = (parts[0] || 'GEN').replace(/[^A-Za-z0-9]/g, '').toUpperCase();
|
|
96
|
+
const suffix = (parts[parts.length - 1] || '00').replace(/[^A-Za-z0-9]/g, '').toUpperCase();
|
|
97
|
+
const short = prefix.length <= 3 ? prefix : prefix.slice(0, 3);
|
|
98
|
+
return `${short || 'GEN'}-${suffix || '00'}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function mdEscape(value) {
|
|
102
|
+
return String(value ?? '').replace(/\|/g, '\\|');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const sliceMap = new Map();
|
|
106
|
+
walkSlices(path.join(repoRoot, 'specs'), sliceMap);
|
|
107
|
+
walkSlices(path.join(repoRoot, 'specs-fix'), sliceMap);
|
|
108
|
+
|
|
109
|
+
const worktrees = parseWorktrees(run('git worktree list --porcelain'));
|
|
110
|
+
|
|
111
|
+
const primary = [];
|
|
112
|
+
const active = [];
|
|
113
|
+
const frozen = [];
|
|
114
|
+
const auxiliary = [];
|
|
115
|
+
|
|
116
|
+
for (const entry of worktrees) {
|
|
117
|
+
const worktreePath = entry.worktree;
|
|
118
|
+
const branchRef = entry.branch || '';
|
|
119
|
+
const branchName = branchRef.replace('refs/heads/', '');
|
|
120
|
+
|
|
121
|
+
if (worktreePath === repoRoot) {
|
|
122
|
+
primary.push({
|
|
123
|
+
branch: branchName || '(detached)',
|
|
124
|
+
path: worktreePath
|
|
125
|
+
});
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const slice = sliceMap.get(branchName);
|
|
130
|
+
if (!slice) {
|
|
131
|
+
auxiliary.push({
|
|
132
|
+
branch: branchName || '(detached)',
|
|
133
|
+
path: worktreePath
|
|
134
|
+
});
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let liveStatus = slice.status;
|
|
139
|
+
const liveSlicePath = path.join(worktreePath, slice.relPath);
|
|
140
|
+
if (fs.existsSync(liveSlicePath)) {
|
|
141
|
+
try {
|
|
142
|
+
const liveJson = JSON.parse(fs.readFileSync(liveSlicePath, 'utf8'));
|
|
143
|
+
liveStatus = liveJson.status || liveStatus;
|
|
144
|
+
} catch {}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const row = {
|
|
148
|
+
alias: toAlias(slice.ticket),
|
|
149
|
+
spec: slice.specSlug,
|
|
150
|
+
slice: slice.sliceId,
|
|
151
|
+
branch: branchName,
|
|
152
|
+
path: worktreePath,
|
|
153
|
+
status: liveStatus,
|
|
154
|
+
title: slice.title
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
if (slice.sliceId.startsWith('slice-00')) {
|
|
158
|
+
frozen.push(row);
|
|
159
|
+
} else {
|
|
160
|
+
active.push(row);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
active.sort((a, b) => a.alias.localeCompare(b.alias));
|
|
165
|
+
frozen.sort((a, b) => a.alias.localeCompare(b.alias));
|
|
166
|
+
auxiliary.sort((a, b) => a.branch.localeCompare(b.branch));
|
|
167
|
+
|
|
168
|
+
const lines = [
|
|
169
|
+
'# Active Slices',
|
|
170
|
+
'',
|
|
171
|
+
'> Archivo local generado por `tools/scripts/refresh-active-slices.sh`.',
|
|
172
|
+
'> No se trackea en git.',
|
|
173
|
+
'',
|
|
174
|
+
`**Actualizado:** ${new Date().toISOString()}`,
|
|
175
|
+
'',
|
|
176
|
+
'## Convencion',
|
|
177
|
+
'',
|
|
178
|
+
'- `Alias`: identificador corto para hablar del slice sin ambiguedad',
|
|
179
|
+
'- `Spec`: directorio del spec',
|
|
180
|
+
'- `slice-00`: baseline congelado, solo referencia',
|
|
181
|
+
'- `slice-01+`: implementacion o revalidacion',
|
|
182
|
+
'',
|
|
183
|
+
'## Checkout Principal',
|
|
184
|
+
'',
|
|
185
|
+
'| Branch | Path |',
|
|
186
|
+
'|--------|------|'
|
|
187
|
+
];
|
|
188
|
+
|
|
189
|
+
for (const row of primary) {
|
|
190
|
+
lines.push(`| ${mdEscape(row.branch)} | ${mdEscape(row.path)} |`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
lines.push('', '## Implementacion Activa', '', '| Alias | Spec | Slice | Branch | Estado | Path |', '|-------|------|-------|--------|--------|------|');
|
|
194
|
+
if (active.length === 0) {
|
|
195
|
+
lines.push('| - | - | - | - | - | - |');
|
|
196
|
+
} else {
|
|
197
|
+
for (const row of active) {
|
|
198
|
+
lines.push(`| ${mdEscape(row.alias)} | ${mdEscape(row.spec)} | ${mdEscape(row.slice)} | ${mdEscape(row.branch)} | ${mdEscape(row.status)} | ${mdEscape(row.path)} |`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
lines.push('', '## Baselines Congelados', '', '| Alias | Spec | Slice | Branch | Estado | Path |', '|-------|------|-------|--------|--------|------|');
|
|
203
|
+
if (frozen.length === 0) {
|
|
204
|
+
lines.push('| - | - | - | - | - | - |');
|
|
205
|
+
} else {
|
|
206
|
+
for (const row of frozen) {
|
|
207
|
+
lines.push(`| ${mdEscape(row.alias)} | ${mdEscape(row.spec)} | ${mdEscape(row.slice)} | ${mdEscape(row.branch)} | congelado | ${mdEscape(row.path)} |`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
lines.push('', '## Worktrees Auxiliares', '', '| Branch | Path |', '|--------|------|');
|
|
212
|
+
if (auxiliary.length === 0) {
|
|
213
|
+
lines.push('| - | - |');
|
|
214
|
+
} else {
|
|
215
|
+
for (const row of auxiliary) {
|
|
216
|
+
lines.push(`| ${mdEscape(row.branch)} | ${mdEscape(row.path)} |`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
lines.push(
|
|
221
|
+
'',
|
|
222
|
+
'## Recomendacion Operativa',
|
|
223
|
+
'',
|
|
224
|
+
'- En VS Code, dejar visibles solo `develop` y la tabla de `Implementacion Activa`.',
|
|
225
|
+
'- Tratar la tabla de `Baselines Congelados` como solo lectura.',
|
|
226
|
+
'- Cerrar visualmente los `Worktrees Auxiliares` salvo cuando estes trabajando ese PR o esa tarea de proceso.'
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
fs.writeFileSync(outputPath, `${lines.join('\n')}\n`);
|
|
230
|
+
NODE
|
|
231
|
+
|
|
232
|
+
printf 'Active slices refreshed: %s\n' "$output_path"
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
release_type="patch"
|
|
6
|
+
publish="false"
|
|
7
|
+
publish_current="false"
|
|
8
|
+
|
|
9
|
+
usage() {
|
|
10
|
+
cat <<'EOF'
|
|
11
|
+
Usage: scripts/release-quiver.sh [patch|minor|major|x.y.z] [--publish | --publish-current]
|
|
12
|
+
|
|
13
|
+
By default the script performs a release dry run:
|
|
14
|
+
- validates the installer smoke
|
|
15
|
+
- validates the package artifact
|
|
16
|
+
- prints the versioning and publish commands to run next
|
|
17
|
+
|
|
18
|
+
Pass --publish to run npm version and npm publish after the smoke checks pass.
|
|
19
|
+
Pass --publish-current to publish the current package version without forcing a patch bump.
|
|
20
|
+
EOF
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
while [[ $# -gt 0 ]]; do
|
|
24
|
+
case "$1" in
|
|
25
|
+
--publish)
|
|
26
|
+
publish="true"
|
|
27
|
+
shift
|
|
28
|
+
;;
|
|
29
|
+
--publish-current)
|
|
30
|
+
publish_current="true"
|
|
31
|
+
publish="true"
|
|
32
|
+
shift
|
|
33
|
+
;;
|
|
34
|
+
-h|--help)
|
|
35
|
+
usage
|
|
36
|
+
exit 0
|
|
37
|
+
;;
|
|
38
|
+
*)
|
|
39
|
+
release_type="$1"
|
|
40
|
+
shift
|
|
41
|
+
;;
|
|
42
|
+
esac
|
|
43
|
+
done
|
|
44
|
+
|
|
45
|
+
repo_root="$(git rev-parse --show-toplevel)"
|
|
46
|
+
cd "$repo_root"
|
|
47
|
+
|
|
48
|
+
if [[ -n "$(git status --porcelain)" ]]; then
|
|
49
|
+
echo "FAIL: release requires a clean worktree" >&2
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
bash scripts/ci/smoke-create-quiver.sh
|
|
54
|
+
bash scripts/package-quiver.sh
|
|
55
|
+
|
|
56
|
+
if [[ "$publish" == "false" ]]; then
|
|
57
|
+
echo "Release dry run passed."
|
|
58
|
+
echo "Next commands:"
|
|
59
|
+
if [[ "$publish_current" == "true" ]]; then
|
|
60
|
+
echo " npm publish --access public"
|
|
61
|
+
else
|
|
62
|
+
echo " npm version $release_type -m \"chore(release): %s\""
|
|
63
|
+
echo " npm publish --access public"
|
|
64
|
+
fi
|
|
65
|
+
echo " git push origin HEAD --tags"
|
|
66
|
+
exit 0
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
if [[ "$publish_current" == "true" ]]; then
|
|
70
|
+
npm publish --access public
|
|
71
|
+
git push origin HEAD --tags
|
|
72
|
+
exit 0
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
npm version "$release_type" -m "chore(release): %s"
|
|
76
|
+
npm publish --access public
|
|
77
|
+
git push origin HEAD --tags
|