Añadidos arhcivos basicos de repos

This commit is contained in:
2026-03-18 21:27:21 +01:00
commit 4bc7a7d291
31 changed files with 6506 additions and 0 deletions
@@ -0,0 +1,245 @@
---
version: 1.0.0
updated: 2026-03-11
tags: [worktree, git, cleanup, automation]
---
# Command: cleanup-worktrees
Elimina worktrees y sus ramas locales asociadas después de haber sido mergeadas. Puede limpiar un worktree específico o todos los worktrees en `worktrees/`.
**Flujo completo:**
1. Validar argumentos (issue number o --all)
2. Listar worktrees a eliminar
3. Para cada worktree:
- Verificar que la rama fue mergeada
- Eliminar worktree
- Eliminar rama local
4. Reportar limpieza completada
## Inputs
Se necesita UNO de estos parámetros:
- `issue_number`: Número de issue (NNNN) para limpiar solo ese worktree
- `--all`: Limpiar todos los worktrees en `worktrees/`
## Flujo obligatorio
### 1. Validar argumentos
Verificar que se proporcionó exactamente un argumento:
```bash
if [ $# -eq 0 ]; then
echo "Error: Debes especificar un número de issue o --all"
echo "Uso: /workspace:cleanup-worktrees <issue_number>"
echo " /workspace:cleanup-worktrees --all"
exit 1
fi
if [ $# -gt 1 ]; then
echo "Error: Demasiados argumentos"
exit 1
fi
ARG=$1
```
### 2. Determinar worktrees a limpiar
**Si es issue específica:**
```bash
if [[ "$ARG" =~ ^[0-9]{4}$ ]]; then
ISSUE_NUM=$ARG
WORKTREE_PATH="worktrees/issue-$ISSUE_NUM"
# Verificar que existe el worktree
if [ ! -d "$WORKTREE_PATH" ]; then
echo "Error: No existe el worktree $WORKTREE_PATH"
exit 1
fi
WORKTREES=("$WORKTREE_PATH")
fi
```
**Si es --all:**
```bash
if [ "$ARG" = "--all" ]; then
# Listar todos los worktrees en worktrees/
if [ ! -d "worktrees" ]; then
echo "No hay directorio worktrees/ para limpiar"
exit 0
fi
# Obtener lista de directorios en worktrees/
WORKTREES=($(find worktrees -maxdepth 1 -type d -name "issue-*" | sort))
if [ ${#WORKTREES[@]} -eq 0 ]; then
echo "No hay worktrees para limpiar"
exit 0
fi
echo "Se encontraron ${#WORKTREES[@]} worktrees para limpiar"
fi
```
**Si no es ninguno:**
```bash
if [ -z "$WORKTREES" ]; then
echo "Error: Argumento inválido '$ARG'"
echo "Usa un número de issue (ej: 0003) o --all"
exit 1
fi
```
### 3. Confirmar con el usuario
Mostrar lo que se va a eliminar:
```bash
echo "Se eliminarán los siguientes worktrees:"
for wt in "${WORKTREES[@]}"; do
ISSUE_NUM=$(basename "$wt" | sed 's/issue-//')
BRANCH="quick/fix-issue-$ISSUE_NUM"
echo " - $wt (rama: $BRANCH)"
done
echo ""
read -p "¿Continuar? (y/N): " CONFIRM
if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then
echo "Operación cancelada"
exit 0
fi
```
### 4. Limpiar cada worktree
Para cada worktree en la lista:
```bash
for wt in "${WORKTREES[@]}"; do
ISSUE_NUM=$(basename "$wt" | sed 's/issue-//')
BRANCH="quick/fix-issue-$ISSUE_NUM"
echo ""
echo "Limpiando issue $ISSUE_NUM..."
# Verificar que la rama fue mergeada (opcional, para seguridad)
MERGED=$(git branch --merged main | grep -c "$BRANCH" || true)
if [ "$MERGED" -eq 0 ]; then
echo "⚠️ Advertencia: La rama $BRANCH NO ha sido mergeada a main"
read -p "¿Eliminar de todas formas? (y/N): " FORCE
if [[ ! "$FORCE" =~ ^[Yy]$ ]]; then
echo "Saltando $wt"
continue
fi
fi
# Eliminar worktree
echo " → Eliminando worktree $wt..."
git worktree remove "$wt" --force 2>/dev/null || {
echo " ⚠️ No se pudo eliminar worktree, puede que ya esté eliminado"
}
# Eliminar rama local
echo " → Eliminando rama $BRANCH..."
git branch -D "$BRANCH" 2>/dev/null || {
echo " ⚠️ No se pudo eliminar rama, puede que ya esté eliminada"
}
echo " ✓ Issue $ISSUE_NUM limpiada"
done
```
### 5. Reportar resultado
```bash
echo ""
echo "✓ Limpieza completada"
echo ""
echo "Worktrees restantes:"
git worktree list | grep -v "(bare)" || echo " (ninguno)"
```
## Ejemplos
**Ejemplo 1: Limpiar una issue específica**
```bash
/workspace:cleanup-worktrees 0003
```
**Output:**
```
Se eliminarán los siguientes worktrees:
- worktrees/issue-0003 (rama: quick/fix-issue-0003)
¿Continuar? (y/N): y
Limpiando issue 0003...
→ Eliminando worktree worktrees/issue-0003...
→ Eliminando rama quick/fix-issue-0003...
✓ Issue 0003 limpiada
✓ Limpieza completada
Worktrees restantes:
(ninguno)
```
**Ejemplo 2: Limpiar todos los worktrees**
```bash
/workspace:cleanup-worktrees --all
```
**Output:**
```
Se encontraron 3 worktrees para limpiar
Se eliminarán los siguientes worktrees:
- worktrees/issue-0003 (rama: quick/fix-issue-0003)
- worktrees/issue-0006 (rama: quick/fix-issue-0006)
- worktrees/issue-0008 (rama: quick/fix-issue-0008)
¿Continuar? (y/N): y
Limpiando issue 0003...
→ Eliminando worktree worktrees/issue-0003...
→ Eliminando rama quick/fix-issue-0003...
✓ Issue 0003 limpiada
Limpiando issue 0006...
→ Eliminando worktree worktrees/issue-0006...
→ Eliminando rama quick/fix-issue-0006...
✓ Issue 0006 limpiada
Limpiando issue 0008...
→ Eliminando worktree worktrees/issue-0008...
→ Eliminando rama quick/fix-issue-0008...
✓ Issue 0008 limpiada
✓ Limpieza completada
```
## Convenciones
- **Nomenclatura de worktrees:** Siempre `worktrees/issue-NNNN`
- **Nomenclatura de ramas:** Siempre `quick/fix-issue-NNNN`
- **Confirmación interactiva:** Siempre pedir confirmación antes de eliminar
- **Verificación de merge:** Advertir si la rama no fue mergeada
## Reglas críticas
- **SIEMPRE verificar que la rama fue mergeada** antes de eliminar (advertir si no)
- **NUNCA eliminar sin confirmación del usuario** (a menos que se agregue flag `--force` en futuro)
- **SIEMPRE usar --force en git worktree remove** para evitar errores por cambios sin commit
- **NUNCA fallar silenciosamente** - reportar cada paso con claridad
- **SIEMPRE mostrar worktrees restantes** al final para confirmar estado
+224
View File
@@ -0,0 +1,224 @@
---
version: 1.0.0
updated: 2026-03-12
tags: [workspace, gitea, repo, creation]
---
# Command: create-repo
Crea un nuevo subrepo (child repository) en `workspaces/`, inicializándolo con la estructura core/shell/app, creando el repo en Gitea, y registrándolo en la base de datos local.
## Para el usuario
### Cuándo usar este comando
Usar cuando necesites crear un nuevo workspace (subrepo) dentro de Dataforge. El comando:
1. Solicita el nombre y descripción del repositorio
2. Muestra un resumen de lo que se creará
3. Pide confirmación antes de proceder
4. Crea el workspace completo (local + Gitea + BD)
### Prerequisitos
- Issues 0006, 0007, 0008 completados (workspaces base)
- Issue 0011a completado (comandos organizados)
- Gitea configurado y accesible (`GITEA_URL` y `GITEA_TOKEN` en env)
- Base de datos SQLite disponible
### Variables de entorno requeridas
```bash
export GITEA_URL="https://gitea.example.com"
export GITEA_TOKEN="tu-token-de-api"
export DATAFORGE_REPOS="./workspaces" # opcional, default: ./workspaces
```
### Ejemplo de uso
```bash
/workspace:create-repo
```
```
Nombre del repositorio: my-etl-pipeline
Descripción: ETL pipeline para datos de ventas
Tipo (go/data/etl/api) [go]: etl
¿Repositorio privado? (s/n) [n]: n
Resumen:
Nombre: my-etl-pipeline
Path local: ./workspaces/my-etl-pipeline
Gitea: https://gitea.example.com/Bl4cksmith/my-etl-pipeline
Módulo Go: gitea.../my-etl-pipeline
Tipo: etl
Privado: no
¿Crear repositorio? (s/n): s
✓ Directorio creado: ./workspaces/my-etl-pipeline
✓ Templates generados (core/, shell/, app/, go.mod, main.go)
✓ Git inicializado
✓ Repositorio Gitea creado
✓ Push inicial completado
✓ Registrado en base de datos
Workspace creado: ./workspaces/my-etl-pipeline
Para trabajar en él:
cd workspaces/my-etl-pipeline
```
## Para Claude
### Precondiciones
Verificar antes de ejecutar:
- [ ] Feature flag `workspace_commands` habilitado en `feature_flags.json`
- [ ] Variables de entorno `GITEA_URL` y `GITEA_TOKEN` configuradas
- [ ] Directorio `workspaces/` existe (o se puede crear)
### Flujo de implementación
#### Paso 1: Solicitar inputs interactivos
Preguntar al usuario:
1. **Nombre del repositorio** — debe ser URL-safe (lowercase, alfanumérico, guiones)
- Validar con `core.ValidateRepoName()`
- Ejemplos válidos: `my-api`, `etl-pipeline`, `data-processor`
- Ejemplos inválidos: `My API`, `my_api`, `-test-`
2. **Descripción** — texto libre, puede estar vacío
3. **Tipo** — uno de: `go` (default), `data`, `etl`, `api`
4. **¿Privado?** — `s/n`, default `n`
#### Paso 2: Mostrar resumen y pedir confirmación
```
Resumen:
Nombre: <nombre>
Path local: <DATAFORGE_REPOS>/<nombre>
Gitea: <GITEA_URL>/Bl4cksmith/<nombre>
Módulo Go: gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/Bl4cksmith/dataforge/<nombre>
Tipo: <tipo>
Privado: <sí/no>
¿Crear repositorio? (s/n):
```
Si el usuario responde `n`, cancelar sin hacer cambios.
#### Paso 3: Ejecutar creación vía `app.CreateWorkspaceCommand`
El flujo completo está implementado en `app/workspace_create.go`:
```go
params := app.CreateWorkspaceParams{
Name: nombre,
Description: descripcion,
Type: tipo,
IsPrivate: privado,
}
result, err := app.CreateWorkspaceCommand(config, params)
```
El comando hace automáticamente:
1. Validar nombre
2. Verificar que no existe en local ni en Gitea
3. Crear estructura `core/shell/app/`
4. Escribir templates (`go.mod`, `main.go`, `core/core.go`, `shell/shell.go`, `app/app.go`, `.gitignore`, `README.md`)
5. `git init` + configurar usuario
6. Crear repo en Gitea
7. Configurar remote y push inicial
8. Registrar en SQLite
**Rollback automático:** Si falla cualquier paso, limpia directorio local y elimina repo Gitea si se creó.
#### Paso 4: Mostrar resultado
```
✓ Workspace creado exitosamente
Path local: <localPath>
Gitea: <giteaURL>
Módulo Go: <moduleName>
Para trabajar en él:
cd <localPath>
```
### Manejo de errores
| Error | Causa | Solución |
|-------|-------|----------|
| "nombre de repositorio inválido" | Nombre no cumple reglas Gitea | Usar solo lowercase, alfanumérico y guiones |
| "ya existe un directorio" | Workspace ya creado localmente | Verificar `ls workspaces/` |
| "ya existe el repositorio en Gitea" | Repo creado en Gitea anteriormente | Verificar en Gitea o usar nombre diferente |
| "error al crear repositorio en Gitea" | Token inválido o sin permisos | Verificar `GITEA_TOKEN` |
| "error al hacer push inicial" | Credenciales git no configuradas | Configurar git credentials |
### Feature flag
Este comando requiere que `workspace_commands` esté habilitado:
```json
{
"features": {
"workspace_commands": {
"enabled": true
}
}
}
```
Si está deshabilitado, informar al usuario que debe habilitarlo en `feature_flags.json`.
## Troubleshooting
### Error: "nombre de repositorio inválido"
El nombre debe cumplir las reglas de Gitea:
- Solo letras, números y guiones
- No puede empezar o terminar con guión
- Entre 2 y 100 caracteres
```bash
# Válidos:
my-api
etl-pipeline-v2
data-processor
# Inválidos:
My API # espacios, mayúsculas
my_api # guión bajo
-test- # empieza/termina con guión
```
### Error: "GITEA_URL o GITEA_TOKEN no configurados"
```bash
export GITEA_URL="https://gitea.example.com"
export GITEA_TOKEN="tu-token"
# Luego ejecutar de nuevo
/workspace:create-repo
```
### Error: "ya existe un directorio en ./workspaces/<nombre>"
El workspace ya existe localmente. Opciones:
1. Usar nombre diferente
2. Eliminar directorio si fue creación fallida: `rm -rf workspaces/<nombre>`
### Error: "rollback falló"
En caso de rollback parcial, verificar manualmente:
```bash
# Ver estado local
ls workspaces/
# Ver repos en Gitea (vía API o interfaz web)
curl -H "Authorization: token $GITEA_TOKEN" $GITEA_URL/api/v1/user/repos
```
+272
View File
@@ -0,0 +1,272 @@
---
version: 1.0.0
updated: 2026-03-12
tags: [workspace, gitea, import, repos]
---
# Command: import-repo
Importa repositorios existentes al sistema Dataforge: desde GitHub/GitLab/otra instancia Gitea (URL remota), o adoptando un repo local en `workspaces/` que aún no está en Gitea.
## Para el usuario
### Cuándo usar este comando
Usar cuando necesites incorporar un repositorio existente al sistema Dataforge:
- Tienes un repo en GitHub/GitLab y quieres migrarlo a Gitea
- Tienes un repo en otra instancia de Gitea y quieres clonarlo a la tuya
- Tienes un directorio en `workspaces/` con git, pero sin estar en Gitea
- Quieres adoptar un proyecto legacy en el ecosistema Dataforge
### Prerequisitos
- Variables de entorno configuradas: `GITEA_URL` y `GITEA_TOKEN`
- Acceso de lectura al repositorio origen (si es remoto)
- Feature flag `workspace_commands` habilitado
### Variables de entorno requeridas
```bash
export GITEA_URL="https://gitea.example.com"
export GITEA_TOKEN="tu-token-de-api"
export DATAFORGE_REPOS="./workspaces" # opcional, default: ./workspaces
```
### Modos de importación
#### Caso 1: Importar desde URL remota
```bash
/workspace:import-repo
# Fuente: https://github.com/Bl4cksmith/analytics-pipeline
# Destino en Gitea: analytics-pipeline (por defecto)
```
Flujo interno:
1. Crear repo vacío en Gitea
2. Clonar origen con `git clone --mirror` (preserva historial completo)
3. Push a Gitea con `git push --mirror`
4. Clonar en `workspaces/` para desarrollo local
5. Registrar en BD SQLite
6. Limpiar temporales
#### Caso 2: Adoptar repo local
```bash
/workspace:import-repo
# Fuente: legacy-tool (nombre del dir en workspaces/)
# Destino en Gitea: legacy-tool (por defecto)
```
Flujo interno:
1. Verificar que `workspaces/legacy-tool/.git` existe
2. Crear repo vacío en Gitea
3. Añadir Gitea como remote `gitea`
4. Push de todos los branches y tags a Gitea
5. Registrar en BD SQLite
---
## Para Claude
### Flujo interactivo
#### Paso 1: Solicitar fuente
```
Fuente del repositorio:
- URL remota (ej: https://github.com/user/repo)
- Nombre local en workspaces/ (ej: legacy-tool)
¿Fuente?
```
Leer la respuesta del usuario.
#### Paso 2: Detectar modo y analizar
Usar funciones del core Go:
- `core.ValidateImportSource(source)` — validar que es segura
- `core.DetectImportMode(source)` — detectar si es remota o local
- `core.GenerateDestinationName(source)` — sugerir nombre de destino
Si es remota, informar al usuario:
```
✓ Modo: importar desde URL remota
Fuente: https://github.com/user/analytics-pipeline
Historia Git: se preservará completa (--mirror)
```
Si es local, informar:
```
✓ Modo: adoptar repositorio local
Directorio: workspaces/legacy-tool
Verificando .git...
```
Si es local, verificar que existe `workspaces/{source}/.git`. Si no existe, informar error:
```
✗ No se encontró .git en workspaces/legacy-tool
¿Quizás quisiste usar la URL completa?
```
#### Paso 3: Solicitar nombre de destino
```
Nombre en Gitea (Enter para usar '{nombre-generado}'):
```
Si el usuario presiona Enter, usar el nombre generado. Si escribe otro, validar con `core.ValidateRepoName`.
#### Paso 4: Verificar que no existe en Gitea
Llamar `GET /api/v1/repos/{owner}/{destName}`. Si ya existe:
```
✗ El repositorio {owner}/{destName} ya existe en Gitea.
Opciones:
1. Usar otro nombre
2. Cancelar
```
#### Paso 5: Solicitar opciones adicionales
```
¿Repositorio privado? (s/N):
Descripción (opcional):
```
#### Paso 6: Mostrar resumen y confirmar
```
Resumen de importación:
Fuente: {source}
Destino Gitea: {gitea_url}/{owner}/{destName}
Workspace local: workspaces/{destName}
Tipo detectado: {tipo}
Historia Git: se preservará completa
Privado: {sí/no}
¿Importar repositorio? (s/N):
```
Si el usuario responde "n" o Enter, cancelar:
```
Importación cancelada.
```
#### Paso 7: Ejecutar importación
Llamar `app.ImportRepositoryCommand(config, params)` con los parámetros recogidos.
Mostrar progreso:
```
Ejecutando importación...
✓ Creando repositorio en Gitea...
✓ Clonando fuente...
✓ Subiendo contenido a Gitea...
✓ Clonando en workspaces/...
✓ Registrando en base de datos...
✓ Limpiando temporales...
```
O para modo adopción local:
```
Ejecutando adopción...
✓ Creando repositorio en Gitea...
✓ Añadiendo remote 'gitea'...
✓ Subiendo branches y tags...
✓ Registrando en base de datos...
```
#### Paso 8: Mostrar resultado
**Éxito:**
```
Repositorio importado exitosamente.
Workspace: workspaces/{destName}
Gitea URL: {gitea_url}/{owner}/{destName}
Tipo: {tipo}
Pasos siguientes:
cd workspaces/{destName}
# El repositorio está listo para usar
# Para sincronizar en otros nodos:
/workspace:sync-repos
```
**Error:**
```
✗ Error durante la importación: {mensaje de error}
Rollback completado: no quedaron cambios parciales.
Sugerencias:
- Verifica que tienes acceso al repositorio origen
- Verifica que GITEA_TOKEN tiene permisos de escritura
- Verifica la conectividad de red
```
### Manejo de errores comunes
#### Repo ya existe en Gitea
- Detectar en Paso 4, antes de iniciar la operación
- Ofrecer cambiar el nombre
#### Credenciales inválidas / sin acceso
- Ocurre al intentar clonar repo privado sin credenciales
- Mensaje: "Acceso denegado al repositorio origen. Verifica que tienes acceso de lectura."
#### Tamaño excesivo
- Si la operación tarda más de 10 minutos, el comando tiene timeout
- Mensaje: "Timeout: el repositorio puede ser muy grande. Intenta clonar manualmente."
#### Fallo de red
- Puede ocurrir durante clone o push
- Rollback automático: se elimina el repo creado en Gitea
#### .git no encontrado (modo local)
- Verificar antes de crear repo en Gitea
- Mensaje: "No se encontró .git en workspaces/{source}"
### Integración con el sistema
Después de una importación exitosa:
- El repo está en Gitea (fuente de verdad)
- El repo está en `workspaces/{name}` (desarrollo local)
- El repo está en la BD SQLite (consultable con `/workspace:list-repos`)
- Compatible con `/workspace:sync-repos` para sincronizar en otros nodos
### Troubleshooting
**Error: "fuente inválida"**
- La fuente contiene caracteres especiales (`;`, `|`, etc.)
- Verificar que la URL es correcta
**Error: "nombre de destino inválido"**
- El nombre contiene caracteres no permitidos
- Solo letras, números, guiones y puntos. Entre 2-100 caracteres.
**Error: "rollback falló"**
- Estado inconsistente: repo puede existir en Gitea pero no localmente
- Verificar manualmente: `GET /api/v1/repos/{owner}/{name}`
- Si existe en Gitea pero no localmente, ejecutar `/workspace:sync-repos`
## Convenciones
- Confirmación obligatoria antes de ejecutar
- Rollback automático si falla cualquier paso
- Historia Git siempre preservada (--mirror para remotos, --all + --tags para locales)
- El remote `gitea` se añade sin sobrescribir `origin` existente
- Feature flag `workspace_commands` debe estar habilitado
## Referencias
- Issue 0011e: Especificación completa
- `app.ImportRepositoryCommand`: Implementación Go
- `core.ValidateImportSource`, `core.DetectImportMode`: Validación pura
- `shell.CloneRemoteToTemp`, `shell.AdoptLocalRepo`: Operaciones I/O
- Gitea API: GET /api/v1/repos/{owner}/{repo}
+170
View File
@@ -0,0 +1,170 @@
---
version: 1.0.0
updated: 2026-03-12
tags: [workspace, list, repos]
---
# Command: list-repos
Lista todos los workspaces registrados en la base de datos local con soporte de filtro y ordenamiento.
## Para el usuario
### Cuándo usar este comando
Usar para inspeccionar rápidamente los workspaces disponibles:
- Ver qué repos existen localmente
- Verificar estado de sincronización con Gitea
- Encontrar un workspace por nombre o descripción
- Ver URLs de Gitea para clonar en otra máquina
### Prerequisitos
- Issue 0007 completado (base de datos SQLite)
- Feature flag `workspace_commands` habilitado
### Sintaxis
```bash
/workspace:list-repos
/workspace:list-repos --filter <term>
/workspace:list-repos --sort <field>
```
### Ejemplos
```bash
# Listar todos los workspaces
/workspace:list-repos
# Filtrar por nombre o descripción
/workspace:list-repos --filter pipeline
# Ordenar por nombre alfabético
/workspace:list-repos --sort name
# Filtrar y ordenar combinados
/workspace:list-repos --filter etl --sort name
```
### Salida esperada
```
Workspaces locales (4 repos):
┌────────────────────────┬─────────────────────────────┬────────────────┬─────────────┐
│ Nombre │ Descripción │ Última act. │ Estado │
├────────────────────────┼─────────────────────────────┼────────────────┼─────────────┤
│ my-etl-pipeline │ ETL para datos ventas │ hace 2 días │ ✓ activo │
│ data-pipeline-v2 │ Pipeline v2 mejorado │ hace 1 sem. │ ✓ activo │
│ ml-training-service │ Servicio ML training │ hace 3 días │ ✓ activo │
│ old-experiment │ Experimento temporal │ hace 2 meses │ ✓ activo │
└────────────────────────┴─────────────────────────────┴────────────────┴─────────────┘
URLs Gitea:
- my-etl-pipeline: https://gitea-xxx.organic-machine.com/Bl4cksmith/my-etl-pipeline
- data-pipeline-v2: https://gitea-xxx.organic-machine.com/Bl4cksmith/data-pipeline-v2
- ml-training-service: https://gitea-xxx.organic-machine.com/Bl4cksmith/ml-training-service
- old-experiment: (no disponible en Gitea)
Para trabajar en un workspace:
cd workspaces/<nombre>
```
## Para Claude
### Precondiciones
Verificar antes de ejecutar:
- [ ] Feature flag `workspace_commands` habilitado en `dev/feature_flags.json`
- [ ] Base de datos inicializada (issue 0007 completado)
### Flujo de implementación
#### Paso 0: Verificar feature flag
Leer `dev/feature_flags.json`. Si `workspace_commands.enabled: false`, informar al usuario:
```
El comando /list-repos requiere que el feature flag 'workspace_commands' esté habilitado.
Editar dev/feature_flags.json y cambiar "enabled": true para workspace_commands.
```
#### Paso 1: Detectar argumentos
Parsear los argumentos del usuario:
- `--filter <term>` → filtrar por nombre/descripción (case-insensitive)
- `--sort <field>` → ordenar por campo (`name` o `date`, default: `date`)
#### Paso 2: Ejecutar vía `app.ListWorkspacesCommand`
El flujo completo está en `app/workspace_list.go`:
```go
// Listar todos:
err := app.ListWorkspacesCommand(config, "", "date")
// Filtrar:
err := app.ListWorkspacesCommand(config, "pipeline", "date")
// Filtrar y ordenar:
err := app.ListWorkspacesCommand(config, "etl", "name")
```
El comando hace automáticamente:
1. Obtener workspaces de SQLite (`shell.ListWorkspacesDB`)
2. Filtrar si hay `--filter` (`core.FilterWorkspaces` — función pura)
3. Ordenar (`core.SortWorkspaces` — función pura)
4. Formatear tabla ASCII (`core.FormatWorkspaceTable` — función pura)
5. Mostrar resultado con URLs de Gitea al final
#### Paso 3: Si no hay workspaces
Si la BD está vacía o el filtro no coincide con nada:
```
No hay workspaces registrados.
```
O si había filtro:
```
Workspaces que coinciden con 'pipeline':
No hay workspaces registrados.
```
Sugerir usar `/workspace:create-repo` para crear el primero o `/workspace:sync-repos` para importar desde Gitea.
### Decisiones de diseño
1. **Tabla ASCII con box-drawing**: Legible en cualquier terminal sin dependencias adicionales.
2. **Filtro case-insensitive**: Busca en slug, nombre y descripción.
3. **Ordenamiento por fecha por defecto**: Los más recientes primero (más útil en el día a día).
4. **URLs Gitea al final**: Separadas de la tabla para no saturar visualmente.
5. **Nombres truncados a 22 chars**: Evita tablas muy anchas.
### Manejo de errores
| Error | Causa | Solución |
|-------|-------|----------|
| "error al inicializar base de datos" | BD no creada | Ejecutar `dataforge init` |
| "error al listar workspaces" | Corrupción de BD | Ejecutar `dataforge workspace rebuild-db` |
## Troubleshooting
### No aparecen workspaces
La BD puede estar vacía. Opciones:
1. Crear un workspace: `/workspace:create-repo`
2. Importar desde Gitea: `/workspace:sync-repos`
### El filtro no encuentra nada
El filtro busca en slug, nombre y descripción (case-insensitive). Verificar:
- El término está bien escrito
- El workspace existe: ejecutar `/workspace:list-repos` sin filtro
### Tabla con formato incorrecto
Puede ocurrir si la terminal es muy estrecha. Usar una terminal de al menos 80 columnas de ancho.
+234
View File
@@ -0,0 +1,234 @@
---
version: 1.0.0
updated: 2026-03-12
tags: [workspace, gitea, sync, repos]
---
# Command: sync-repos
Sincroniza workspaces locales con repositorios en Gitea: detecta repos nuevos en Gitea que no existen localmente, clona repos faltantes, actualiza metadata en la BD local, y detecta inconsistencias (huérfanos).
## Para el usuario
### Cuándo usar este comando
Usar cuando necesites sincronizar tu estado local con Gitea:
- Después de clonar el parent repo en una máquina nueva
- Cuando otro nodo creó un workspace en Gitea
- Para verificar consistencia entre local y Gitea
- Después de ejecutar `/workspace:create-repo` en otra máquina
### Prerequisitos
- Issue 0011b completado (comando /create-repo)
- Variables de entorno configuradas: `GITEA_URL` y `GITEA_TOKEN`
- Feature flag `workspace_commands` habilitado
### Variables de entorno requeridas
```bash
export GITEA_URL="https://gitea.example.com"
export GITEA_TOKEN="tu-token-de-api"
export DATAFORGE_REPOS="./workspaces" # opcional, default: ./workspaces
```
### Ejemplo de uso
```bash
# Sincronización completa (con confirmación interactiva)
/workspace:sync-repos
# Solo análisis (dry-run)
/workspace:sync-repos --dry-run
```
### Salida esperada
```
Analizando workspaces locales...
Consultando repositorios en Gitea...
Plan de sincronización:
Repos a clonar (2) — existen en Gitea pero no localmente:
+ data-pipeline-v2 (https://gitea.example.com/Bl4cksmith/data-pipeline-v2.git)
+ ml-training-service (https://gitea.example.com/Bl4cksmith/ml-training-service.git)
Repos a actualizar metadata (1):
~ my-etl-pipeline
Repos locales no en Gitea — huérfanos (1):
? old-experiment
Total: 2 a clonar, 1 a actualizar, 1 huérfanos detectados
¿Ejecutar sincronización? (s/n): s
Clonando data-pipeline-v2...
✓ data-pipeline-v2 clonado
Clonando ml-training-service...
✓ ml-training-service clonado
⚠ old-experiment no está en Gitea (mantener local)
Sincronización completada.
Clonados: 2
Actualizados: 1
Huérfanos: 1
Workspaces activos: 4
```
## Para Claude
### Precondiciones
Verificar antes de ejecutar:
- [ ] Feature flag `workspace_commands` habilitado en `feature_flags.json`
- [ ] Variables de entorno `GITEA_URL` y `GITEA_TOKEN` configuradas
- [ ] Issue 0011b completado
### Flujo de implementación
#### Paso 0: Verificar feature flag
Leer `feature_flags.json`:
```json
{
"features": {
"workspace_commands": {
"enabled": true
}
}
}
```
Si `enabled: false`, informar al usuario y detenerse.
#### Paso 1: Detectar modo de ejecución
Determinar si el usuario pasó `--dry-run`:
- Con `--dry-run`: ejecutar solo análisis, no hacer cambios
- Sin `--dry-run`: mostrar plan y pedir confirmación antes de ejecutar
#### Paso 2: Ejecutar análisis vía `app.SyncWorkspacesCommand`
El flujo completo está implementado en `app/workspace_sync.go`:
```go
// Modo dry-run (solo análisis):
err := app.SyncWorkspacesCommand(config, true)
// Modo ejecución completa:
err := app.SyncWorkspacesCommand(config, false)
```
El comando hace automáticamente:
1. Obtener workspaces locales desde SQLite
2. Consultar repos en Gitea (organización o usuario)
3. Comparar con `core.CompareWorkspaces()` (función pura)
4. Mostrar plan con ToClone, ToUpdate, Orphans
5. Si no dry-run: clonar repos faltantes y actualizar metadata
#### Paso 3: Confirmación interactiva (si no --dry-run)
Después de mostrar el plan:
```
¿Ejecutar sincronización? (s/n):
```
- Si `n`: cancelar sin cambios
- Si `s`: ejecutar sincronización completa
#### Paso 4: Mostrar resultado final
Mostrar resumen con conteos de clonados, actualizados, huérfanos.
### Decisiones de diseño importantes
1. **Huérfanos NO se eliminan**: Si un repo local no está en Gitea, solo se reporta como huérfano. NO se elimina automáticamente (podría ser un repo en desarrollo que no está pusheado aún).
2. **Dry-run por defecto** en análisis: El plan siempre se muestra antes de ejecutar, y siempre requiere confirmación.
3. **Confirmación obligatoria**: El comando SIEMPRE muestra el plan y pide confirmación antes de clonar o actualizar.
4. **Clonación secuencial**: Los repos se clonan uno a uno (no en paralelo por simplicidad).
### Manejo de errores
| Error | Causa | Solución |
|-------|-------|----------|
| "GITEA_URL y GITEA_TOKEN son requeridos" | Variables de entorno no configuradas | `export GITEA_URL=... GITEA_TOKEN=...` |
| "error al obtener repositorios de Gitea" | Token inválido o Gitea inaccesible | Verificar token y conectividad |
| "Error clonando <repo>" | URL incorrecta o permisos insuficientes | Verificar credenciales git y permisos |
| "error al abrir base de datos" | BD no inicializada | Ejecutar `dataforge` para inicializar BD |
### Feature flag
Este comando requiere que `workspace_commands` esté habilitado:
```json
{
"features": {
"workspace_commands": {
"enabled": true
}
}
}
```
Si está deshabilitado, informar al usuario:
```
El comando /sync-repos requiere que el feature flag 'workspace_commands' esté habilitado.
Editar feature_flags.json y cambiar "enabled": true para workspace_commands.
```
## Troubleshooting
### Error: "GITEA_URL y GITEA_TOKEN son requeridos"
```bash
export GITEA_URL="https://gitea.example.com"
export GITEA_TOKEN="tu-token"
# Luego ejecutar de nuevo
/workspace:sync-repos
```
### Error: "error al obtener repositorios de Gitea"
Verificar:
1. Gitea accesible: `curl -H "Authorization: token $GITEA_TOKEN" $GITEA_URL/api/v1/user`
2. Token tiene permisos de lectura de repositorios
### Error: "Error clonando <repo>"
Posibles causas:
- Credenciales git no configuradas para HTTPS
- Repo privado sin permisos de acceso
- URL de clone incorrecta
Solución:
```bash
# Verificar credenciales git
git config --global credential.helper store
# Verificar acceso manual
git clone <clone_url>
```
### Los huérfanos no desaparecen
Los huérfanos son repos locales que no están en Gitea. Opciones:
1. Si el repo fue eliminado de Gitea: ejecutar `dataforge workspace clean <slug>`
2. Si el repo debe estar en Gitea: pushear el repo a Gitea primero
### La BD local está desactualizada
Usar `RebuildDBCommand` para reconstruir desde cero:
```bash
dataforge rebuild-db
```