feat(infra): grupo claude-fleet — FleetView TUI + orquestacion de Claudes

Sistema FleetView para centralizar la flota de procesos Claude Code vivos en una
sola ventana kitty + tmux (socket aislado -L fleet) con un panel TUI:

- list_claude_fleet (+ tipo claude_fleet): escanea ~/.claude/sessions + goals +
  runtime, valida procesos vivos (anti-PID-reciclado), join por sessionId.
- list_resumable_claudes (+ tipo resumable_claude): sesiones cerradas reanudables.
- wrappers tmux: tmux_new_claude_window (con --resume), tmux_swap_window_into_console
  (preserva ancho del sidebar), tmux_map_claude_panes.
- launch_kittyclaude: comando entrypoint; instala atajos alt+flechas/enter/n/0/k/r,
  mouse on, remain-on-exit off; fija el ancho del sidebar con hooks.
- docs/capabilities/claude-fleet.md + entrada en el INDEX.

Incluye ademas funciones datascience en progreso (excel/duckdb/postgres) y ajustes
varios de docs e infra de otra sesion, agrupados aqui para no perderlos.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-17 00:04:41 +02:00
parent 7d395f39e5
commit 927437a8d8
58 changed files with 5961 additions and 2 deletions
+113
View File
@@ -0,0 +1,113 @@
"""Ingesta una hoja de un archivo .xlsx a una tabla DuckDB.
Funcion impura: abre el archivo DuckDB destino en modo read-write
(`duckdb.connect(duckdb_path)`, que crea el archivo si no existe), carga la
extension `excel` de DuckDB y materializa la hoja del .xlsx en una tabla con
`read_xlsx`. La conexion se cierra siempre en un bloque try/finally. Devuelve un
dict sin lanzar excepciones, siguiendo el estilo del grupo duckdb del registry:
{status:'ok', ...} en exito y {status:'error', error:str} en fallo.
Camino activo (verificado en DuckDB 1.5.2): extension nativa `excel`. El path del
.xlsx y el nombre de la hoja se pasan como parametros posicionales (marcador `?`)
a `read_xlsx`, por lo que NO se interpolan en el SQL y no hay inyeccion por esa
via. El identificador de tabla destino SI se interpola (CREATE/INSERT no admiten
parametro para el nombre de tabla), asi que se valida contra un regex estricto.
mode='replace' (default) -> `CREATE OR REPLACE TABLE <table> AS SELECT * FROM
read_xlsx(?)`: reemplaza la tabla entera. mode='append' -> crea la tabla si no
existe (`CREATE TABLE IF NOT EXISTS ... AS SELECT ... LIMIT 0` para fijar el
schema) y luego `INSERT INTO <table> SELECT * FROM read_xlsx(?)`.
"""
import re
# Identificador de tabla valido: letras, digitos y guion bajo, sin empezar por
# digito. Rechaza cualquier cosa que pudiera inyectarse en el CREATE/INSERT.
_VALID_IDENT = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
def excel_to_duckdb(
xlsx_path: str,
duckdb_path: str,
table: str,
sheet: str = None,
mode: str = "replace",
) -> dict:
"""Ingesta una hoja de un .xlsx a una tabla DuckDB via la extension excel.
Args:
xlsx_path: ruta al archivo .xlsx de origen. Debe existir y ser legible.
Se pasa como parametro posicional a read_xlsx (no se interpola).
duckdb_path: ruta al archivo DuckDB destino. Se abre en modo escritura, que
crea el archivo si no existe. DuckDB es single-writer: si otro proceso
lo tiene abierto en escritura, falla con error de lock.
table: nombre de la tabla destino. Se valida contra
^[A-Za-z_][A-Za-z0-9_]*$ antes de interpolarlo en el SQL (CREATE/INSERT
no admiten parametro para el nombre de tabla). Identificador invalido
devuelve {status:'error', ...} sin tocar la base.
sheet: nombre de la hoja a leer. None (default) lee la primera hoja del
libro. Se pasa como parametro posicional (sheet=?) a read_xlsx.
mode: 'replace' (default) reemplaza la tabla entera con CREATE OR REPLACE
TABLE AS SELECT. 'append' crea la tabla si no existe y luego inserta
las filas con INSERT INTO ... SELECT. Cualquier otro valor devuelve
{status:'error', ...}.
Returns:
dict. En exito: {status:'ok', table:str, row_count:int} donde row_count es
el numero de filas que tiene la tabla tras la ingesta. En error (sin
lanzar): {status:'error', error:str}.
"""
if not isinstance(table, str) or not _VALID_IDENT.match(table):
return {
"status": "error",
"error": f"invalid table identifier: {table!r}",
}
if mode not in ("replace", "append"):
return {
"status": "error",
"error": f"invalid mode: {mode!r} (expected 'replace' or 'append')",
}
quoted = '"' + table.replace('"', '""') + '"'
# Argumentos de read_xlsx: path siempre, sheet solo si se especifica. Todo
# como parametros posicionales para evitar inyeccion via el .xlsx/hoja.
if sheet is not None:
read_call = "read_xlsx(?, sheet=?)"
read_params = [xlsx_path, sheet]
else:
read_call = "read_xlsx(?)"
read_params = [xlsx_path]
conn = None
try:
conn = __import__("duckdb").connect(duckdb_path)
# La extension excel se instala (red la 1a vez) y carga en la conexion.
conn.execute("INSTALL excel; LOAD excel;")
if mode == "replace":
conn.execute(
f"CREATE OR REPLACE TABLE {quoted} AS SELECT * FROM {read_call}",
read_params,
)
else: # append
# Fijamos el schema de la tabla con un SELECT vacio si no existe, sin
# cargar datos; luego insertamos todas las filas.
conn.execute(
f"CREATE TABLE IF NOT EXISTS {quoted} AS "
f"SELECT * FROM {read_call} LIMIT 0",
read_params,
)
conn.execute(
f"INSERT INTO {quoted} SELECT * FROM {read_call}",
read_params,
)
conn.commit()
row_count = conn.execute(f"SELECT COUNT(*) FROM {quoted}").fetchone()[0]
return {"status": "ok", "table": table, "row_count": int(row_count)}
except Exception as e: # noqa: BLE001
return {"status": "error", "error": str(e)}
finally:
if conn is not None:
conn.close()