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:
@@ -0,0 +1,63 @@
|
||||
//go:build !windows
|
||||
|
||||
package infra
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TmuxNewClaudeWindow crea una window nueva en <session> del socket <socket>
|
||||
// que corre `claude --dangerously-skip-permissions` en <cwd>. Acepta argumentos
|
||||
// extra opcionales que se anaden al comando (ej. "--resume", "<sessionId>" para
|
||||
// reabrir una conversacion). Devuelve el window_id (ej "@7"). No cambia el foco
|
||||
// (-d). Opera SIEMPRE sobre el socket aislado pasado como parametro
|
||||
// (tmux -L <socket>), nunca sobre el servidor tmux por defecto del usuario.
|
||||
func TmuxNewClaudeWindow(socket, session, cwd string, extraArgs ...string) (string, error) {
|
||||
if socket == "" {
|
||||
return "", fmt.Errorf("tmux_new_claude_window: socket vacio")
|
||||
}
|
||||
if session == "" {
|
||||
return "", fmt.Errorf("tmux_new_claude_window: session vacia")
|
||||
}
|
||||
if cwd == "" {
|
||||
return "", fmt.Errorf("tmux_new_claude_window: cwd vacio")
|
||||
}
|
||||
|
||||
// El comando del pane: claude reemplaza al shell, asi que #{pane_pid} sera el
|
||||
// PID de claude. Se anaden los argumentos extra (ej. --resume <id>).
|
||||
command := "claude --dangerously-skip-permissions"
|
||||
if len(extraArgs) > 0 {
|
||||
command += " " + strings.Join(extraArgs, " ")
|
||||
}
|
||||
|
||||
// -d: no cambia el foco. -P -F '#{window_id}': imprime el id de la window
|
||||
// creada. -t <session>: la crea en esa sesion. -c <cwd>: working dir del pane.
|
||||
out, stderr, err := runTmux(socket,
|
||||
"new-window", "-d", "-P", "-F", "#{window_id}",
|
||||
"-t", session, "-c", cwd,
|
||||
command,
|
||||
)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("tmux_new_claude_window: new-window en %q: %w (%s)", session, err, stderr)
|
||||
}
|
||||
|
||||
windowID := strings.TrimSpace(out)
|
||||
if windowID == "" {
|
||||
return "", fmt.Errorf("tmux_new_claude_window: new-window no devolvio window_id (stderr=%q)", stderr)
|
||||
}
|
||||
return windowID, nil
|
||||
}
|
||||
|
||||
// runTmux ejecuta `tmux -L <socket> <args...>` y devuelve stdout, stderr y el
|
||||
// error de ejecucion. Helper comun a la capa de control tmux de fleetview.
|
||||
func runTmux(socket string, args ...string) (stdout, stderr string, err error) {
|
||||
full := append([]string{"-L", socket}, args...)
|
||||
cmd := exec.Command("tmux", full...)
|
||||
var outBuf, errBuf strings.Builder
|
||||
cmd.Stdout = &outBuf
|
||||
cmd.Stderr = &errBuf
|
||||
err = cmd.Run()
|
||||
return outBuf.String(), errBuf.String(), err
|
||||
}
|
||||
Reference in New Issue
Block a user