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>
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 decpp/apps/<X>/oprojects/*/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.txty se registra encpp/CMakeLists.txt(es decir, aparece como subdirectorio encpp/build/windows/apps/<APP>/). Default para apps C++. - Android: si existe
AndroidManifest.xml,build.gradle,build.gradle.ktso carpetaandroid/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/(nocpp/build/). El de Linux escpp/build/. Coexisten sin conflicto. - El toolchain
mingw-w64.cmakeya configura linkado estatico (-static-libgcc -static-libstdc++ -lwinpthread) — el.exeresultante 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 encpp/CMakeLists.txtconadd_subdirectory(${PROJ_DIR}/apps/<APP> ${CMAKE_BINARY_DIR}/apps/<APP>)). - NO tocar
AdminLocalni instalar nada enProgram Files— solo el escritorio del usuario.