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
@@ -0,0 +1,61 @@
"""Devuelve el schema (columnas y tipos) de una tabla DuckDB en modo solo lectura.
Funcion impura: abre un archivo DuckDB con `duckdb.connect(db_path, read_only=True)`,
de modo que nunca crea ni modifica la base. La conexion se cierra siempre en un
bloque try/finally. Ejecuta `DESCRIBE <table>` (con el identificador de tabla
validado y citado, ya que DESCRIBE no admite parametros posicionales) y devuelve
las columnas con su tipo DuckDB. 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.
Complementa a `duckdb_list_tables_py_infra` (que tablas hay) y a
`duckdb_query_readonly_py_infra` (lectura de filas). Es la introspeccion de
columnas del grupo duckdb, util para mapear tipos a otro motor (p.ej. PostgreSQL).
"""
import re
# Un identificador de tabla valido: letras, digitos y guion bajo, sin empezar por
# digito. Suficiente para tablas creadas por el propio ecosistema; rechaza
# cualquier cosa que pudiera inyectarse en el DESCRIBE (que no admite parametros).
_VALID_IDENT = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*$")
def duckdb_table_schema(db_path: str, table: str) -> dict:
"""Devuelve el schema de una tabla DuckDB en modo solo lectura.
Args:
db_path: ruta al archivo DuckDB. Debe existir: el modo read_only NO crea
la base. Un path inexistente devuelve {status:'error', ...}.
table: nombre de la tabla a inspeccionar. Se valida contra
^[A-Za-z_][A-Za-z0-9_]*$ antes de interpolarlo en el DESCRIBE (que no
admite parametros posicionales). Un identificador invalido devuelve
{status:'error', ...} sin tocar la base.
Returns:
dict. En exito: {status:'ok', table:str, columns:[{name:str, type:str},...]}
donde type es el tipo DuckDB tal cual lo reporta el motor (BIGINT, DOUBLE,
VARCHAR, ...). 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}",
}
conn = None
try:
conn = __import__("duckdb").connect(db_path, read_only=True)
# DESCRIBE no admite parametros; el identificador ya esta validado y se
# cita con dobles comillas (escapando comillas internas, imposible aqui
# por el regex pero defensivo).
quoted = '"' + table.replace('"', '""') + '"'
rows = conn.execute(f"DESCRIBE {quoted}").fetchall()
# DESCRIBE devuelve: (column_name, column_type, null, key, default, extra)
columns = [{"name": row[0], "type": row[1]} for row in rows]
return {"status": "ok", "table": table, "columns": columns}
except Exception as e: # noqa: BLE001
return {"status": "error", "error": str(e)}
finally:
if conn is not None:
conn.close()