Files
fn_registry/.claude/commands/compile.md
T
egutierrez 81d8a7c95d feat(framework): assets/ subfolder para distribuibles read-only
Refina la convencion de layout: el top de cada app distribuible
solo lleva el .exe + DLLs nativas; todo lo demas (TTFs, enrichers,
runtime Python, MCP servers) vive en <exe_dir>/assets/.

Cambios:
- cpp/CMakeLists.txt::add_imgui_app — copia las 5 TTFs (Karla,
  Roboto, DroidSans, Cousine, tabler-icons) a
  $<TARGET_FILE_DIR>/assets/ en lugar de junto al exe.
- framework/app_base: nuevas funciones fn::asset_dir() y
  fn::asset_path(name) que resuelven a <exe_dir>/assets/<name>.
- functions/core/icon_font.cpp::find_asset — anade
  fn::asset_path(filename) como PRIMERA ruta de busqueda, antes
  de las legacy ./<file> y ./assets/<file>. Mantiene los
  fallbacks para dev (FN_ASSETS_DIR, FN_CPP_ROOT).
- .claude/commands/compile.md — el deploy a Desktop pone TTFs +
  enrichers/ + runtime/ + gx-cli en <DEST>/assets/. Solo .exe y
  DLLs nativas (duckdb.dll) quedan en el top. local_files/ se
  preserva si existe.

Layout final:
  Desktop/apps/<APP>/
  ├── <APP>.exe + *.dll          (binario + DLLs Windows)
  ├── assets/                    (read-only distribuible)
  │   ├── *.ttf, enrichers/, runtime/, gx-cli, ...
  └── local_files/               (per-PC, creado al primer arranque)

Esto cierra la separacion conceptual de la convencion: la carpeta
es trivial de zippear (solo .exe + assets/), el reset/sync es
trivial (local_files/), y todas las apps del registry adoptan el
mismo layout via fn_framework.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 00:50:33 +02:00

7.9 KiB

/compile — Compila la app actual y la copia al escritorio de Windows

Compila una app del registry para los targets que soporte (Windows via MinGW, Android via Gradle/NDK si esta configurado) y deja el resultado en /mnt/c/Users/lucas/Desktop/apps/<app>/, listo para usar desde Windows.

Pensado para apps C++ del workspace cpp/ (donde ya hay toolchain mingw-w64.cmake y build dir cpp/build/windows/). Si en el futuro hay apps Android (Gradle wrapper o NDK), tambien las detecta.

Argumento

$ARGUMENTS — opcional. Nombre de la app a compilar (ej: chart_demo, registry_dashboard).

  • Sin argumento: detectar la app desde pwd (si estas dentro de cpp/apps/<X>/ o projects/*/apps/<X>/).
  • Si no hay app deducible y no se pasa argumento → listar apps disponibles y pedir nombre.
  • Si se pasa argumento, usarlo directamente.

Pasos

1. Resolver la app y su directorio fuente

ROOT=/home/lucas/fn_registry
APP_ARG="$ARGUMENTS"

# Detectar desde CWD si no hay argumento
if [ -z "$APP_ARG" ]; then
  CWD="$(pwd)"
  case "$CWD" in
    "$ROOT"/cpp/apps/*|"$ROOT"/projects/*/apps/*)
      APP_ARG="$(basename "$CWD")" ;;
  esac
fi

# Si sigue vacio, listar apps y abortar
if [ -z "$APP_ARG" ]; then
  echo "Apps disponibles:"
  ls "$ROOT"/cpp/apps/ 2>/dev/null
  ls "$ROOT"/projects/*/apps/ 2>/dev/null
  echo "Uso: /compile <app_name>"
  exit 1
fi

# Buscar el directorio real
APP_DIR=""
for cand in "$ROOT/cpp/apps/$APP_ARG" "$ROOT"/projects/*/apps/"$APP_ARG"; do
  [ -d "$cand" ] && APP_DIR="$cand" && break
done

if [ -z "$APP_DIR" ]; then
  echo "No encuentro app '$APP_ARG' en cpp/apps/ ni projects/*/apps/"
  exit 1
fi
echo "App: $APP_ARG"
echo "Dir: $APP_DIR"

2. Detectar targets soportados

Examinar el app.md y los archivos del directorio para decidir que se puede compilar:

  • Windows (MinGW): si la app tiene CMakeLists.txt y se registra en cpp/CMakeLists.txt (es decir, aparece como subdirectorio en cpp/build/windows/apps/<APP>/). Default para apps C++.
  • Android: si existe AndroidManifest.xml, build.gradle, build.gradle.kts o carpeta android/ dentro de $APP_DIR. (Hoy no hay ninguna; saltar silenciosamente.)
  • Linux (opcional, no por defecto): el build dir cpp/build/ ya genera el binario para Linux. Solo se hace si el usuario lo pide explicitamente.
TARGETS=()
[ -f "$APP_DIR/CMakeLists.txt" ] && TARGETS+=("windows")

if [ -f "$APP_DIR/AndroidManifest.xml" ] || \
   [ -f "$APP_DIR/build.gradle" ] || \
   [ -f "$APP_DIR/build.gradle.kts" ] || \
   [ -d "$APP_DIR/android" ]; then
  TARGETS+=("android")
fi

if [ ${#TARGETS[@]} -eq 0 ]; then
  echo "No se detecta ningun target compilable en $APP_DIR"
  exit 1
fi
echo "Targets: ${TARGETS[*]}"

3. Compilar Windows (cross-compile MinGW)

Solo si windows esta en TARGETS.

BUILD_WIN="$ROOT/cpp/build/windows"

# Configurar build dir si no existe
if [ ! -f "$BUILD_WIN/CMakeCache.txt" ]; then
  mkdir -p "$BUILD_WIN"
  cmake -S "$ROOT/cpp" -B "$BUILD_WIN" \
    -DCMAKE_TOOLCHAIN_FILE="$ROOT/cpp/toolchains/mingw-w64.cmake" \
    -DCMAKE_BUILD_TYPE=Release
fi

# Compilar SOLO el target de la app (no todo el arbol)
cmake --build "$BUILD_WIN" --target "$APP_ARG" -j"$(nproc)"

Si el target no existe en CMake (porque la app no esta registrada en cpp/CMakeLists.txt), reportar y proponer registrarla siguiendo cpp_apps.md §5. NO autoregistrarla sin confirmacion del usuario.

4. Copiar a /mnt/c/Users/lucas/Desktop/apps/<APP>/

Layout estandar (convencion assets/ + local_files/, ver cpp_apps.md §7):

Desktop/apps/<APP>/
├── <APP>.exe                     ← binario (top level por convencion Windows DLL)
├── *.dll                         ← DLLs nativas (Windows las busca junto al exe)
├── assets/                       ← read-only, ships con el zip
│   ├── *.ttf                     ←   fuentes (vienen de add_imgui_app)
│   ├── enrichers/                ←   si <app_dir>/enrichers existe
│   ├── runtime/                  ←   Python embed si app.md tiene python_runtime: true
│   ├── gx-cli, gx-cli.exe        ←   si la app necesita un MCP server
│   └── ...                       ←   cualquier otro asset distribuible
└── local_files/                  ← writable, per-PC, creado por la app al
                                    primer arranque. NUNCA borrar al recompilar.
DEST="/mnt/c/Users/lucas/Desktop/apps/$APP_ARG"
ASSETS="$DEST/assets"
mkdir -p "$DEST" "$ASSETS"

EXE_SRC="$BUILD_WIN/apps/$APP_ARG/$APP_ARG.exe"
if [ ! -f "$EXE_SRC" ]; then
  echo "ERROR: no se ha generado $EXE_SRC"
  exit 1
fi

# 1. Binario + DLLs en el top level (Windows DLL search convention).
cp -v "$EXE_SRC" "$DEST/"
find "$BUILD_WIN/apps/$APP_ARG" -maxdepth 1 -type f -name '*.dll' \
    -exec cp -v {} "$DEST/" \;

# 2. assets/ — TTFs (las copia add_imgui_app a build/<app>/assets/) y
#    cualquier asset extra del build (build/<app>/assets/*).
if [ -d "$BUILD_WIN/apps/$APP_ARG/assets" ]; then
  rsync -a --delete "$BUILD_WIN/apps/$APP_ARG/assets/" "$ASSETS/"
fi

# 3. enrichers/ del app_dir -> assets/enrichers/.
if [ -d "$APP_DIR/enrichers" ]; then
  rsync -a --delete --exclude '__pycache__' --exclude '*.pyc' \
      "$APP_DIR/enrichers/" "$ASSETS/enrichers/"
fi

# 4. runtime/ Python embebido -> assets/runtime/ (si la app lo declara).
if grep -q '^python_runtime:[[:space:]]*true' "$APP_DIR/app.md" 2>/dev/null; then
  if [ ! -d "$APP_DIR/runtime/python" ] || \
     [ "$APP_DIR/app.md" -nt "$APP_DIR/runtime/.lock" ]; then
    echo "[freeze] regenerando runtime Python (Windows) para $APP_ARG"
    "$APP_DIR/tools/freeze_python_runtime.sh" "$APP_DIR" windows
  fi
  rsync -a --delete --exclude '__pycache__' --exclude '*.pyc' \
      "$APP_DIR/runtime/" "$ASSETS/runtime/"
fi

# 5. Otros assets sueltos del app_dir (gx-cli, scripts varios). El
#    convention es: si vive en <app_dir>/ y no es codigo fuente, va a
#    assets/. Ahora mismo la unica excepcion es gx-cli (graph_explorer).
for extra in gx-cli gx-cli.exe; do
  if [ -f "$APP_DIR/$extra" ]; then
    cp -v "$APP_DIR/$extra" "$ASSETS/"
  fi
done

# 6. NO TOCAR local_files/. Si existe en $DEST, preservar — contiene
#    estado del usuario (DBs, settings, layouts ImGui, proyectos).
echo "OK: $APP_ARG -> $DEST"
[ -d "$DEST/local_files" ] && echo "    local_files/ preservado: $(du -sh "$DEST/local_files" | cut -f1)"

5. Compilar Android (solo si TARGETS contiene android)

Hoy no hay apps Android en el registry, asi que esta rama no se ejecuta. Cuando se anada la primera, este es el patron previsto:

if [[ " ${TARGETS[*]} " == *" android "* ]]; then
  ANDROID_DIR="$APP_DIR"
  [ -d "$APP_DIR/android" ] && ANDROID_DIR="$APP_DIR/android"

  cd "$ANDROID_DIR"
  if [ -x "./gradlew" ]; then
    ./gradlew assembleRelease
    APK="$(find "$ANDROID_DIR/app/build/outputs/apk/release" -name '*.apk' | head -n1)"
    [ -n "$APK" ] && cp -v "$APK" "/mnt/c/Users/lucas/Desktop/apps/$APP_ARG/"
  else
    echo "android: no hay ./gradlew en $ANDROID_DIR — saltando."
  fi
fi

Cuando llegue la primera app Android, este bloque puede ampliarse (firma, ABI splits, etc.).

6. Resumen

Imprime al final una linea por target con:

  • Tamano del binario (ls -lh)
  • Path final en /mnt/c/Users/lucas/Desktop/apps/<APP>/
  • Nombre del exe/apk

Notas

  • El build de Windows usa cpp/build/windows/ (no cpp/build/). El de Linux es cpp/build/. Coexisten sin conflicto.
  • El toolchain mingw-w64.cmake ya configura linkado estatico (-static-libgcc -static-libstdc++ -lwinpthread) — el .exe resultante es self-contained y no necesita DLLs en el escritorio.
  • Si se pasa una app que vive en projects/<proj>/apps/<APP>/, el target CMake sigue siendo <APP> (registrado en cpp/CMakeLists.txt con add_subdirectory(${PROJ_DIR}/apps/<APP> ${CMAKE_BINARY_DIR}/apps/<APP>)).
  • NO tocar AdminLocal ni instalar nada en Program Files — solo el escritorio del usuario.