Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e49841a60a |
@@ -1,204 +0,0 @@
|
||||
---
|
||||
description: Genera en un vault Obsidian un resumen capítulo a capítulo de uno o varios libros, siguiendo el formato de notas del vault captacion_clientes (MOC de libro + una nota por capítulo + MOC de categoría, todo enlazado con wikilinks).
|
||||
---
|
||||
|
||||
# /capitulos — resumen de libros capítulo a capítulo en Obsidian
|
||||
|
||||
Genera notas de estudio de un libro (o varios) en un vault Obsidian, replicando el formato
|
||||
canónico del vault `captacion_clientes`: una nota MOC por libro, una nota por capítulo, y una
|
||||
nota MOC de categoría que agrupa los libros. Todo enlazado con wikilinks `[[ ]]` para que
|
||||
Obsidian construya el grafo.
|
||||
|
||||
## Argumentos
|
||||
|
||||
`$ARGUMENTS` contiene, en lenguaje natural, los libros a procesar y opcionalmente el destino.
|
||||
Interpreta:
|
||||
|
||||
- **Libros** — uno o varios títulos. Pueden venir con autor ("Forecasting de Hyndman"). Si el
|
||||
usuario dice "los libros que me has dicho" o similar, usa los que se recomendaron en la
|
||||
conversación previa.
|
||||
- **Vault destino** — si no se especifica, **PREGUNTA** antes de escribir (ver Decisiones).
|
||||
Vault por defecto de ejemplo de formato: `/home/enmanuel/Obsidian/captacion_clientes`.
|
||||
- **Categoría** — la subcarpeta bajo `Libros/` que agrupa los libros (ej. "Marca y Mercado",
|
||||
"Datos e Inversión"). Si no se da, propón una coherente con el tema de los libros y confírmala.
|
||||
- **Profundidad** — `completo` (default, como The Mom Test: idea central + puntos clave +
|
||||
citas + aplicación por capítulo) o `breve` (idea central + 3 bullets por capítulo).
|
||||
|
||||
## Decisiones a confirmar antes de escribir (si faltan en los argumentos)
|
||||
|
||||
Usa `AskUserQuestion` para resolver lo que cambie el trabajo, NO inventes:
|
||||
|
||||
1. **Vault y categoría destino** — dónde se crean las notas.
|
||||
2. **Alcance** — qué libros exactamente y cuántos (si la lista es grande, confirma si son
|
||||
todos o un subconjunto; cada libro es trabajo no trivial).
|
||||
3. **Enfoque de "Aplicación"** — el ángulo desde el que se escribe la sección "Aplicación a mi
|
||||
negocio / a mi caso" de cada capítulo (ej. inversión cuantitativa, data-analyst, SaaS…).
|
||||
El vault de captación lo orienta al negocio del usuario; mantén ese espíritu pero ajustado
|
||||
al tema real de los libros.
|
||||
|
||||
## Estructura de archivos a crear
|
||||
|
||||
```
|
||||
<vault>/Libros/<Categoría>/
|
||||
<Categoría> - MOC.md # MOC de categoría (crear o ACTUALIZAR, no sobrescribir)
|
||||
<Libro>/
|
||||
<Libro> - MOC.md # MOC del libro
|
||||
01 - <Título capítulo>.md # una nota por capítulo, NN zero-padded a 2 dígitos
|
||||
02 - <Título capítulo>.md
|
||||
...
|
||||
```
|
||||
|
||||
- Carpeta por libro, archivo por capítulo. Nombre de capítulo: `NN - <Título>.md` con `NN`
|
||||
empezando en `01`. Si el capítulo tiene título original en otro idioma, puedes incluir la
|
||||
traducción entre paréntesis como en el vault (`01 - The Mom Test (El test de la madre).md`).
|
||||
- Nombres de archivo sin caracteres que rompan en Obsidian (evita `/`, `:`; los paréntesis y
|
||||
acentos son válidos).
|
||||
|
||||
## Determinar los capítulos de cada libro
|
||||
|
||||
Para listar los capítulos reales de un libro:
|
||||
|
||||
1. Usa tu conocimiento del libro si lo conoces con fiabilidad (índice real, no inventado).
|
||||
2. Si no estás seguro del índice exacto, **búscalo en la web** (`WebSearch` / `WebFetch` sobre
|
||||
la tabla de contenidos del libro) antes de escribir. No inventes capítulos.
|
||||
3. Indica en el MOC del libro si el índice procede de una edición concreta.
|
||||
|
||||
**Regla dura:** nunca te inventes el número o los títulos de los capítulos. Si no puedes
|
||||
verificarlos, dilo y pregunta al usuario en vez de fabricar un índice plausible.
|
||||
|
||||
## Plantilla — MOC del libro (`<Libro> - MOC.md`)
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: <Libro> - MOC
|
||||
book: <Libro>
|
||||
author: <Autor>
|
||||
year: <Año>
|
||||
type: book-moc
|
||||
tags:
|
||||
- <slug-libro>
|
||||
- <tema-1>
|
||||
- moc
|
||||
---
|
||||
|
||||
# <Libro> — Mapa de contenidos (MOC)
|
||||
|
||||
## Metadata
|
||||
- **Autor:** <Autor>
|
||||
- **Año:** <Año> (<edición si aplica>)
|
||||
- **Subtítulo:** *<subtítulo original>* (<traducción>)
|
||||
- **Tema:** <de qué va en una frase>
|
||||
- **Por qué importa:** <2-3 frases sobre qué problema resuelve y para quién>
|
||||
|
||||
## Resumen global
|
||||
<Un párrafo denso (8-15 líneas) que sintetiza la tesis del libro y recorre el hilo de los
|
||||
capítulos sin enumerarlos uno a uno: cuenta el argumento completo en prosa.>
|
||||
|
||||
## Capítulos
|
||||
1. [[01 - <Título capítulo>]]
|
||||
2. [[02 - <Título capítulo>]]
|
||||
...
|
||||
|
||||
## Aplicación a mi caso (visión transversal)
|
||||
<Párrafo que conecta el libro entero con el objetivo concreto del usuario (el enfoque
|
||||
confirmado en las Decisiones): qué capítulos son los más relevantes y por qué.>
|
||||
```
|
||||
|
||||
## Plantilla — nota de capítulo (`NN - <Título>.md`)
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: <Título capítulo>
|
||||
book: <Libro>
|
||||
author: <Autor>
|
||||
chapter: <N>
|
||||
type: chapter-summary
|
||||
tags:
|
||||
- <slug-libro>
|
||||
- <tema>
|
||||
---
|
||||
|
||||
# NN. <Título capítulo>
|
||||
|
||||
> Libro: [[<Libro> - MOC]]
|
||||
|
||||
## Idea central
|
||||
<1-3 frases con la tesis del capítulo.>
|
||||
|
||||
## Puntos clave
|
||||
- <bullet sustantivo, no genérico>
|
||||
- <…>
|
||||
- <…>
|
||||
|
||||
## Ejemplos / citas
|
||||
- <ejemplo concreto del capítulo o cita textual con su traducción si es en otro idioma>
|
||||
- <…>
|
||||
|
||||
## Aplicación a mi caso
|
||||
<Párrafo concreto: cómo aplicar la idea del capítulo al caso del usuario.>
|
||||
|
||||
---
|
||||
Anterior: [[NN-1 - <Título anterior>]] · Siguiente: [[NN+1 - <Título siguiente>]] · Índice: [[<Libro> - MOC]]
|
||||
```
|
||||
|
||||
Notas de la plantilla:
|
||||
- El primer capítulo: `Anterior: —`. El último: `Siguiente: —`. (Ver patrón en el vault.)
|
||||
- La sección "Aplicación" es obligatoria y debe ser específica del caso del usuario, no un
|
||||
consejo genérico. Es lo que da valor a estas notas frente a un resumen cualquiera.
|
||||
- En profundidad `breve`, omite "Ejemplos / citas" y deja "Puntos clave" en 3 bullets.
|
||||
|
||||
## Plantilla — MOC de categoría (`<Categoría> - MOC.md`)
|
||||
|
||||
Si ya existe, **ACTUALÍZALO** añadiendo los libros nuevos a la sección que corresponda (no lo
|
||||
reescribas perdiendo lo previo). Si no existe, créalo:
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: <Categoría> — MOC
|
||||
type: moc
|
||||
tags:
|
||||
- libros
|
||||
- <tema-categoría>
|
||||
---
|
||||
|
||||
# <Categoría> — Mapa de contenidos
|
||||
|
||||
<Frase que describe el tema común de los libros de esta categoría.>
|
||||
|
||||
Cada libro tiene su propia nota MOC con el índice de capítulos enlazados.
|
||||
|
||||
## <Sub-tema 1>
|
||||
- [[<Libro A> - MOC]] — <Autor>. <una línea de qué aporta>.
|
||||
- [[<Libro B> - MOC]] — <Autor>. <…>.
|
||||
|
||||
## Orden de lectura recomendado
|
||||
1. **<Libro>** — <por qué primero>.
|
||||
2. ...
|
||||
```
|
||||
|
||||
## Flujo de ejecución
|
||||
|
||||
1. Parsear `$ARGUMENTS`: libros, vault, categoría, profundidad, enfoque.
|
||||
2. Resolver decisiones faltantes con `AskUserQuestion`.
|
||||
3. Para cada libro: verificar el índice real de capítulos (conocimiento fiable o WebSearch).
|
||||
4. Crear carpeta del libro. Escribir el MOC del libro y todas las notas de capítulo con
|
||||
wikilinks y navegación correctos.
|
||||
5. Crear o actualizar el MOC de categoría enlazando los libros nuevos.
|
||||
6. **Paralelización:** si son varios libros, cada libro es independiente (carpetas disjuntas).
|
||||
En modo orquestador, lanza un ejecutor por libro (o por lote de libros) escribiendo en
|
||||
carpetas distintas del mismo vault. Cada ejecutor escribe SOLO su carpeta de libro; el MOC
|
||||
de categoría lo actualiza UN único agente al final (o el orquestador) para evitar que dos
|
||||
ejecutores editen el mismo archivo a la vez.
|
||||
7. Reportar: lista de archivos creados (MOC + nº de capítulos por libro) y la ruta del vault
|
||||
para abrirlo en Obsidian.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **El vault es artefacto local** (gitignored en fn_registry, symlink a `~/Obsidian/<vault>`).
|
||||
Escribir notas NO toca el repo `fn_registry`. Si el vault es su propio repo git, NO commitees
|
||||
desde varios ejecutores a la vez (race): deja el commit/sync al usuario o a un único paso final.
|
||||
- **No sobrescribas** un MOC de categoría existente ni notas de capítulo ya escritas a mano sin
|
||||
confirmarlo. Ante colisión de nombre, pregunta.
|
||||
- **Índices inventados = bug.** Verifica los capítulos reales antes de escribir.
|
||||
- **Wikilinks deben resolver:** el texto dentro de `[[ ]]` debe coincidir exactamente con el
|
||||
nombre de archivo (sin extensión). Un typo rompe el enlace en Obsidian.
|
||||
@@ -1,107 +0,0 @@
|
||||
---
|
||||
description: EDA (exploratory data analysis) de una tabla o de una base entera con el grupo `eda` del registry. Perfila, escribe el report (JSON + Markdown + PDF móvil) y monta un analysis Jupyter lanzado en el navegador colaborativo y ejecutado en vivo por Claude.
|
||||
---
|
||||
|
||||
# /eda — Exploratory Data Analysis con el grupo `eda`
|
||||
|
||||
Cuando Enmanuel pide un EDA ("hazme un EDA de X", "analiza esta tabla", "qué hay en estos datos"), **no escribas análisis inline**: usa el grupo de capacidad `eda` del registry, escribe los reports y monta el analysis Jupyter en su navegador colaborativo, ejecutando las celdas tú mismo en vivo. Respeta la memoria `eda-workflow-registry` y la regla `.claude/rules/notebook_collaboration.md`.
|
||||
|
||||
Página madre del grupo: `docs/capabilities/eda.md` (léela primero para cargar el cluster entero).
|
||||
|
||||
## Uso
|
||||
|
||||
```
|
||||
/eda /ruta/datos.duckdb tabla # EDA de una tabla DuckDB
|
||||
/eda /ruta/datos.csv # CSV/Parquet → cargar a DuckDB y perfilar
|
||||
/eda postgresql://user:pass@host:5432/db tabla # EDA de una tabla PostgreSQL (backend="postgres")
|
||||
/eda /ruta/datos.duckdb --all # EDA de TODA la base (todas las tablas + FK + join graph)
|
||||
/eda /ruta/datos.duckdb ventas --series --pdf # con análisis de serie temporal + PDF móvil
|
||||
```
|
||||
|
||||
`$ARGUMENTS` lleva la fuente y, opcionalmente, la tabla y flags. Interpreta:
|
||||
- **Fuente**: ruta a `.duckdb`/`.csv`/`.parquet`, o un DSN PostgreSQL (`postgresql://...` o `postgres://...`).
|
||||
- **Tabla**: nombre de la tabla. Si no se da y la fuente es un único archivo CSV/Parquet, usa su nombre base. Si se pide "toda la base" / `--all`, usa `profile_database`.
|
||||
- **Flags** (actívalos según lo que pida el usuario; pregunta solo si es ambiguo y costoso):
|
||||
- `--models` → `run_models=True` (PCA/KMeans/IsolationForest/normalidad).
|
||||
- `--llm` → `run_llm=True` (1 call LLM sobre el perfil agregado).
|
||||
- `--series` → `run_series=True` (estacionariedad ADF+KPSS, ACF/PACF, STL, retornos por columna numérica).
|
||||
- `--pdf` → `emit_pdf=True` (PDF A5 legacy de `render_eda_pdf`, legible en móvil).
|
||||
- `--legacy-only` → emite SOLO el PDF legacy (sin AutomaticEDA), para casos en que solo se quiera el PDF rápido.
|
||||
- `--lite` / `--bajo-consumo` → `render_automatic_eda(profile_level="lite")`: EDA barato y rápido (CI, vistazo previo, máquina sin GPU/red). Apaga LLM y serie temporal y limita los modelos a **PCA + normalidad** (sin KMeans ni IsolationForest, lo caro en CPU), con `sample` reducido. `--full` → `profile_level="full"` (standard + narrativa LLM). Por defecto `profile_level="standard"` (comportamiento histórico). Un flag explícito (`--llm`, `--models`, ...) prima sobre el preset.
|
||||
|
||||
Por defecto, **un EDA completo emite SIEMPRE el informe AutomaticEDA en sus dos formatos: PDF (A5 móvil) Y PPTX (16:9 para compartir)** con los 11 capítulos poblados (portada, overview, distribuciones, calidad, correlaciones, modelos, series, geoespacial, agregación, interpretación LLM). Usa el pipeline `render_automatic_eda` (o `profile_table(emit_automatic=True)`), que activa `run_models` y `run_series` para que los capítulos de modelos/series/geoespacial/agregación salgan poblados. Deja `run_llm` para cuando el usuario lo pida o interese la interpretación semántica + narrativa por capítulo (es la única parte que gasta tokens del modelo).
|
||||
|
||||
## Reglas duras
|
||||
|
||||
1. **Registry-first**: invoca las funciones del grupo `eda`, no reescribas lógica de perfilado ni de gráficos inline (regla `registry_first.md`).
|
||||
2. **CSV/Parquet/Excel** entran cargándolos antes a DuckDB (`read_csv_auto`/`read_parquet`/`read_xlsx`) — DuckDB es el motor por defecto. No traigas la tabla entera a RAM.
|
||||
3. **Secretos**: si la fuente es un DSN PostgreSQL con credenciales, NO las imprimas en los reports ni en el notebook; resuélvelas vía `resolve_pg_dsn`/`pass` cuando aplique.
|
||||
4. **El report es un artefacto local**: vive en `reports/` (gitignored), no se sube a Gitea ni se versiona. Compartir = pasar la ruta (regla `reports.md`).
|
||||
5. **Entrega las salidas**: el informe **AutomaticEDA PDF + PPTX** (siempre, con `render_automatic_eda` / `emit_automatic=True`) + (opcional) JSON sidecar + Markdown + PDF legacy + **notebook Jupyter colaborativo ejecutado en vivo**. Comparte las rutas de PDF y PPTX.
|
||||
|
||||
## Paso 1 — Perfilar y escribir los reports
|
||||
|
||||
Una tabla (caso normal):
|
||||
|
||||
```bash
|
||||
PYTHONPATH=python/functions python/.venv/bin/python3 - <<'PYEOF'
|
||||
from pipelines.render_automatic_eda import render_automatic_eda
|
||||
# Informe AutomaticEDA COMPLETO one-shot: perfil + ctx (datos crudos) + PDF + PPTX
|
||||
# con los 11 capítulos poblados (clusters pintados, evolución temporal, mapa,
|
||||
# tablas de agregación). run_llm=True añade la narrativa LLM por capítulo.
|
||||
r = render_automatic_eda(
|
||||
"/ruta/datos.duckdb", "ventas",
|
||||
profile_level="standard", # "lite" = bajo consumo CPU/LLM; "full" = + narrativa LLM
|
||||
out_dir="reports",
|
||||
)
|
||||
print("status:", r["status"])
|
||||
print("pdf: ", r["pdf_path"], "(", r["n_pages"], "págs )")
|
||||
print("pptx: ", r["pptx_path"], "(", r["n_slides"], "slides )")
|
||||
print("manifest:", r["manifest_path"])
|
||||
PYEOF
|
||||
```
|
||||
|
||||
Si además quieres el report Markdown + JSON sidecar y/o el PDF legacy junto al
|
||||
AutomaticEDA, usa `profile_table(emit_automatic=True, emit_pdf=True, write_report=True)`:
|
||||
emite todo a la vez (`report_md_path`, `report_json_path`, `pdf_path` legacy,
|
||||
`aeda_pdf_path`, `aeda_pptx_path`, `aeda_manifest_path`).
|
||||
|
||||
Una base entera (todas las tablas + relaciones FK):
|
||||
|
||||
```bash
|
||||
PYTHONPATH=python/functions python/.venv/bin/python3 - <<'PYEOF'
|
||||
from pipelines.profile_database import profile_database
|
||||
r = profile_database("/ruta/datos.duckdb")
|
||||
print(r["db_profile"]["join_graph"]["mermaid"])
|
||||
PYEOF
|
||||
```
|
||||
|
||||
Lee el Markdown resultante y resume a Enmanuel lo esencial: forma, calidad, correlaciones fuertes (ya corregidas por FDR), series no estacionarias, transformaciones sugeridas y avisos exploratorios.
|
||||
|
||||
## Paso 2 — Notebook Jupyter colaborativo, ejecutado en vivo por Claude
|
||||
|
||||
Sigue la memoria `eda-workflow-registry` y la regla `notebook_collaboration.md`:
|
||||
|
||||
1. Genera el notebook con `build_eda_notebook` (mismo perfil de la tabla):
|
||||
|
||||
```bash
|
||||
PYTHONPATH=python/functions python/.venv/bin/python3 - <<'PYEOF'
|
||||
from datascience import build_eda_notebook
|
||||
build_eda_notebook("/ruta/datos.duckdb", "ventas",
|
||||
"analysis/eda_ventas/notebooks/01_eda.ipynb", run_models=True)
|
||||
PYEOF
|
||||
```
|
||||
|
||||
(o crea un analysis dedicado con `fn run init_jupyter_analysis eda_ventas duckdb` y escribe el notebook dentro de `notebooks/`).
|
||||
|
||||
2. Confirma que hay Jupyter colaborativo activo con `jupyter_discover` (o lánzalo con el `run-jupyter-lab.sh` del analysis) y **ábrelo en el navegador colaborativo** para que Enmanuel lo vea en vivo.
|
||||
|
||||
3. **Ejecuta tú las celdas** (no se las dejes para que las corra él): usa las funciones del dominio `notebook` (`jupyter_exec` append+execute / `jupyter_read`) descritas en `notebook_collaboration.md`, o el MCP `jupyter` si está conectado en la sesión del analysis. Ejecuta de arriba a abajo, comenta cada bloque relevante y deja el notebook navegable.
|
||||
|
||||
## Notas
|
||||
|
||||
- El `TableProfile` lleva ahora, además del perfilado base y las correlaciones con FDR: `series` (por columna numérica, con `run_series`), `reexpression` por columna numérica (escalera de Tukey) y `caveats` (siempre, avisos exploratorios). El Markdown y el PDF renderizan estas secciones automáticamente cuando están presentes.
|
||||
- El informe **AutomaticEDA** (`render_automatic_eda` / `emit_automatic=True`) emite el MISMO documento por capítulos a **PDF (A5 móvil)** y **PPTX (16:9)** con garantía de no-corte (texto envuelto, tablas partidas repitiendo cabecera, figuras escaladas) y negrita real (`**texto**`). Escribe `automatic_eda_manifest.json` con la versión de cada capítulo. Los capítulos modelos/series/geoespacial/agregación se pueblan con los datos crudos que `build_eda_render_ctx` muestrea de la base (no se traen tablas enteras a RAM).
|
||||
- El PDF legacy (`emit_pdf`, `render_eda_pdf`) sigue disponible y es independiente del AutomaticEDA (A5 vertical, gráficos Tufte). Se escribe junto al Markdown en `reports/`.
|
||||
- `run_series` ordena por la primera columna datetime si existe; si no, por el orden físico de filas. Necesita ≥8 puntos válidos por columna.
|
||||
- Fuentes: DuckDB (CSV/Parquet/Excel cargados antes) y PostgreSQL (`backend="postgres"`). `profile_database` (multi-tabla + FK) es solo DuckDB por ahora.
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
description: Muestra la flota de Claudes vivos (sessionId + objetivo + estado) y, con argumento, salta con foco a esa conversación dentro de la sesión tmux fleet. `/fleet show` trae la TUI al contexto tmux actual.
|
||||
argument-hint: "[show | texto|sessionId|PID para saltar — vacío = listar la flota]"
|
||||
description: Muestra la flota de Claudes vivos (sessionId + objetivo + estado) y, con argumento, salta con foco a esa conversación dentro de la sesión tmux fleet.
|
||||
argument-hint: "[texto|sessionId|PID para saltar — vacío = listar la flota]"
|
||||
---
|
||||
|
||||
# /fleet — ver y navegar la flota de Claudes
|
||||
@@ -33,32 +33,9 @@ cd "${FN_REGISTRY_ROOT:-$HOME/fn_registry}/apps/fleetview" && go build -o fleetv
|
||||
- la sesión actual / orquestador si la puedes identificar (su `session_id` coincide con el de quien invoca).
|
||||
4. Si la lista está vacía, indícalo y sugiere que el perfil fleet podría no estar activo (revisar `$FLEET_SOCKET` y que la sesión tmux exista).
|
||||
|
||||
### `show` → traer la TUI al contexto tmux actual
|
||||
|
||||
Si `$ARGUMENTS` es exactamente `show` (alias `open`/`attach`), el usuario quiere
|
||||
volver a ver el panel FleetView en el contexto/pane actual sin abrir ninguna
|
||||
ventana ni arrancar una flota nueva. Ejecuta:
|
||||
|
||||
```bash
|
||||
"${FN_REGISTRY_ROOT:-$HOME/fn_registry}/apps/fleetview/fleetview" show
|
||||
```
|
||||
|
||||
Comportamiento (decidido por la app, no abre terminal externa):
|
||||
|
||||
- **dentro de tmux con la flota viva** → `select-window` de la window `console`
|
||||
del socket fleet (trae la TUI al frente; no abre nada).
|
||||
- **fuera de tmux** → `attach` a la sesión fleet en la terminal actual (la reutiliza).
|
||||
- **sin flota viva** → error claro, exit 1, no abre nada (sugiere arrancarla con
|
||||
`fleetclaude`).
|
||||
|
||||
Es el equivalente del comportamiento de `fleetclaude` sin args invocado dentro de
|
||||
una flota viva (reuse de contexto): úsalo cuando ya tengas una flota corriendo y
|
||||
solo quieras recuperar la vista del panel. Para abrir una flota NUEVA aparte, usa
|
||||
`fleetclaude --new` (no este comando).
|
||||
|
||||
### Con argumentos → saltar con foco
|
||||
|
||||
El usuario quiere que la interfaz tmux salte a una conversación concreta. `$ARGUMENTS` es el query: texto del objetivo, prefijo de `sessionId`, o PID (cualquier valor que no sea `show`).
|
||||
El usuario quiere que la interfaz tmux salte a una conversación concreta. `$ARGUMENTS` es el query: texto del objetivo, prefijo de `sessionId`, o PID.
|
||||
|
||||
1. Ejecuta:
|
||||
```bash
|
||||
|
||||
@@ -31,13 +31,12 @@ Diferencia con `dev/flows/`:
|
||||
|
||||
**Fase 1 (manual via Claude):**
|
||||
|
||||
El agente lee `dev/issues/**/*.md` (recursivo: incluye subcarpetas por dominio como `dev/issues/kanban/`, `dev/issues/cpp/`, ... excluyendo `completed/`), parsea frontmatter YAML con `yaml.safe_load`, aplica el filtro, imprime tabla.
|
||||
El agente lee `dev/issues/*.md`, parsea frontmatter YAML con `yaml.safe_load`, aplica el filtro, imprime tabla.
|
||||
|
||||
```python
|
||||
import yaml, pathlib, re
|
||||
issues = []
|
||||
for f in pathlib.Path("dev/issues").glob("**/*.md"):
|
||||
if f.parent.name == "completed": continue
|
||||
for f in pathlib.Path("dev/issues").glob("*.md"):
|
||||
if f.name in {"README.md", "template.md"}: continue
|
||||
txt = f.read_text()
|
||||
m = re.match(r"^---\n(.*?)\n---", txt, re.S)
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
"enabledMcpjsonServers": [
|
||||
"registry",
|
||||
"jupyter",
|
||||
"orchestrator",
|
||||
"godot",
|
||||
"ardour"
|
||||
"orchestrator"
|
||||
],
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
"godot": {
|
||||
"type": "http",
|
||||
"url": "http://127.0.0.1:8000/mcp"
|
||||
},
|
||||
"ardour": {
|
||||
"command": "/home/enmanuel/audio-tools/ardour-mcp/target/release/ardour_mcp_server",
|
||||
"args": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,25 +3,23 @@ name: launch_fleetclaude
|
||||
kind: function
|
||||
lang: bash
|
||||
domain: infra
|
||||
version: "1.7.0"
|
||||
version: "1.5.0"
|
||||
purity: impure
|
||||
signature: "launch_fleetclaude [--cwd <dir>] [--bin <path>] [--session <name>] [--reuse] [--new] [--cols <n>]"
|
||||
description: "Entrypoint de FleetView: abre una ventana de terminal con una sesion tmux (socket aislado por perfil) de dos panes (TUI fleetview a la izquierda, claude --dangerously-skip-permissions a la derecha) para centralizar la flota de Claudes. REUSO DE CONTEXTO: si se invoca DENTRO de una flota tmux viva (su window 'console') sin --new, NO abre ventana ni crea un perfil nuevo; trae la TUI al pane/contexto actual (equivale a 'fleetview show'). El flag --new fuerza una flota+ventana nueva aunque estes en tmux. La terminal se AUTO-DETECTA sin config por PC: kitty si esta instalado y hay display ($DISPLAY/$WAYLAND_DISPLAY), si no Windows Terminal (wt.exe) en WSL adjuntando via wsl.exe. El pane de la TUI corre dentro del bucle supervisor supervise_fleetview_tui, que la relanza si muere (crash/panic/kill), asi el panel de control NUNCA se pierde. Soporta PERFILES multiples: fuera de tmux, o con --new, cada invocacion abre un perfil nuevo (fleet, fleet2, fleet3, ...) con su propia flota; inyecta FLEET_SOCKET/FLEET_SESSION a la TUI para que cada panel vea solo sus Claudes. Instala atajos alt+flechas/alt+enter/alt+n que controlan la TUI desde cualquier pane, y fija el ancho del sidebar con hooks."
|
||||
tags: [claude-fleet, infra, kitty, tmux, claude, fleetview, launcher, wsl, windows-terminal]
|
||||
signature: "launch_fleetclaude [--cwd <dir>] [--bin <path>] [--session <name>] [--reuse] [--cols <n>]"
|
||||
description: "Entrypoint de FleetView: abre una ventana kitty con una sesion tmux (socket aislado por perfil) de dos panes (TUI fleetview a la izquierda, claude --dangerously-skip-permissions a la derecha) para centralizar la flota de Claudes. El pane de la TUI corre dentro del bucle supervisor supervise_fleetview_tui, que la relanza si muere (crash/panic/kill), asi el panel de control NUNCA se pierde. Soporta PERFILES multiples: sin --session/--reuse cada invocacion abre un perfil nuevo (fleet, fleet2, fleet3, ...) con su propia flota; inyecta FLEET_SOCKET/FLEET_SESSION a la TUI para que cada panel vea solo sus Claudes. Instala atajos alt+flechas/alt+enter/alt+n que controlan la TUI desde cualquier pane, y fija el ancho del sidebar con hooks."
|
||||
tags: [claude-fleet, infra, kitty, tmux, claude, fleetview, launcher]
|
||||
params:
|
||||
- name: --cwd
|
||||
desc: "Directorio de trabajo de ambos panes tmux. Opcional. Default: raiz del repo fn_registry, derivada dinamicamente via git rev-parse desde la ubicacion del script (sin hardcodear paths de usuario)."
|
||||
- name: --bin
|
||||
desc: "Ruta al binario de la TUI fleetview que corre en el pane izquierdo. Opcional. Default: <repo>/apps/fleetview/fleetview. Si no es ejecutable, el pane izquierdo muestra un mensaje de como compilarla y deja una shell viva."
|
||||
- name: --session
|
||||
desc: "Fija el perfil (socket+sesion tmux comparten nombre) por nombre exacto; reutiliza el existente si ya vive (idempotente sobre ese nombre). Opcional. Sin esta opcion, el perfil se elige automaticamente (primer nombre libre de la secuencia fleet, fleet2, ...). Invocado DENTRO de tmux con un nombre DISTINTO al de la flota actual equivale a --new (pides otra flota: ventana nueva, sin reuse de contexto)."
|
||||
desc: "Fija el perfil (socket+sesion tmux comparten nombre) por nombre exacto; reutiliza el existente si ya vive (idempotente sobre ese nombre). Opcional. Sin esta opcion, el perfil se elige automaticamente (primer nombre libre de la secuencia fleet, fleet2, ...)."
|
||||
- name: --reuse
|
||||
desc: "Reattach al perfil principal 'fleet' en vez de abrir uno nuevo. Opcional. Recupera el comportamiento idempotente clasico (volver a invocar NO duplica la flota, reusa la existente)."
|
||||
- name: --new
|
||||
desc: "Fuerza una flota NUEVA en una ventana NUEVA (kitty/wt.exe) incluso estando dentro de una flota tmux. Opcional. Es la via explicita para abrir una FleetView aparte; sin este flag, invocado dentro de una flota viva se reusa el contexto actual (no abre ventana ni crea perfil)."
|
||||
- name: --cols
|
||||
desc: "Ancho en columnas del pane izquierdo (la TUI). Opcional. Default: 40."
|
||||
output: "Caso reuse de contexto (dentro de una flota tmux viva, sin --new): trae la TUI al pane/contexto actual con select-window de la window 'console' (o 'fleetview show' si el binario existe) y retorna 0, sin abrir nada. Caso ventana-nueva (fuera de tmux, o con --new): crea/reutiliza una sesion tmux detached con dos panes y lanza una ventana de terminal 'FleetView' adjunta (kitty o Windows Terminal segun auto-deteccion), desacoplada del shell padre. Imprime el estado por stdout. Sin valor de retorno; exit 0 en exito, !=0 con mensaje claro si no hay terminal ni contexto que reusar."
|
||||
output: "Crea/reutiliza una sesion tmux detached con dos panes y lanza una ventana kitty 'FleetView' adjunta a ella, desacoplada del shell padre (setsid). Imprime el estado por stdout. Sin valor de retorno; exit 0 en exito."
|
||||
uses_functions:
|
||||
- supervise_fleetview_tui_bash_infra
|
||||
uses_types: []
|
||||
@@ -38,44 +36,32 @@ file_path: "bash/functions/infra/launch_fleetclaude.sh"
|
||||
## Ejemplo
|
||||
|
||||
```bash
|
||||
# DENTRO de una flota tmux viva (p. ej. en el pane del orquestador): reusa el
|
||||
# contexto, trae la TUI al pane actual. NO abre ventana ni crea perfil nuevo.
|
||||
fleetclaude
|
||||
|
||||
# FUERA de tmux: perfil nuevo automatico (fleet la 1a vez; fleet2, ... si ya hay
|
||||
# uno) en una ventana de terminal nueva, reutilizando la terminal actual (attach):
|
||||
fleetclaude
|
||||
|
||||
# Forzar una flota+ventana NUEVA aunque estes dentro de una flota tmux:
|
||||
fleetclaude --new
|
||||
|
||||
# Reattach a la flota principal 'fleet' (comportamiento idempotente clasico):
|
||||
fleetclaude --reuse
|
||||
|
||||
# Perfil con nombre fijo y ancho de pane personalizado:
|
||||
fleetclaude --session trabajo --cols 50
|
||||
|
||||
# Via fn run (resuelve por nombre o ID):
|
||||
fn run launch_fleetclaude
|
||||
|
||||
# Perfil nuevo automatico (fleet la 1a vez; fleet2, fleet3, ... si ya hay uno):
|
||||
launch_fleetclaude
|
||||
|
||||
# Reattach a la flota principal 'fleet' (comportamiento idempotente clasico):
|
||||
launch_fleetclaude --reuse
|
||||
|
||||
# Perfil con nombre fijo y ancho de pane personalizado:
|
||||
launch_fleetclaude --session trabajo --cols 50
|
||||
```
|
||||
|
||||
Dentro de una flota viva, `fleetclaude` sin args reusa el contexto (la window
|
||||
`console` pasa al frente). Fuera de tmux (o con `--new`) aparece una ventana de
|
||||
terminal titulada `FleetView (<perfil>)` con dos panes lado a lado: a la izquierda
|
||||
la TUI `fleetview`, a la derecha una sesion de `claude --dangerously-skip-permissions`.
|
||||
Cada perfil es un socket+sesion tmux aislados con su propia flota: puedes tener
|
||||
varias FleetView abiertas a la vez con `--new`.
|
||||
Tras invocarlo aparece una ventana kitty titulada `FleetView (<perfil>)` con dos
|
||||
panes lado a lado: a la izquierda la TUI `fleetview`, a la derecha una sesion de
|
||||
`claude --dangerously-skip-permissions`. Cada perfil es un socket+sesion tmux
|
||||
aislados con su propia flota: puedes tener varias FleetView abiertas a la vez.
|
||||
Por defecto, volver a invocarlo abre un perfil NUEVO (no reusa); usa `--reuse`
|
||||
o `--session <nombre>` para volver a una flota concreta.
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Usala cuando quieras un unico punto de entrada a la flota de Claudes en vez de
|
||||
N ventanas kitty sueltas: lanzas `fleetclaude` y tienes la TUI de control y un
|
||||
Claude listo para trabajar en la misma ventana. Tipico al empezar la jornada o
|
||||
al retomar el trabajo en el repo `fn_registry`. Si **ya estas dentro de una
|
||||
flota** (en el pane del orquestador) y solo quieres volver a ver la TUI, lanza
|
||||
`fleetclaude` sin args: trae el panel al contexto actual sin abrir otra ventana
|
||||
ni arrancar una flota duplicada. Usa `--new` solo cuando quieras DELIBERADAMENTE
|
||||
una segunda flota aparte.
|
||||
al retomar el trabajo en el repo `fn_registry`.
|
||||
|
||||
## Gotchas
|
||||
|
||||
@@ -92,41 +78,12 @@ una segunda flota aparte.
|
||||
`respawn-pane` de alt+R y los Claude nuevos hereden el socket). `main.go` los
|
||||
lee con fallback a `fleet`. Por eso cada panel ve SOLO los Claude de su perfil
|
||||
(cruza la lista del sistema con los panes de su socket).
|
||||
- **Auto-deteccion de terminal (sin config por PC)**: en la ruta ventana-nueva el
|
||||
launcher elige terminal solo. (1) `kitty` instalado **y** display usable
|
||||
(`$DISPLAY`/`$WAYLAND_DISPLAY`) → kitty (escritorio Linux nativo o WSLg con
|
||||
kitty). (2) Si no, WSL con `wt.exe` en el PATH → Windows Terminal ejecutando
|
||||
`wsl.exe [-d $WSL_DISTRO_NAME] -- bash -lic 'tmux -L <perfil> attach ...'`.
|
||||
(3) Ninguna → error con las salidas posibles. Asi el MISMO `fleetclaude`
|
||||
funciona en un PC con kitty y en otro WSL sin kitty, cada uno elige su
|
||||
terminal. Causa raiz del sintoma "se lanza la flota pero no se ve": kitty no
|
||||
instalado en WSL hacia que la sesion tmux se creara sin ventana que la mostrara.
|
||||
- **Dentro de una flota tmux viva: reuse de contexto (no ventana nueva)**: si
|
||||
invocas `fleetclaude` sin `--new` desde dentro de una flota fleetview viva
|
||||
(`$TMUX` definido y el socket actual tiene una sesion homonima con window
|
||||
`console`), NO abre ventana ni crea un perfil `fleetN+1`: trae la TUI al pane
|
||||
actual (`fleetview show`, o `tmux -L <perfil> select-window -t <perfil>:console`
|
||||
si el binario no esta compilado) y retorna 0. El perfil de la flota actual se
|
||||
deriva de `$TMUX` (basename del socket = nombre `-L`), senal fiable aunque
|
||||
`$FLEET_SOCKET` venga vacio (ver `detect_fleet_context`). **`--new`** fuerza el
|
||||
comportamiento clasico (flota+ventana nueva); pasar `--session <otro>` distinto
|
||||
al perfil actual equivale a `--new` implicito. Fuera de tmux y con TTY, reutiliza
|
||||
la terminal actual con `exec tmux attach` (nunca `attach` anidado dentro de
|
||||
tmux). Sin TTY ni contexto que reusar (atajo de escritorio/cron) cae a la ruta
|
||||
ventana-nueva. Antes de este fix (v1.6.0 y anteriores) cualquier `fleetclaude`
|
||||
dentro de tmux abria una kitty nueva y un socket `fleetN+1` — el sintoma que
|
||||
acumulaba 6+ sockets `fleet*`.
|
||||
- **`local x` unbound bajo `set -u`**: el archivo corre con `set -euo pipefail`.
|
||||
`local left_pane right_pane` dejaba esas vars *unbound* (no vacias), asi que la
|
||||
rama "reutilizar sesion existente" (`--reuse`/`--session <vivo>`) reventaba con
|
||||
`left_pane: unbound variable` al evaluar `[[ -z "$left_pane" ]]`. Se inicializan
|
||||
explicitamente a `""` (`local left_pane="" right_pane=""`). Si tocas estas vars,
|
||||
no vuelvas a declararlas sin valor.
|
||||
- **kitty detached (setsid)**: la ventana kitty se lanza con `setsid ... &` para
|
||||
sobrevivir al cierre de la terminal que la invoco. La ventana de Windows
|
||||
Terminal (wt.exe) ya es un proceso Windows independiente del arbol Linux, asi
|
||||
que sobrevive sola (se lanza con `&`+`disown` desde un subshell con cwd `/mnt/c`
|
||||
para evitar el warning de wt.exe por cwd UNC `\\wsl.localhost\...`).
|
||||
- **Dentro de tmux abre ventana nueva**: si invocas `fleetclaude` desde dentro de
|
||||
una sesion tmux (`$TMUX` definido), NO hace `attach` anidado (rompe / avisa de
|
||||
nesting); cae a la ruta kitty y abre una ventana nueva. Fuera de tmux y con
|
||||
TTY, reutiliza la terminal actual con `exec tmux attach`.
|
||||
- **kitty detached (setsid)**: la ventana se lanza con `setsid ... &` para
|
||||
sobrevivir al cierre de la terminal que la invoco. No bloquea al shell padre.
|
||||
- **TUI bajo supervisor (auto-respawn)**: el pane izquierdo NO corre un
|
||||
`exec fleetview` de una sola vida, sino `supervise_fleetview_tui` (bucle que
|
||||
relanza la TUI si muere por crash/panic/kill). Asi el panel de control nunca se
|
||||
@@ -159,37 +116,14 @@ una segunda flota aparte.
|
||||
- **Ancho del sidebar via hooks**: `client-resized` y `window-layout-changed`
|
||||
re-fijan el pane 0 (TUI) a `--cols` columnas, porque el `attach` de kitty y el
|
||||
conmutar de Claude redistribuyen el espacio.
|
||||
- **tmux siempre; terminal (kitty/wt.exe) solo en la ruta ventana-nueva**: `tmux`
|
||||
es obligatorio (aborta != 0 si falta). Una terminal nueva (kitty o Windows
|
||||
Terminal) solo se necesita en la ruta ventana-nueva: `--new`, o sin TTY ni flota
|
||||
viva que reusar (atajo de escritorio, cron, script). Dentro de una flota viva sin
|
||||
`--new` se reusa el contexto (ni kitty ni wt.exe). Invocado desde una terminal
|
||||
interactiva fuera de tmux (el caso normal del alias `fleetclaude`), reutiliza la
|
||||
terminal actual con `exec tmux attach` y tampoco necesita kitty ni wt.exe.
|
||||
- **tmux siempre, kitty solo sin TTY**: `tmux` es obligatorio (aborta != 0 si
|
||||
falta). `kitty` solo se necesita en la ruta sin-TTY (atajo de escritorio, cron,
|
||||
script), donde abre una ventana nueva. Invocado desde una terminal interactiva
|
||||
(el caso normal del alias `fleetclaude`), reutiliza la terminal actual con
|
||||
`exec tmux attach` y NO necesita kitty — util en WSL u hosts sin kitty.
|
||||
|
||||
## Capability growth log
|
||||
|
||||
- v1.7.0 (2026-06-30) — **reuse de contexto dentro de la flota + flag `--new`**.
|
||||
Invocado sin `--new` desde dentro de una flota tmux viva (su window `console`),
|
||||
`fleetclaude` ya NO abre una kitty nueva ni crea un perfil `fleetN+1`: trae la
|
||||
TUI al pane/contexto actual (`fleetview show`, o `tmux -L <perfil> select-window
|
||||
-t <perfil>:console` como fallback sin binario) y retorna 0. El perfil actual se
|
||||
deriva de `$TMUX` (basename del socket); pasar `--session <otro>` distinto al
|
||||
actual equivale a `--new` implicito. Nuevo flag `--new` para forzar la ruta
|
||||
clasica (flota+ventana nueva) aun dentro de tmux. Fuera de tmux el comportamiento
|
||||
es intacto (`exec tmux attach` reutiliza la terminal). Arregla el sintoma de que
|
||||
lanzar `fleetclaude` dentro de una flota abria ventana kitty + socket nuevo
|
||||
(`fleet7`, `fleet8`, ...). Fix incidental: `local left_pane="" right_pane=""`
|
||||
(antes `local left_pane right_pane` reventaba con `unbound variable` bajo
|
||||
`set -u` al reutilizar una sesion existente).
|
||||
- v1.6.0 (2026-06-29) — **auto-deteccion de terminal (kitty ↔ Windows Terminal)**.
|
||||
La ruta ventana-nueva ya no asume kitty: elige terminal segun el host. kitty si
|
||||
esta instalado y hay display (`$DISPLAY`/`$WAYLAND_DISPLAY`); si no, en WSL abre
|
||||
Windows Terminal (`wt.exe`) ejecutando `wsl.exe [-d $WSL_DISTRO_NAME] -- bash
|
||||
-lic 'tmux ... attach'`. Mismo `fleetclaude` en un PC con kitty y en otro WSL
|
||||
sin kitty. Arregla el sintoma "se lanza la flota pero no se ve": en WSL sin
|
||||
kitty la sesion tmux se creaba pero ninguna ventana la mostraba. wt.exe se
|
||||
lanza desde un subshell con cwd `/mnt/c` para evitar el warning por cwd UNC.
|
||||
- v1.5.0 (2026-06-24) — **auto-respawn de la TUI**. El pane izquierdo ya no corre
|
||||
`exec fleetview` (una sola vida), sino el bucle supervisor
|
||||
`supervise_fleetview_tui`, que relanza la TUI si muere (crash/panic/kill de su
|
||||
|
||||
@@ -23,7 +23,6 @@ launch_fleetclaude() {
|
||||
local cols=52
|
||||
local explicit_session=0 # 1 si el usuario pasó --session <name> a mano
|
||||
local reuse=0 # 1 si el usuario pidió --reuse (reattach al perfil principal)
|
||||
local want_new=0 # 1 si el usuario pidió --new (forzar flota+ventana nueva)
|
||||
local T="" # socket tmux aislado; se fija al resolver el perfil
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
@@ -47,9 +46,6 @@ launch_fleetclaude() {
|
||||
--reuse)
|
||||
reuse=1
|
||||
;;
|
||||
--new)
|
||||
want_new=1
|
||||
;;
|
||||
--cols)
|
||||
shift
|
||||
cols="${1:-40}"
|
||||
@@ -66,11 +62,6 @@ Claudes). Sin --session ni --reuse, cada invocacion abre un perfil NUEVO: usa
|
||||
el primer nombre libre de la secuencia fleet, fleet2, fleet3, ... Asi puedes
|
||||
tener varias FleetView abiertas a la vez, cada una con su flota independiente.
|
||||
|
||||
REUSO DE CONTEXTO: si ya estas DENTRO de una flota tmux viva (p. ej. en el pane
|
||||
del orquestador), 'fleetclaude' sin args NO abre una ventana ni crea un perfil
|
||||
nuevo: trae la TUI al contexto/pane actual (equivale a 'fleetview show'). Para
|
||||
abrir explicitamente una flota aparte en una ventana nueva, usa --new.
|
||||
|
||||
Opciones:
|
||||
--cwd <dir> Directorio de trabajo de los panes.
|
||||
Default: raiz del repo fn_registry (derivada dinamicamente).
|
||||
@@ -78,21 +69,13 @@ Opciones:
|
||||
Default: <repo>/apps/fleetview/fleetview
|
||||
--session <name> Fija el perfil (socket+sesion) por nombre exacto; reutiliza
|
||||
el existente si ya esta vivo. Sin esta opcion, perfil auto.
|
||||
Si se invoca DENTRO de tmux con un nombre DISTINTO al de la
|
||||
flota actual, equivale a --new (pides otra flota).
|
||||
--reuse Reattach al perfil principal 'fleet' en vez de abrir uno
|
||||
nuevo (vuelve al comportamiento idempotente clasico).
|
||||
--new Fuerza una flota NUEVA en una ventana NUEVA (kitty/wt.exe),
|
||||
incluso dentro de tmux. Es la via explicita para tener una
|
||||
FleetView aparte; sin este flag, dentro de tmux se reusa el
|
||||
contexto actual.
|
||||
--cols <n> Ancho (columnas) del pane izquierdo. Default: 40.
|
||||
-h, --help Muestra esta ayuda.
|
||||
|
||||
Ejemplos:
|
||||
launch_fleetclaude # dentro de la flota: reusa el contexto;
|
||||
# fuera de tmux: perfil nuevo (fleet, ...)
|
||||
launch_fleetclaude --new # flota+ventana nueva aunque estes en tmux
|
||||
launch_fleetclaude # perfil nuevo (fleet, luego fleet2, ...)
|
||||
launch_fleetclaude --reuse # reattach a la flota principal 'fleet'
|
||||
launch_fleetclaude --session trabajo # perfil con nombre fijo 'trabajo'
|
||||
launch_fleetclaude --cwd ~/fn_registry --cols 50
|
||||
@@ -144,45 +127,6 @@ USAGE
|
||||
return 1
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# REUSO DE CONTEXTO (sin --new): si ya estamos DENTRO de una flota tmux
|
||||
# viva, 'fleetclaude' sin args NO abre una ventana/terminal nueva ni crea
|
||||
# un perfil fleetN+1 — trae la TUI al contexto/pane actual, igual que
|
||||
# 'fleetview show'. El flag --new fuerza el comportamiento clasico (flota
|
||||
# nueva en ventana nueva); --reuse mantiene su semantica historica.
|
||||
#
|
||||
# El perfil de la flota actual se deriva de $TMUX (el basename del socket
|
||||
# es el nombre -L; senal fiable aunque $FLEET_SOCKET venga vacio, ver
|
||||
# detect_fleet_context). Si se paso --session con un nombre DISTINTO al
|
||||
# actual, es pedir OTRA flota -> se trata como --new implicito (no reusa).
|
||||
# "Flota viva" = el socket tiene una sesion homonima con una window
|
||||
# 'console' (la firma de una FleetView), no un tmux cualquiera.
|
||||
# -----------------------------------------------------------------------
|
||||
if [[ "$want_new" -eq 0 && "$reuse" -eq 0 && -n "${TMUX:-}" ]]; then
|
||||
local current_socket target_socket
|
||||
current_socket="$(basename "${TMUX%%,*}")"
|
||||
target_socket="$current_socket"
|
||||
[[ "$explicit_session" -eq 1 ]] && target_socket="$session"
|
||||
|
||||
if [[ "$target_socket" == "$current_socket" ]] \
|
||||
&& tmux -L "$current_socket" has-session -t "$current_socket" 2>/dev/null \
|
||||
&& tmux -L "$current_socket" list-windows -t "$current_socket" \
|
||||
-F '#{window_name}' 2>/dev/null | grep -qx console; then
|
||||
# Traer la TUI al contexto actual sin abrir nada nuevo. Preferimos
|
||||
# el binario (centraliza la politica en la app: 'fleetview show');
|
||||
# si no esta compilado, caemos a 'select-window' directo, que es lo
|
||||
# que 'show' hace por dentro dentro de tmux (cero dependencia).
|
||||
if [[ -x "$bin" ]] \
|
||||
&& FLEET_SOCKET="$current_socket" FLEET_SESSION="$current_socket" \
|
||||
"$bin" show 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
tmux -L "$current_socket" select-window -t "$current_socket":console
|
||||
echo "launch_fleetclaude: flota '$current_socket' viva; TUI traida al contexto actual (sin ventana nueva)."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Resolver el PERFIL (socket+sesion tmux comparten nombre).
|
||||
#
|
||||
@@ -256,10 +200,7 @@ USAGE
|
||||
# indice 1 y cualquier referencia a console.0 falla con
|
||||
# "can't find pane: 0". Los pane ID son estables e inmunes al base-index.
|
||||
# -----------------------------------------------------------------------
|
||||
# Inicializadas a "" (no solo declaradas): bajo `set -u` una `local x` sin
|
||||
# valor queda *unbound*, y al reutilizar una sesion existente el `[[ -z
|
||||
# "$left_pane" ]]` de mas abajo reventaba con "unbound variable".
|
||||
local left_pane="" right_pane=""
|
||||
local left_pane right_pane
|
||||
if $T has-session -t "$session" 2>/dev/null; then
|
||||
echo "launch_fleetclaude: la sesion tmux '$session' ya existe; reutilizandola."
|
||||
else
|
||||
@@ -353,61 +294,31 @@ USAGE
|
||||
$T set-hook -g window-layout-changed "resize-pane -t $left_pane -x $cols"
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Adjuntar la sesion en una terminal, DESACOPLADA del shell padre para que
|
||||
# no muera al cerrar la terminal invocadora.
|
||||
# Lanzar kitty adjuntando la sesion, DESACOPLADA del shell padre con
|
||||
# setsid, para que no muera al cerrar la terminal invocadora.
|
||||
# (Mismo patron que reboot_all_claudes para relanzar terminales.)
|
||||
# -----------------------------------------------------------------------
|
||||
# Adjuntar la sesion:
|
||||
# - Terminal interactiva y FUERA de tmux: convertir ESA terminal en el
|
||||
# panel FleetView (exec reemplaza el proceso; al hacer detach vuelve la
|
||||
# shell). Asi `fleetclaude` no abre otra ventana: usa la actual.
|
||||
# - DENTRO de tmux (o sin TTY: atajo de escritorio, cron, script): abrir
|
||||
# una ventana de terminal NUEVA desacoplada. No hacemos `attach`
|
||||
# una ventana kitty nueva desacoplada (setsid). No hacemos `attach`
|
||||
# anidado dentro de otra sesion tmux (rompe / da el warning de nesting).
|
||||
if [ -t 0 ] && [ -t 1 ] && [ -z "${TMUX:-}" ]; then
|
||||
exec tmux -L "$session" attach -t "$session"
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Ruta ventana-nueva: AUTO-DETECTAR la terminal disponible (sin config por
|
||||
# PC). El mismo `fleetclaude` funciona en un escritorio Linux con kitty y en
|
||||
# un WSL sin kitty pero con Windows Terminal.
|
||||
# 1. kitty instalado + display usable ($DISPLAY/$WAYLAND_DISPLAY) -> kitty
|
||||
# (escritorio Linux nativo, o WSLg con kitty instalado).
|
||||
# 2. WSL con wt.exe alcanzable -> Windows Terminal ejecutando wsl.exe que
|
||||
# adjunta la sesion tmux (PCs WSL sin kitty: la ventana kitty nunca
|
||||
# aparece sin una terminal Linux real, por eso "se lanza pero no se ve").
|
||||
# 3. Ninguna -> error claro con las dos salidas posibles.
|
||||
# -----------------------------------------------------------------------
|
||||
if command -v kitty >/dev/null 2>&1 && [[ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]]; then
|
||||
setsid kitty --title "FleetView ($session)" -e tmux -L "$session" attach -t "$session" </dev/null >/dev/null 2>&1 &
|
||||
disown 2>/dev/null || true
|
||||
echo "launch_fleetclaude: ventana kitty 'FleetView ($session)' adjunta al perfil '$session'."
|
||||
return 0
|
||||
# Ruta ventana-nueva: necesitamos kitty para abrirla.
|
||||
if ! command -v kitty >/dev/null 2>&1; then
|
||||
echo "launch_fleetclaude: kitty no esta instalado (necesario para abrir ventana nueva)." >&2
|
||||
echo "launch_fleetclaude: lanzalo desde una terminal interactiva fuera de tmux, o instala kitty." >&2
|
||||
return 1
|
||||
fi
|
||||
setsid kitty --title "FleetView ($session)" -e tmux -L "$session" attach -t "$session" </dev/null >/dev/null 2>&1 &
|
||||
disown 2>/dev/null || true
|
||||
|
||||
if command -v wt.exe >/dev/null 2>&1; then
|
||||
# bash -lic <attach> dentro de wsl.exe: login+interactive para que tmux y
|
||||
# el PATH del perfil esten disponibles en la ventana de Windows Terminal.
|
||||
local attach_cmd
|
||||
attach_cmd="tmux -L $(printf '%q' "$session") attach -t $(printf '%q' "$session")"
|
||||
local distro="${WSL_DISTRO_NAME:-}"
|
||||
local wsl_args=(wsl.exe)
|
||||
[[ -n "$distro" ]] && wsl_args+=(-d "$distro")
|
||||
wsl_args+=(-- bash -lic "$attach_cmd")
|
||||
# cd a una ruta Windows (/mnt/c) evita el warning de wt.exe por cwd UNC
|
||||
# (\\wsl.localhost\...). El cwd real de los panes lo fija la sesion tmux.
|
||||
( cd /mnt/c 2>/dev/null || cd /
|
||||
wt.exe new-tab --title "FleetView ($session)" "${wsl_args[@]}" </dev/null >/dev/null 2>&1 &
|
||||
disown 2>/dev/null || true )
|
||||
echo "launch_fleetclaude: Windows Terminal 'FleetView ($session)' adjunta al perfil '$session' (WSL distro '${distro:-default}')."
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "launch_fleetclaude: no hay terminal para abrir una ventana nueva." >&2
|
||||
echo "launch_fleetclaude: - escritorio Linux: instala kitty y exporta DISPLAY/WAYLAND_DISPLAY." >&2
|
||||
echo "launch_fleetclaude: - WSL: usa Windows Terminal (wt.exe debe estar en el PATH)." >&2
|
||||
echo "launch_fleetclaude: - o lanza fleetclaude desde una terminal interactiva fuera de tmux." >&2
|
||||
return 1
|
||||
echo "launch_fleetclaude: ventana kitty 'FleetView ($session)' adjunta al perfil '$session'."
|
||||
return 0
|
||||
}
|
||||
|
||||
# Permitir ejecutar el archivo directamente (no solo como funcion sourced).
|
||||
|
||||
+34
-50
@@ -18,7 +18,6 @@ type pyParam struct {
|
||||
Default string // empty if required
|
||||
IsKwargs bool // **kwargs
|
||||
IsRegistry bool // type is a registry type (needs factory)
|
||||
KwOnly bool // declared after a bare "*" or "*args" — must be passed by keyword
|
||||
}
|
||||
|
||||
// pyFactory links a registry type to the function that creates it.
|
||||
@@ -46,21 +45,12 @@ func parsePySignature(sig string) []pyParam {
|
||||
// Split by comma, respecting nested brackets
|
||||
parts := splitParams(raw)
|
||||
var params []pyParam
|
||||
kwOnly := false
|
||||
for _, part := range parts {
|
||||
part = strings.TrimSpace(part)
|
||||
if part == "" || part == "self" || part == "cls" {
|
||||
continue
|
||||
}
|
||||
// A bare "*" (PEP 3102) or "*args" var-positional marks the start of
|
||||
// keyword-only params. Neither maps cleanly to positional CLI args, so
|
||||
// skip the marker itself and flag every following param as keyword-only.
|
||||
if part == "*" || (strings.HasPrefix(part, "*") && !strings.HasPrefix(part, "**")) {
|
||||
kwOnly = true
|
||||
continue
|
||||
}
|
||||
p := parseSingleParam(part)
|
||||
p.KwOnly = kwOnly
|
||||
params = append(params, p)
|
||||
}
|
||||
return params
|
||||
@@ -199,19 +189,11 @@ func generatePyRunner(fn *registry.Function, db *registry.DB, registryRoot strin
|
||||
// Classify params
|
||||
var factoryImports []string // import lines for factories
|
||||
var factorySetup []string // code to create factory objects
|
||||
var bodyLines []string // code that fills _call_args / _call_kwargs
|
||||
var argLines []string // code to parse CLI args
|
||||
var callArgs []string // arguments to pass to the function
|
||||
|
||||
cliArgIdx := 0
|
||||
|
||||
// emitCall appends one param to _call_args (positional) or _call_kwargs
|
||||
// (keyword-only). indent prefixes the line (for params read inside an `if`).
|
||||
emitCall := func(p pyParam, indent string) string {
|
||||
if p.KwOnly {
|
||||
return fmt.Sprintf("%s_call_kwargs[%q] = %s", indent, p.Name, p.Name)
|
||||
}
|
||||
return fmt.Sprintf("%s_call_args.append(%s)", indent, p.Name)
|
||||
}
|
||||
|
||||
for _, p := range params {
|
||||
if p.IsKwargs {
|
||||
// Skip **kwargs for now — can't auto-resolve from CLI
|
||||
@@ -253,35 +235,27 @@ func generatePyRunner(fn *registry.Function, db *registry.DB, registryRoot strin
|
||||
fmt.Sprintf("%s = %s(%s)", p.Name, factory.FuncName,
|
||||
strings.Join(factoryArgs, ", ")))
|
||||
|
||||
// Factory objects are always present (required).
|
||||
bodyLines = append(bodyLines, emitCall(p, ""))
|
||||
callArgs = append(callArgs, p.Name)
|
||||
} else {
|
||||
// Primitive type — from CLI args.
|
||||
// Primitive type — from CLI args
|
||||
if p.Default != "" {
|
||||
// Optional: only pass when the CLI arg is present. When absent we
|
||||
// DON'T replicate the signature default (it may reference a module
|
||||
// constant that doesn't exist in this runner) — we simply omit the
|
||||
// argument so the function applies its own native default.
|
||||
bodyLines = append(bodyLines,
|
||||
fmt.Sprintf("if len(_args) > %d:", cliArgIdx))
|
||||
bodyLines = append(bodyLines,
|
||||
fmt.Sprintf(" %s = _args[%d]", p.Name, cliArgIdx))
|
||||
if conv := convertArg(p.Name, p.Type, true); conv != "" {
|
||||
bodyLines = append(bodyLines, " "+conv)
|
||||
}
|
||||
bodyLines = append(bodyLines, emitCall(p, " "))
|
||||
// Optional param with default
|
||||
argLines = append(argLines,
|
||||
fmt.Sprintf("%s = _args[%d] if len(_args) > %d else %s",
|
||||
p.Name, cliArgIdx, cliArgIdx, convertDefault(p.Type, p.Default)))
|
||||
argLines = append(argLines,
|
||||
convertArg(p.Name, p.Type, true))
|
||||
} else {
|
||||
// Required param.
|
||||
bodyLines = append(bodyLines,
|
||||
// Required param
|
||||
argLines = append(argLines,
|
||||
fmt.Sprintf("if len(_args) <= %d: sys.exit('error: missing required arg: %s (%s)')",
|
||||
cliArgIdx, p.Name, p.Type))
|
||||
bodyLines = append(bodyLines,
|
||||
argLines = append(argLines,
|
||||
fmt.Sprintf("%s = _args[%d]", p.Name, cliArgIdx))
|
||||
if conv := convertArg(p.Name, p.Type, false); conv != "" {
|
||||
bodyLines = append(bodyLines, conv)
|
||||
}
|
||||
bodyLines = append(bodyLines, emitCall(p, ""))
|
||||
argLines = append(argLines,
|
||||
convertArg(p.Name, p.Type, false))
|
||||
}
|
||||
callArgs = append(callArgs, p.Name)
|
||||
cliArgIdx++
|
||||
}
|
||||
}
|
||||
@@ -315,18 +289,18 @@ func generatePyRunner(fn *registry.Function, db *registry.DB, registryRoot strin
|
||||
sb.WriteString("\n")
|
||||
}
|
||||
|
||||
// Arg parsing — build the positional/keyword argument collections.
|
||||
sb.WriteString("# --- parse CLI args ---\n")
|
||||
sb.WriteString("_call_args = []\n")
|
||||
sb.WriteString("_call_kwargs = {}\n")
|
||||
for _, line := range bodyLines {
|
||||
sb.WriteString(line + "\n")
|
||||
// Arg parsing
|
||||
if len(argLines) > 0 {
|
||||
sb.WriteString("# --- parse CLI args ---\n")
|
||||
for _, line := range argLines {
|
||||
sb.WriteString(line + "\n")
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
|
||||
// Call
|
||||
sb.WriteString("# --- execute ---\n")
|
||||
sb.WriteString(fmt.Sprintf("_result = %s(*_call_args, **_call_kwargs)\n", fn.Name))
|
||||
sb.WriteString(fmt.Sprintf("_result = %s(%s)\n", fn.Name, strings.Join(callArgs, ", ")))
|
||||
sb.WriteString("\n")
|
||||
|
||||
// Output
|
||||
@@ -391,6 +365,16 @@ func convertArg(name, typ string, _ bool) string {
|
||||
}
|
||||
}
|
||||
|
||||
// convertDefault ensures the default value is valid Python for the given type.
|
||||
func convertDefault(_, def string) string {
|
||||
// Most defaults from the signature are already valid Python
|
||||
// Just handle the None case for Optional types
|
||||
if def == "None" || def == "" {
|
||||
return "None"
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// pythonList creates a Python list literal from strings: ["a", "b", "c"]
|
||||
func pythonList(items []string) string {
|
||||
quoted := make([]string, len(items))
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"fn-registry/registry"
|
||||
)
|
||||
|
||||
// Signature with a bare "*" (PEP 3102) separating positional from keyword-only
|
||||
// params. This is the shape that used to make fn run emit "* = _args[3]".
|
||||
const kwOnlySig = "def add_event_dav(summary: str, start: str, end: str = '', *, location: str = '', all_day: bool = False) -> dict"
|
||||
|
||||
func TestParsePySignatureBareStarKeywordOnly(t *testing.T) {
|
||||
params := parsePySignature(kwOnlySig)
|
||||
|
||||
// The bare "*" marker must never surface as a real parameter.
|
||||
for _, p := range params {
|
||||
if p.Name == "*" {
|
||||
t.Fatalf("bare '*' leaked as a param: %+v", params)
|
||||
}
|
||||
}
|
||||
|
||||
want := map[string]bool{ // name -> expected KwOnly
|
||||
"summary": false,
|
||||
"start": false,
|
||||
"end": false,
|
||||
"location": true,
|
||||
"all_day": true,
|
||||
}
|
||||
if len(params) != len(want) {
|
||||
t.Fatalf("got %d params, want %d: %+v", len(params), len(want), params)
|
||||
}
|
||||
for _, p := range params {
|
||||
kw, ok := want[p.Name]
|
||||
if !ok {
|
||||
t.Errorf("unexpected param %q", p.Name)
|
||||
continue
|
||||
}
|
||||
if p.KwOnly != kw {
|
||||
t.Errorf("param %q KwOnly=%v, want %v", p.Name, p.KwOnly, kw)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeneratePyRunnerKeywordOnlyValid(t *testing.T) {
|
||||
fn := ®istry.Function{
|
||||
Name: "add_event_dav",
|
||||
Lang: "py",
|
||||
FilePath: "python/functions/pipelines/add_event_dav.py",
|
||||
Signature: kwOnlySig,
|
||||
}
|
||||
|
||||
// All params are primitive, so no factory lookup happens and db is unused.
|
||||
script, err := generatePyRunner(fn, nil, "")
|
||||
if err != nil {
|
||||
t.Fatalf("generatePyRunner: %v", err)
|
||||
}
|
||||
|
||||
if strings.Contains(script, "* = _args") {
|
||||
t.Fatalf("runner emitted invalid syntax '* = _args':\n%s", script)
|
||||
}
|
||||
|
||||
// The signature default DEFAULT_BASE_URL (a module constant) must NOT be
|
||||
// replicated into the runner — that NameErrors at runtime.
|
||||
if strings.Contains(script, "DEFAULT_BASE_URL") {
|
||||
t.Errorf("runner replicated non-literal default DEFAULT_BASE_URL:\n%s", script)
|
||||
}
|
||||
|
||||
// Required positionals are appended; keyword-only optionals go to kwargs.
|
||||
for _, want := range []string{
|
||||
"_call_args.append(summary)",
|
||||
"_call_args.append(start)",
|
||||
`_call_kwargs["location"] = location`,
|
||||
`_call_kwargs["all_day"] = all_day`,
|
||||
"_result = add_event_dav(*_call_args, **_call_kwargs)",
|
||||
} {
|
||||
if !strings.Contains(script, want) {
|
||||
t.Errorf("missing %q in generated runner:\n%s", want, script)
|
||||
}
|
||||
}
|
||||
|
||||
// The generated runner must itself be valid Python (compile, don't run).
|
||||
mustCompilePython(t, script)
|
||||
}
|
||||
|
||||
// mustCompilePython checks the script parses as valid Python via py_compile.
|
||||
func mustCompilePython(t *testing.T, script string) {
|
||||
t.Helper()
|
||||
f, err := os.CreateTemp(t.TempDir(), "runner_*.py")
|
||||
if err != nil {
|
||||
t.Fatalf("temp file: %v", err)
|
||||
}
|
||||
if _, err := f.WriteString(script); err != nil {
|
||||
t.Fatalf("write: %v", err)
|
||||
}
|
||||
f.Close()
|
||||
py := pythonBinForTest()
|
||||
out, err := exec.Command(py, "-m", "py_compile", f.Name()).CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("generated runner is not valid Python (%s): %v\n%s", py, err, out)
|
||||
}
|
||||
}
|
||||
|
||||
// pythonBinForTest prefers the project venv, falling back to python3 on PATH.
|
||||
func pythonBinForTest() string {
|
||||
for _, c := range []string{"../../python/.venv/bin/python3", "python3"} {
|
||||
if c == "python3" {
|
||||
return c
|
||||
}
|
||||
if _, err := os.Stat(c); err == nil {
|
||||
return c
|
||||
}
|
||||
}
|
||||
return "python3"
|
||||
}
|
||||
|
||||
// A "*args" var-positional marker must behave like the bare "*": skipped, and
|
||||
// everything after it treated as keyword-only.
|
||||
func TestParsePySignatureVarargsKeywordOnly(t *testing.T) {
|
||||
sig := "def f(a: str, *args, b: int = 0) -> dict"
|
||||
params := parsePySignature(sig)
|
||||
|
||||
for _, p := range params {
|
||||
if strings.HasPrefix(p.Name, "*") {
|
||||
t.Fatalf("'*args' marker leaked as a param: %+v", params)
|
||||
}
|
||||
}
|
||||
if len(params) != 2 {
|
||||
t.Fatalf("got %d params, want 2: %+v", len(params), params)
|
||||
}
|
||||
got := map[string]bool{}
|
||||
for _, p := range params {
|
||||
got[p.Name] = p.KwOnly
|
||||
}
|
||||
if got["a"] != false || got["b"] != true {
|
||||
t.Errorf("KwOnly mismatch: a=%v (want false), b=%v (want true)", got["a"], got["b"])
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
# 0033 — C++ http_inspector + websocket_client
|
||||
|
||||
@@ -11,7 +11,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
# 0051 — Funciones pendientes del pipeline de extraccion (NER+RE+OpenIE)
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
# 0054 — deploy_server: refactor registry-first (SSH/systemd/rsync/health/docker-compose)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
# 0055 — docker_tui: refactor para usar funciones docker_* del registry
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
# 0056 — audit_uses_functions: detectar imports Python anidados (`from pkg.subpkg import X`)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
# 0057 — audit_uses_functions: mejorar deteccion de simbolos Go con abreviaturas
|
||||
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
# 0058 — kanban: sync uses_functions cuando termine WIP en curso
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0059"
|
||||
title: "Resolver doble tracking de `apps/*/app.md` (fn_registry + sub-repo)"
|
||||
status: completado
|
||||
status: pendiente
|
||||
type: infra
|
||||
domain:
|
||||
- registry-quality
|
||||
@@ -11,7 +11,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
# 0060 — `fn doctor secrets`: scan de secrets en TODOS los repos
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
# 0061 — Integrar `notify_telegram` en deploy_server + bucle reactivo
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "55"
|
||||
title: "Roadmap de prereqs — issues de osint_graph que odr_console necesita antes/durante MVP"
|
||||
status: deferred
|
||||
status: pendiente
|
||||
type: epic
|
||||
domain:
|
||||
- osint
|
||||
@@ -7,7 +7,8 @@ domain:
|
||||
- registry-quality
|
||||
scope: registry-only
|
||||
priority: alta
|
||||
depends: ["0071f"]
|
||||
depends:
|
||||
- "0071f"
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
|
||||
@@ -7,7 +7,8 @@ domain:
|
||||
- registry-quality
|
||||
scope: registry-only
|
||||
priority: media
|
||||
depends: ["0071f"]
|
||||
depends:
|
||||
- "0071f"
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
|
||||
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
|
||||
## Contexto
|
||||
|
||||
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
|
||||
## Contexto
|
||||
|
||||
+4
-1
@@ -13,7 +13,10 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready, gamedev, cpp, wasm]
|
||||
tags:
|
||||
- gamedev
|
||||
- cpp
|
||||
- wasm
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
+2
-1
@@ -7,7 +7,8 @@ domain:
|
||||
- gamedev
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
depends: ["0072a"]
|
||||
depends:
|
||||
- "0072a"
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
+2
-1
@@ -7,7 +7,8 @@ domain:
|
||||
- gamedev
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
depends: ["0072b"]
|
||||
depends:
|
||||
- "0072b"
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
+3
-1
@@ -7,7 +7,9 @@ domain:
|
||||
- gamedev
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
depends: ["0072a", "0072b"]
|
||||
depends:
|
||||
- "0072a"
|
||||
- "0072b"
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
+3
-1
@@ -7,7 +7,9 @@ domain:
|
||||
- gamedev
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
depends: ["0072a", "0072d"]
|
||||
depends:
|
||||
- "0072a"
|
||||
- "0072d"
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
+2
-1
@@ -7,7 +7,8 @@ domain:
|
||||
- gamedev
|
||||
scope: multi-app
|
||||
priority: media
|
||||
depends: ["0072e"]
|
||||
depends:
|
||||
- "0072e"
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
+3
-1
@@ -7,7 +7,9 @@ domain:
|
||||
- gamedev
|
||||
scope: multi-app
|
||||
priority: media
|
||||
depends: ["0072b", "0072c"]
|
||||
depends:
|
||||
- "0072b"
|
||||
- "0072c"
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
+3
-1
@@ -7,7 +7,9 @@ domain:
|
||||
- gamedev
|
||||
scope: multi-app
|
||||
priority: media
|
||||
depends: ["0072b", "0072c"]
|
||||
depends:
|
||||
- "0072b"
|
||||
- "0072c"
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
+3
-1
@@ -7,7 +7,9 @@ domain:
|
||||
- gamedev
|
||||
scope: app-scoped
|
||||
priority: media
|
||||
depends: ["0072b", "0072c"]
|
||||
depends:
|
||||
- "0072b"
|
||||
- "0072c"
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
+6
-2
@@ -7,12 +7,16 @@ domain:
|
||||
- gamedev
|
||||
scope: multi-app
|
||||
priority: media
|
||||
depends: ["0072b"]
|
||||
depends:
|
||||
- "0072b"
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
updated: 2026-05-17
|
||||
tags: [gamedev, cpp, physics]
|
||||
tags:
|
||||
- gamedev
|
||||
- cpp
|
||||
- physics
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
+5
-1
@@ -7,7 +7,11 @@ domain:
|
||||
- gamedev
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
depends: ["0072b", "0072c", "0072d", "0072j"]
|
||||
depends:
|
||||
- "0072b"
|
||||
- "0072c"
|
||||
- "0072d"
|
||||
- "0072j"
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
|
||||
## Sintoma
|
||||
|
||||
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-10
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
|
||||
## Sintoma
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-13
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
+1
-1
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-13
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0087"
|
||||
title: "Capability Discovery Acceleration"
|
||||
status: completado
|
||||
status: pendiente
|
||||
type: feature
|
||||
domain:
|
||||
- meta
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
---
|
||||
id: "0178"
|
||||
id: "0088"
|
||||
title: "kanban: requester input vacío + navegación con teclado"
|
||||
status: pendiente
|
||||
type: feature
|
||||
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
|
||||
## Problema
|
||||
+1
-1
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
# 0088a — Trading: project scaffolding
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ domain:
|
||||
- meta
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
depends: ["0088a"]
|
||||
depends: []
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
+1
-1
@@ -7,7 +7,7 @@ domain:
|
||||
- trading
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
depends: ["0088a", "0088d"]
|
||||
depends: []
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
+1
-1
@@ -7,7 +7,7 @@ domain:
|
||||
- trading
|
||||
scope: app-scoped
|
||||
priority: alta
|
||||
depends: ["0088a"]
|
||||
depends: []
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
+1
-1
@@ -8,7 +8,7 @@ domain:
|
||||
- meta
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
depends: ["0088a"]
|
||||
depends: []
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
+1
-1
@@ -8,7 +8,7 @@ domain:
|
||||
- meta
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
depends: ["0088a"]
|
||||
depends: []
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
+1
-1
@@ -7,7 +7,7 @@ domain:
|
||||
- trading
|
||||
scope: app-scoped
|
||||
priority: alta
|
||||
depends: ["0088b", "0088c", "0088d", "0088e", "0088f"]
|
||||
depends: []
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
+1
-1
@@ -7,7 +7,7 @@ domain:
|
||||
- trading
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
depends: ["0088b", "0088c", "0088d", "0088e", "0088f", "0088g"]
|
||||
depends: []
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
+1
-1
@@ -7,7 +7,7 @@ domain:
|
||||
- trading
|
||||
scope: app-scoped
|
||||
priority: alta
|
||||
depends: ["0088a", "0088d"]
|
||||
depends: []
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
+1
-1
@@ -8,7 +8,7 @@ domain:
|
||||
- frontend
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
depends: ["0088d", "0088g", "0088h", "0088i"]
|
||||
depends: []
|
||||
blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
+1
-1
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
|
||||
## Problema
|
||||
+1
-1
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
|
||||
## Problema
|
||||
+1
-1
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
|
||||
## Problema
|
||||
+1
-1
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
|
||||
## Problema
|
||||
+1
-1
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
|
||||
## Problema
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0096"
|
||||
title: "Estandarizar ubicacion de apps: fuera de carpetas por lenguaje"
|
||||
status: completado
|
||||
status: pendiente
|
||||
type: feature
|
||||
domain:
|
||||
- apps-infra
|
||||
@@ -12,7 +12,7 @@ blocks: []
|
||||
related: []
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready]
|
||||
tags: []
|
||||
---
|
||||
# 0100 — Migrar frontmatter inline a YAML canonico en dev/issues/
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0101"
|
||||
title: "dev_console Go binario: /issue /flow /work unificados"
|
||||
status: completado
|
||||
status: pendiente
|
||||
type: app
|
||||
domain:
|
||||
- meta
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0103"
|
||||
title: "Taxonomia + slash commands /issue /flow /work"
|
||||
status: completado
|
||||
status: pendiente
|
||||
type: feature
|
||||
domain:
|
||||
- meta
|
||||
@@ -16,7 +16,7 @@ related:
|
||||
- "0103"
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [slash-command, dispatch, type-aware, ausente-ready]
|
||||
tags: [slash-command, dispatch, type-aware]
|
||||
---
|
||||
|
||||
# 0104 — `/fix-issue` type-aware dispatch
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0105"
|
||||
title: "Estandarizar bloque service: en app.md + indexer + fn doctor services-spec"
|
||||
status: completado
|
||||
status: in-progress
|
||||
type: feature
|
||||
domain:
|
||||
- meta
|
||||
@@ -16,7 +16,7 @@ related:
|
||||
- "0107"
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [modules, versioning, codegen, fail-loud, ausente-ready]
|
||||
tags: [modules, versioning, codegen, fail-loud]
|
||||
---
|
||||
|
||||
# 0107e — Version pinning + codegen fail-loud
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0109g"
|
||||
title: "skill_tree: panel terminal embebida (claude TUI dentro de la app)"
|
||||
status: deferred
|
||||
status: pendiente
|
||||
type: feature
|
||||
domain:
|
||||
- meta
|
||||
@@ -15,7 +15,12 @@ related:
|
||||
- "0109"
|
||||
created: 2026-05-17
|
||||
updated: 2026-05-17
|
||||
tags: [ausente-ready, skill-tree, cpp, imgui, dashboard, gamification]
|
||||
tags:
|
||||
- skill-tree
|
||||
- cpp
|
||||
- imgui
|
||||
- dashboard
|
||||
- gamification
|
||||
---
|
||||
|
||||
# 0109k — Dashboard panel
|
||||
|
||||
@@ -16,7 +16,13 @@ related:
|
||||
- "0106"
|
||||
created: 2026-05-18
|
||||
updated: 2026-05-18
|
||||
tags: [ausente-ready, service, go, http, issues, flows, api]
|
||||
tags:
|
||||
- service
|
||||
- go
|
||||
- http
|
||||
- issues
|
||||
- flows
|
||||
- api
|
||||
---
|
||||
|
||||
# 0109m — issues_api service
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ related:
|
||||
- "0106"
|
||||
created: 2026-05-18
|
||||
updated: 2026-05-18
|
||||
tags: [http, cpp, registry-gap, curl, helper, ausente-ready]
|
||||
tags: [http, cpp, registry-gap, curl, helper]
|
||||
---
|
||||
|
||||
# 0110 — Helper HTTP cliente C++ en el registry
|
||||
@@ -16,7 +16,7 @@ related:
|
||||
- "0068"
|
||||
created: 2026-05-18
|
||||
updated: 2026-05-19
|
||||
tags: [e2e_checks, recopilador, batch, coverage, epic, ausente-ready]
|
||||
tags: [e2e_checks, recopilador, batch, coverage, epic]
|
||||
---
|
||||
|
||||
# Sub-issues
|
||||
|
||||
@@ -16,7 +16,7 @@ related:
|
||||
- "0068"
|
||||
created: 2026-05-19
|
||||
updated: 2026-05-19
|
||||
tags: [e2e_checks, recopilador, batch, design, ausente-ready]
|
||||
tags: [e2e_checks, recopilador, batch, design]
|
||||
---
|
||||
|
||||
# 0121a — Design-e2e batch
|
||||
|
||||
@@ -7,7 +7,9 @@ domain:
|
||||
- registry-quality
|
||||
scope: registry
|
||||
priority: media
|
||||
depends: ["0121a"]
|
||||
depends:
|
||||
- "0121a"
|
||||
- "0121b"
|
||||
blocks:
|
||||
- "0122"
|
||||
related:
|
||||
|
||||
@@ -17,7 +17,7 @@ related:
|
||||
- "0086"
|
||||
created: 2026-05-18
|
||||
updated: 2026-05-18
|
||||
tags: [revisor, mejorador, proposals, auto-apply, autonomous, ausente-ready]
|
||||
tags: [revisor, mejorador, proposals, auto-apply, autonomous]
|
||||
---
|
||||
|
||||
# 0122 — fn-revisor + ampliar filtro auto-aplicable del orquestador
|
||||
|
||||
@@ -13,7 +13,7 @@ related:
|
||||
- "0121a"
|
||||
created: 2026-05-19
|
||||
updated: 2026-05-19
|
||||
tags: [dag_engine, cleanup, technical-debt, ausente-ready]
|
||||
tags: [dag_engine, cleanup, technical-debt]
|
||||
---
|
||||
|
||||
# 0124 — dag_engine cleanup
|
||||
|
||||
@@ -13,7 +13,7 @@ related:
|
||||
- "0121a"
|
||||
created: 2026-05-19
|
||||
updated: 2026-05-19
|
||||
tags: [deploy_server, cli, idempotency, ausente-ready]
|
||||
tags: [deploy_server, cli, idempotency]
|
||||
---
|
||||
|
||||
# 0125 — deploy_server `--db` flag
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0128"
|
||||
title: "kanban: adjuntar archivos (drag&drop desc/chat + tab Archivos)"
|
||||
status: in-progress
|
||||
status: in_progress
|
||||
type: feature
|
||||
domain:
|
||||
- apps-tools
|
||||
|
||||
@@ -13,7 +13,12 @@ blocks:
|
||||
- 0130b
|
||||
related:
|
||||
- "0130"
|
||||
tags: [registry, go, parser, frontmatter, fsnotify, ausente-ready]
|
||||
tags:
|
||||
- registry
|
||||
- go
|
||||
- parser
|
||||
- frontmatter
|
||||
- fsnotify
|
||||
flow: "0130"
|
||||
created: "2026-05-22"
|
||||
updated: "2026-05-22"
|
||||
|
||||
@@ -8,7 +8,8 @@ domain:
|
||||
- dev-ux
|
||||
scope: app-scoped
|
||||
priority: alta
|
||||
depends: ["0130a"]
|
||||
depends:
|
||||
- "0130a"
|
||||
blocks:
|
||||
- "0130c"
|
||||
related:
|
||||
|
||||
+2
-1
@@ -8,7 +8,8 @@ domain:
|
||||
- dev-ux
|
||||
scope: app-scoped
|
||||
priority: alta
|
||||
depends: ["0130b"]
|
||||
depends:
|
||||
- "0130b"
|
||||
blocks: []
|
||||
related:
|
||||
- "0130"
|
||||
+1
-1
@@ -16,7 +16,7 @@ related:
|
||||
- "0131"
|
||||
created: 2026-05-22
|
||||
updated: 2026-05-22
|
||||
tags: [cpp, imgui, terminal, pty, module, ausente-ready]
|
||||
tags: [cpp, imgui, terminal, pty, module]
|
||||
flow: ""
|
||||
---
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
---
|
||||
id: "0134"
|
||||
title: "Mesh protocol spec: capability manifests, ed25519 envelopes, enrollment, audit chain"
|
||||
status: pendiente
|
||||
status: pending
|
||||
type: spec
|
||||
domain:
|
||||
- infra
|
||||
- cybersecurity
|
||||
- protocols
|
||||
scope: cross-app
|
||||
priority: alta
|
||||
priority: high
|
||||
depends: []
|
||||
blocks:
|
||||
- "0135"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: "0144"
|
||||
title: "Agent LLM per machine (user + sudo) con tool registry y mesh dispatch"
|
||||
status: pendiente
|
||||
status: pending
|
||||
type: spec
|
||||
domain:
|
||||
- agents
|
||||
@@ -9,7 +9,7 @@ domain:
|
||||
- infra
|
||||
- cybersecurity
|
||||
scope: multi-app
|
||||
priority: alta
|
||||
priority: high
|
||||
depends:
|
||||
- "0134"
|
||||
- "0140"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user