927437a8d8
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>
69 lines
5.1 KiB
Markdown
69 lines
5.1 KiB
Markdown
---
|
|
name: list_resumable_claudes
|
|
kind: function
|
|
lang: go
|
|
domain: infra
|
|
version: "1.0.0"
|
|
purity: impure
|
|
signature: "func ListResumableClaudesFrom(claudeDir string) ([]ResumableClaude, error) | func ListResumableClaudes() ([]ResumableClaude, error)"
|
|
description: "Lista las sesiones de Claude Code CERRADAS que se pueden reabrir con `claude --resume <sessionId>` (Linux). Escanea ~/.claude/sessions/*.json para construir el conjunto de sessionIds VIVOS (mismo criterio anti-PID-reciclado que list_claude_fleet: procStart == campo 22 de /proc/<pid>/stat), luego recorre ~/.claude/goals/*.json y devuelve cada sesion cuyo proceso NO esta vivo y que tiene un goal no vacio. Cada entrada lleva session_id, goal, emojis y name (rename) del goal.json, y last_active = mtime del goal.json. Ordenadas por last_active desc y limitadas a 40. Pieza de datos del picker de resume de la app TUI fleetview."
|
|
tags: [claude-fleet, infra, claude, session, resume, proc, tui]
|
|
uses_functions: [list_claude_fleet_go_infra]
|
|
uses_types: [resumable_claude_go_infra]
|
|
returns: [resumable_claude_go_infra]
|
|
returns_optional: false
|
|
error_type: "error_go_core"
|
|
imports: []
|
|
params:
|
|
- name: "claudeDir"
|
|
desc: "Directorio raiz de Claude Code a escanear (ej. /home/enmanuel/.claude). ListResumableClaudesFrom lo recibe explicito (testeable con t.TempDir()); ListResumableClaudes lo resuelve via os.UserHomeDir() + .claude."
|
|
output: "Slice de ResumableClaude (resumable_claude_go_infra), una entrada por sesion CERRADA con goal en goals/<id>.json. Cada entrada lleva SessionID (basename del goal.json sin .json), Goal, Emojis, Name (rename) y LastActive (mtime del goal.json en epoch segundos). Excluye las sesiones cuyo proceso sigue vivo (ya en la flota) y las que no tienen goal. Ordenado por LastActive descendente y capado a 40 resultados. Devuelve slice vacio (sin error) si la carpeta goals/ no existe; error si no se puede leer por otra causa."
|
|
tested: true
|
|
tests: ["TestListResumableClaudesFrom"]
|
|
test_file_path: "functions/infra/resumable_claude_test.go"
|
|
file_path: "functions/infra/resumable_claude.go"
|
|
notes: "Complementaria de list_claude_fleet_go_infra: aquella lista las sesiones VIVAS, esta las CERRADAS-pero-resumibles. Reutiliza los helpers procIsAlive/procStartTime del mismo paquete infra (definidos en functions/infra/list_claude_fleet.go) — no los redefine. El conjunto de vivos se construye desde sessions/*.json; el catalogo de candidatas desde goals/*.json. El sessionId de una candidata es el basename del goal.json (no hay sessions/<PID>.json para ella porque su proceso ya murio). LastActive es el mtime del archivo, no la actividad real de la conversacion. Build tag //go:build !windows (depende de /proc, no portable a Windows)."
|
|
---
|
|
|
|
## Ejemplo
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"fn-registry/functions/infra"
|
|
)
|
|
|
|
func main() {
|
|
resumables, err := infra.ListResumableClaudes() // escanea ~/.claude
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
for _, r := range resumables {
|
|
fmt.Printf("%s %-40s claude --resume %s\n", r.Emojis, r.Goal, r.SessionID)
|
|
}
|
|
}
|
|
```
|
|
|
|
```go
|
|
// Variante testeable: escanea un directorio arbitrario (fixtures en tests).
|
|
resumables, _ := infra.ListResumableClaudesFrom("/home/enmanuel/.claude")
|
|
fmt.Println(len(resumables), "sesiones reabribles")
|
|
```
|
|
|
|
## Cuando usarla
|
|
|
|
Cuando necesites poblar un picker de "reanudar" en la TUI fleetview (o cualquier UI/automatizacion equivalente): te da las sesiones de Claude Code que ya cerraste pero que tenian un objetivo guardado, listas para `claude --resume <session_id>`. Excluye las que siguen vivas (esas ya estan en la flota, las lista `list_claude_fleet_go_infra`). Usa `ListResumableClaudesFrom` en tests (inyectando un directorio con fixtures) y `ListResumableClaudes` en runtime real.
|
|
|
|
## Gotchas
|
|
|
|
- **Impura: lee el filesystem y /proc.** No es determinista entre llamadas (las sesiones nacen y mueren). Solo lectura — nunca relanza ni mata nada.
|
|
- **El statusline purga goals viejos.** Las sesiones de mas de ~7 dias suelen tener su `goals/<id>.json` purgado por el statusline, asi que dejan de aparecer aqui aunque `claude --resume` siga pudiendo reabrirlas. Esta funcion solo ve lo que queda en `goals/`.
|
|
- **PID reciclado.** El conjunto de "vivos" usa el mismo guardado anti-PID-reciclado que `list_claude_fleet`: un PID reasignado a otro proceso NO marca la sesion como viva (procStart != campo 22 de /proc/<pid>/stat), por lo que su goal seguira saliendo como resumible correctamente.
|
|
- **Orden por mtime, no por actividad real.** `LastActive` es el `mtime` del `goal.json`, que se toca cuando el statusline reescribe el objetivo/fase — no es el instante exacto del ultimo mensaje de la conversacion. Es una aproximacion "lo mas reciente arriba", no un timestamp exacto de actividad.
|
|
- **Cap a 40.** Solo se devuelven las 40 mas recientes; si hay mas goals cerrados, los antiguos se omiten.
|
|
- **Goals sin goal o ilegibles se omiten** silenciosamente. Un `goal.json` con `goal` vacio (o solo espacios) no es resumible (no hay trabajo que reanudar). Archivos no-`.json` y JSON corrupto se ignoran.
|
|
- **/proc no es portable.** Build tag `//go:build !windows`; depende de `/proc/<pid>/stat` (Linux) para decidir que sesiones estan vivas.
|