- Inicio
- Documentation
- Sesiones
- Cambio de sesión y listado de sesiones recientes
Cambio de sesión y listado de sesiones recientes
Este documento describe cómo coding-agent descubre sesiones recientes, resuelve objetivos de --resume, presenta selectores de sesión y cambia la sesión activa en tiempo de ejecución.
Se centra en el comportamiento de la implementación actual, incluyendo rutas de respaldo y advertencias.
Archivos de implementación
Sección titulada «Archivos de implementación»../src/session/session-manager.ts../src/session/agent-session.ts../src/cli/session-picker.ts../src/modes/components/session-selector.ts../src/modes/controllers/selector-controller.ts../src/main.ts../src/sdk.ts../src/modes/interactive-mode.ts../src/modes/utils/ui-helpers.ts
Descubrimiento de sesiones recientes
Sección titulada «Descubrimiento de sesiones recientes»Alcance del directorio
Sección titulada «Alcance del directorio»SessionManager almacena sesiones bajo un directorio con alcance al cwd por defecto:
~/.xcsh/agent/sessions/--<cwd-encoded>--/*.jsonl
SessionManager.list(cwd, sessionDir?) lee solo ese directorio a menos que se proporcione un sessionDir explícito.
Dos rutas de listado con diferentes cargas útiles
Sección titulada «Dos rutas de listado con diferentes cargas útiles»Existen dos pipelines de listado diferentes:
-
getRecentSessions(sessionDir, limit)(vista de bienvenida/resumen)- Lee solo un prefijo de 4KB (
readTextPrefix(..., 4096)) de cada archivo. - Analiza el encabezado + vista previa del texto más antiguo del usuario.
- Devuelve
RecentSessionInfoligero con getters lazy paranameytimeAgo. - Ordena por
mtimedel archivo de forma descendente.
- Lee solo un prefijo de 4KB (
-
SessionManager.list(...)/SessionManager.listAll()(selectores de reanudación y coincidencia de ID)- Lee los archivos de sesión completos.
- Construye objetos
SessionInfo(id,cwd,title,messageCount,firstMessage,allMessagesText, marcas de tiempo). - Descarta sesiones con cero entradas de
message. - Ordena por
modifiedde forma descendente.
Comportamiento de respaldo de metadatos
Sección titulada «Comportamiento de respaldo de metadatos»Para resúmenes recientes (RecentSessionInfo):
- preferencia de nombre para mostrar:
header.title-> primer prompt del usuario ->header.id-> nombre del archivo - el nombre se trunca a 40 caracteres para visualizaciones compactas
- los caracteres de control/saltos de línea se eliminan/sanitizan de los nombres derivados del título
Para entradas de lista SessionInfo:
titleesheader.titleo el últimoshortSummaryde compactaciónfirstMessagees el texto del primer mensaje del usuario o"(no messages)"
Resolución de --continue y preferencia de breadcrumb del terminal
Sección titulada «Resolución de --continue y preferencia de breadcrumb del terminal»SessionManager.continueRecent(cwd, sessionDir?) resuelve el objetivo en este orden:
- Leer el breadcrumb con alcance al terminal (
~/.xcsh/agent/terminal-sessions/<terminal-id>) - Validar el breadcrumb:
- el terminal actual puede ser identificado
- el cwd del breadcrumb coincide con el cwd actual (comparación de rutas resueltas)
- el archivo referenciado aún existe
- Si el breadcrumb es inválido/no existe, recurrir al archivo más reciente por mtime en el directorio de sesiones (
findMostRecentSession) - Si no se encuentra ninguno, crear una nueva sesión
La derivación del ID del terminal prefiere la ruta TTY y recurre a identificadores basados en variables de entorno (KITTY_WINDOW_ID, TMUX_PANE, TERM_SESSION_ID, WT_SESSION).
Las escrituras de breadcrumb son de mejor esfuerzo y no fatales.
Resolución del objetivo de reanudación en tiempo de inicio (main.ts)
Sección titulada «Resolución del objetivo de reanudación en tiempo de inicio (main.ts)»--resume <value>
Sección titulada «--resume <value>»createSessionManager(...) maneja --resume con valor de cadena en dos modos:
-
Valor tipo ruta (contiene
/,\\, o termina con.jsonl)SessionManager.open(sessionArg, parsed.sessionDir)directo
-
Valor de prefijo de ID
- busca coincidencia en
SessionManager.list(cwd, sessionDir)medianteid.startsWith(sessionArg) - si no hay coincidencia local y
sessionDirno está forzado, intentaSessionManager.listAll() - se usa la primera coincidencia (sin prompt de ambigüedad)
- busca coincidencia en
Comportamiento de coincidencia entre proyectos:
- si el cwd de la sesión coincidente difiere del cwd actual, el CLI pregunta si bifurcar al proyecto actual
- sí ->
SessionManager.forkFrom(...) - no -> lanza error (
Session "..." is in another project (...))
Sin coincidencia -> lanza error (Session "..." not found.).
--resume (sin valor)
Sección titulada «--resume (sin valor)»Se maneja después de la construcción inicial del session-manager:
- listar sesiones locales con
SessionManager.list(cwd, parsed.sessionDir) - si está vacío: imprimir
No sessions foundy salir tempranamente - abrir selector TUI (
selectSession) - si se cancela: imprimir
No session selectedy salir tempranamente - si se selecciona:
SessionManager.open(selectedPath)
--continue
Sección titulada «--continue»Usa SessionManager.continueRecent(...) directamente (comportamiento de breadcrumb primero descrito anteriormente).
Detalles internos de selección por selector
Sección titulada «Detalles internos de selección por selector»Selector CLI (src/cli/session-picker.ts)
Sección titulada «Selector CLI (src/cli/session-picker.ts)»selectSession(sessions) crea una TUI independiente con SessionSelectorComponent y se resuelve exactamente una vez:
- selección -> resuelve con la ruta seleccionada
- cancelar (Esc) -> resuelve con
null - salida forzada (ruta Ctrl+C) -> detiene la TUI y
process.exit(0)
Selector interactivo dentro de sesión (SelectorController.showSessionSelector)
Sección titulada «Selector interactivo dentro de sesión (SelectorController.showSessionSelector)»Flujo:
- obtener sesiones del directorio de sesión actual vía
SessionManager.list(currentCwd, currentSessionDir) - montar
SessionSelectorComponenten el área del editor usandoshowSelector(...) - callbacks:
- seleccionar -> cerrar selector y llamar a
handleResumeSession(sessionPath) - cancelar -> restaurar editor y rerenderizar
- salir ->
ctx.shutdown()
- seleccionar -> cerrar selector y llamar a
Comportamiento del componente selector de sesión
Sección titulada «Comportamiento del componente selector de sesión»SessionList soporta:
- navegación con flechas/página
- Enter para seleccionar
- Esc para cancelar
- Ctrl+C para salir
- búsqueda difusa a través de id/título/cwd/primer mensaje/todos los mensajes/ruta de la sesión
Comportamiento de renderizado con lista vacía:
- renderiza un mensaje en lugar de fallar
- Enter en lista vacía no hace nada (sin callback)
- Esc/Ctrl+C siguen funcionando
Advertencia: El texto de la UI dice Press Tab to view all, pero este componente actualmente no tiene manejador de Tab y el cableado actual solo lista sesiones del alcance actual.
Ejecución del cambio en tiempo de ejecución (AgentSession.switchSession)
Sección titulada «Ejecución del cambio en tiempo de ejecución (AgentSession.switchSession)»switchSession(sessionPath) es la ruta principal de cambio dentro del proceso.
Ciclo de vida/transición de estado:
- capturar
previousSessionFile - emitir evento hook
session_before_switch(reason: "resume", cancelable) - si se cancela -> retorna
falsesin cambio - desconectar del flujo de eventos del agente actual
- abortar generación/flujo de herramientas activo
- limpiar buffers de mensajes de steering/seguimiento/siguiente turno en cola
- vaciar el escritor de sesión (
sessionManager.flush()) para persistir escrituras pendientes sessionManager.setSessionFile(sessionPath)- actualiza el puntero del archivo de sesión
- escribe el breadcrumb del terminal
- carga entradas / migra / resuelve blobs / reindexa
- si los datos del archivo están ausentes/son inválidos: inicializa una nueva sesión en esa ruta y reescribe el encabezado
- actualizar
agent.sessionId - reconstruir contexto vía
buildSessionContext() - emitir evento hook
session_switch(reason: "resume",previousSessionFile) - reemplazar mensajes del agente con el contexto reconstruido
- restaurar modelo por defecto desde
sessionContext.models.defaultsi está disponible y presente en el registro de modelos - restaurar nivel de pensamiento:
- si la rama ya tiene
thinking_level_change, aplicar el nivel de sesión guardado - de lo contrario, derivar el nivel de pensamiento por defecto de la configuración, ajustar a la capacidad del modelo, establecerlo y agregar una nueva entrada
thinking_level_change
- si la rama ya tiene
- reconectar listeners del agente y retornar
true
Reconstrucción del estado de la UI después del cambio interactivo
Sección titulada «Reconstrucción del estado de la UI después del cambio interactivo»SelectorController.handleResumeSession realiza el reinicio de la UI alrededor de switchSession:
- detener animación de carga
- limpiar contenedor de estado
- limpiar UI de mensaje pendiente y mapa de herramientas pendientes
- reiniciar componente de streaming/referencias de mensaje
- llamar a
session.switchSession(...) - limpiar contenedor del chat y rerenderizar desde el contexto de sesión (
renderInitialMessages) - recargar todos desde los artefactos de la nueva sesión
- mostrar
Resumed session
Así que el estado visible de conversación/todos se reconstruye desde el nuevo archivo de sesión.
Reanudación al inicio vs cambio dentro de sesión
Sección titulada «Reanudación al inicio vs cambio dentro de sesión»Reanudación al inicio (--continue, --resume, apertura directa)
Sección titulada «Reanudación al inicio (--continue, --resume, apertura directa)»- El archivo de sesión se elige antes de
createAgentSession(...). sdk.tsconstruyeexistingSession = sessionManager.buildSessionContext().- Los mensajes del agente se restauran una vez durante la creación de la sesión.
- El modelo/pensamiento se seleccionan durante la creación (incluyendo lógica de restauración/respaldo).
- El modo interactivo luego ejecuta
#restoreModeFromSession()para re-entrar al estado de modo persistido (actualmente plan/plan_paused).
Cambio dentro de sesión (ruta del selector estilo /resume)
Sección titulada «Cambio dentro de sesión (ruta del selector estilo /resume)»- Usa
AgentSession.switchSession(...)en unAgentSessionya en ejecución. - Los mensajes/modelo/pensamiento se reconstruyen inmediatamente en su lugar.
- Se emiten eventos hook
session_before_switch/session_switch. - Se refrescan el chat/todos de la UI.
- No se realiza una llamada dedicada de restauración de modo post-cambio en el flujo del selector; el comportamiento de re-entrada al modo no es simétrico con
#restoreModeFromSession()del inicio.
Comportamiento ante fallos y casos límite
Sección titulada «Comportamiento ante fallos y casos límite»Rutas de cancelación
Sección titulada «Rutas de cancelación»- Cancelación del selector CLI -> retorna
null, el llamador imprimeNo session selected, el proceso sale tempranamente. - Cancelación del selector interactivo -> se restaura el editor, sin cambio de sesión.
- Cancelación por hook (
session_before_switch) ->switchSession()retornafalse.
Rutas con lista vacía
Sección titulada «Rutas con lista vacía»- CLI
--resume(sin valor): lista vacía imprimeNo sessions foundy sale. - Selector interactivo: lista vacía renderiza mensaje y permanece cancelable.
Archivo de sesión objetivo ausente/inválido
Sección titulada «Archivo de sesión objetivo ausente/inválido»Al abrir/cambiar a una ruta específica (setSessionFile):
- ENOENT -> tratado como vacío -> nueva sesión inicializada en esa ruta exacta y persistida.
- encabezado malformado/inválido (o entradas parseadas efectivamente ilegibles) -> tratado como vacío -> nueva sesión inicializada y persistida.
Esto es comportamiento de recuperación, no fallo duro.
Fallos duros
Sección titulada «Fallos duros»El cambio/apertura aún puede lanzar excepciones en fallos de E/S reales (errores de permisos, fallos de reescritura, etc.), que se propagan a los llamadores.
Advertencias sobre coincidencia de prefijo de ID
Sección titulada «Advertencias sobre coincidencia de prefijo de ID»- La coincidencia de ID usa
startsWithy toma la primera coincidencia en la lista ordenada. - No hay UI de ambigüedad si múltiples sesiones comparten prefijo.
SessionManager.list(...)excluye sesiones con cero mensajes, por lo que esas sesiones no son reanudables vía coincidencia de ID/selector de lista.