- Inicio
- Documentation
- Sesiones
- Operaciones de sesión: export, dump, share, fork, resume/continue
Operaciones de sesión: export, dump, share, fork, resume/continue
Este documento describe el comportamiento visible para el operador de las operaciones de sesión export/share/fork/resume tal como están implementadas actualmente.
Archivos de implementación
Sección titulada «Archivos de implementación»../src/modes/controllers/command-controller.ts../src/session/agent-session.ts../src/session/session-manager.ts../src/export/html/index.ts../src/export/custom-share.ts../src/main.ts
Matriz de operaciones
Sección titulada «Matriz de operaciones»| Operación | Ruta de entrada | Mutación de sesión | Creación/cambio de archivo de sesión | Artefacto de salida |
|---|---|---|---|---|
/dump | Comando slash interactivo | No | No | Texto en portapapeles |
/export [path] | Comando slash interactivo | No | No | Archivo HTML |
--export <session.jsonl> [outputPath] | Ruta rápida de inicio CLI | Sin mutación de sesión en tiempo de ejecución | Sin sesión activa; lee el archivo objetivo | Archivo HTML |
/share | Comando slash interactivo | No | No | HTML temporal + URL de compartir/gist |
/fork | Comando slash interactivo | Sí (la identidad de sesión activa cambia) | Crea nuevo archivo de sesión y cambia la sesión actual a este (solo en modo persistente) | Copia el directorio de artefactos al nuevo namespace de sesión cuando está presente |
/resume | Comando slash interactivo | Sí (el estado activo en memoria es reemplazado) | Cambia al archivo de sesión existente seleccionado | Ninguno |
--resume | Inicio CLI (selector) | Sí después de la creación de sesión | Abre el archivo de sesión existente seleccionado | Ninguno |
--resume <id|path> | Inicio CLI | Sí después de la creación de sesión | Abre sesión existente; el caso entre proyectos puede bifurcar hacia el proyecto actual | Ninguno |
--continue | Inicio CLI | Sí después de la creación de sesión | Abre la miga de pan del terminal o la sesión más reciente; crea una nueva si no existe ninguna | Ninguno |
Export y dump
Sección titulada «Export y dump»/export [outputPath] (interactivo)
Sección titulada «/export [outputPath] (interactivo)»Flujo:
InputControllerenruta/export...aCommandController.handleExportCommand.- El comando divide por espacios en blanco y usa solo el primer argumento después de
/exportcomooutputPath. AgentSession.exportToHtml()llama aexportSessionToHtml(sessionManager, state, { outputPath, themeName }).- En caso de éxito, la UI muestra la ruta y abre el archivo en el navegador.
Detalles de comportamiento:
- Los argumentos
--copy,clipboardycopyson rechazados explícitamente con una advertencia para usar/dump. - La exportación incrusta encabezado/entradas/hoja de sesión más el
systemPromptactual y las descripciones de herramientas del estado del agente. - No se añaden entradas de sesión durante la exportación.
Advertencia:
- El análisis de argumentos se basa en espacios en blanco (
text.split(/\s+/)), por lo que las rutas entre comillas con espacios no se preservan como una sola ruta en esta ruta de comando.
--export <inputSessionFile> [outputPath] (CLI)
Sección titulada «--export <inputSessionFile> [outputPath] (CLI)»Flujo en main.ts:
- Se maneja tempranamente (antes del inicio interactivo/de sesión).
- Llama a
exportFromFile(inputPath, outputPath?). SessionManager.open(inputPath)carga las entradas, luego se genera y escribe el HTML.- El proceso imprime
Exported to: ...y termina.
Detalles de comportamiento:
- Un archivo de entrada faltante se muestra como
File not found: <path>. - Esta ruta no crea un
AgentSessiony no muta ninguna sesión en ejecución.
/dump (exportación interactiva al portapapeles)
Sección titulada «/dump (exportación interactiva al portapapeles)»Flujo:
CommandController.handleDumpCommand()llama asession.formatSessionAsText().- Si devuelve cadena vacía, reporta
No messages to dump yet. - De lo contrario, copia al portapapeles mediante
copyToClipboardnativo.
El contenido del dump incluye:
- Prompt del sistema
- Modelo activo/nivel de razonamiento
- Definiciones de herramientas + parámetros
- Mensajes de usuario/asistente
- Bloques de razonamiento y llamadas a herramientas
- Resultados de herramientas y bloques de ejecución (excepto entradas bash/python con
excludeFromContext) - Entradas personalizadas/hook/mención de archivos/resumen de rama/resumen de compactación
No se realizan cambios de persistencia de sesión al hacer dump.
/share es solo interactivo y siempre comienza exportando la sesión actual a un archivo HTML temporal.
Fase 1: exportación temporal
Sección titulada «Fase 1: exportación temporal»- Ruta del archivo temporal:
${os.tmpdir()}/${Snowflake.next()}.html - Usa
session.exportToHtml(tmpFile) - Si la exportación falla (notablemente en sesiones en memoria), share termina con error.
Fase 2: manejador de compartir personalizado (si está presente)
Sección titulada «Fase 2: manejador de compartir personalizado (si está presente)»loadCustomShare() busca en ~/.xcsh/agent el primer candidato existente:
share.tsshare.jsshare.mjs
Requisitos:
- El módulo debe exportar por defecto una función
(htmlPath) => Promise<CustomShareResult | string | undefined>.
Si está presente y es válido:
- La UI entra en estado de carga
Sharing.... - Interpretación del resultado del manejador:
- string => se trata como URL, se muestra y se abre
- object => se muestran
urly/omessage; se abreurl undefined/falsy =>Session sharedgenérico
- El archivo temporal se elimina después de completarse.
Comportamiento crítico de respaldo:
- Si el manejador personalizado existe pero falla al cargarse, el comando genera error y retorna.
- Si el manejador personalizado se ejecuta y lanza una excepción, el comando genera error y retorna.
- En ambos casos de fallo, no recurre al gist de GitHub como respaldo.
- El respaldo a gist solo ocurre cuando no existe ningún script de compartir personalizado.
Fase 3: respaldo predeterminado a gist
Sección titulada «Fase 3: respaldo predeterminado a gist»Solo cuando no se encuentra ningún manejador de compartir personalizado:
- Valida
gh auth status. - Muestra el indicador de carga
Creating gist.... - Ejecuta
gh gist create --public=false <tmpFile>. - Analiza la URL del gist, deriva el id del gist, construye la URL de vista previa
https://gistpreview.github.io/?<id>. - Muestra tanto la URL de vista previa como la del gist; abre la vista previa.
Semánticas de cancelación/aborto en share:
- El indicador de carga tiene un hook
onAbortque restaura la UI del editor y reportaShare cancelled. - El comando subyacente
gh gist createno recibe una señal de aborto en esta ruta de código; la cancelación es a nivel de UI y se verifica después de que el comando retorna.
/fork crea una nueva sesión a partir de la actual y cambia la identidad de sesión activa.
Precondiciones y guardas inmediatas
Sección titulada «Precondiciones y guardas inmediatas»- Si el agente está en streaming,
/forkse rechaza con advertencia. - Los indicadores de estado/carga de la UI se limpian antes de la operación.
Flujo a nivel de sesión
Sección titulada «Flujo a nivel de sesión»AgentSession.fork():
- Emite
session_before_switchconreason: "fork"(cancelable). - Descarga las escrituras pendientes.
- Llama a
SessionManager.fork(). - Copia el directorio de artefactos del namespace de sesión antiguo al nuevo (mejor esfuerzo; los fallos de copia que no son ENOENT se registran en log, no son fatales).
- Actualiza
agent.sessionId. - Emite
session_switchconreason: "fork".
Comportamiento de SessionManager.fork():
- Requiere modo persistente y archivo de sesión existente.
- Crea nuevo id de sesión y nueva ruta de archivo JSONL.
- Reescribe el encabezado con:
- nuevo
id - nueva marca de tiempo
cwdsin cambiosparentSessionestablecido al id de sesión anterior
- nuevo
- Mantiene todas las entradas que no son encabezado sin cambios en el nuevo archivo.
Comportamiento no persistente
Sección titulada «Comportamiento no persistente»- El administrador de sesiones en memoria devuelve
undefineddefork(). AgentSession.fork()devuelvefalse.- La UI reporta
Fork failed (session not persisted or cancelled).
Resume y continue
Sección titulada «Resume y continue»/resume interactivo
Sección titulada «/resume interactivo»Flujo:
- Abre el selector de sesión poblado mediante
SessionManager.list(currentCwd, currentSessionDir). - Al seleccionar,
SelectorController.handleResumeSession(sessionPath)llama asession.switchSession(sessionPath). - La UI limpia/reconstruye el chat y los pendientes, luego reporta
Resumed session.
Notas:
- Este selector solo lista sesiones en el ámbito del directorio de sesión actual.
- No usa búsqueda global entre proyectos.
CLI --resume
Sección titulada «CLI --resume»--resume (sin valor)
Sección titulada «--resume (sin valor)»main.tslista sesiones para el cwd/sessionDir actual y abre el selector.- La ruta seleccionada se abre con
SessionManager.open(selectedPath)antes de la creación de sesión.
--resume <value>
Sección titulada «--resume <value>»Orden de resolución de createSessionManager():
- Si el valor parece una ruta (
/,\, o.jsonl), abre directamente. - De lo contrario, trata como prefijo de id:
- busca en el ámbito actual (
SessionManager.list(cwd, sessionDir)) - si no se encuentra y no hay
sessionDirexplícito, busca globalmente (SessionManager.listAll())
- busca en el ámbito actual (
Comportamiento de coincidencia de id entre proyectos:
- Si el cwd de la sesión coincidente difiere del cwd actual, el CLI pregunta:
Session found in different project ... Fork into current directory? [y/N]
- Al aceptar:
SessionManager.forkFrom(match.path, cwd, sessionDir)crea un nuevo archivo local bifurcado. - Al rechazar/predeterminado sin TTY: el comando genera error.
CLI --continue
Sección titulada «CLI --continue»SessionManager.continueRecent(cwd, sessionDir):
- Resuelve el directorio de sesión para el cwd actual.
- Lee primero la miga de pan con ámbito de terminal.
- Recurre como respaldo al archivo de sesión modificado más recientemente.
- Abre la sesión encontrada; si no existe ninguna, crea una nueva sesión.
Este es un comportamiento solo de inicio; no existe un comando slash interactivo /continue.
Cómo el cambio de sesión muta realmente el estado en tiempo de ejecución
Sección titulada «Cómo el cambio de sesión muta realmente el estado en tiempo de ejecución»AgentSession.switchSession(sessionPath) realiza la transición en tiempo de ejecución utilizada por las operaciones tipo resume:
- Emite
session_before_switchconreason: "resume"ytargetSessionFile(cancelable). - Desconecta la suscripción de eventos del agente y aborta el trabajo en curso.
- Limpia los mensajes encolados de steering/seguimiento/siguiente turno.
- Descarga las escrituras del administrador de sesión actual.
sessionManager.setSessionFile(sessionPath)y actualizaagent.sessionId.- Construye el contexto de sesión a partir de las entradas cargadas.
- Emite
session_switchconreason: "resume". - Reemplaza los mensajes del agente desde el contexto.
- Restaura el modelo (si está disponible en el registro actual).
- Restaura o inicializa el nivel de razonamiento.
- Reconecta la suscripción de eventos del agente.
switchSession() en sí mismo no crea ningún archivo de sesión nuevo.
Emisiones de eventos y puntos de cancelación
Sección titulada «Emisiones de eventos y puntos de cancelación»Hooks del ciclo de vida de switch/fork
Sección titulada «Hooks del ciclo de vida de switch/fork»Para newSession, fork y switchSession:
- Evento anterior:
session_before_switch- razones:
new,fork,resume - cancelable devolviendo
{ cancel: true }
- razones:
- Evento posterior:
session_switch- mismo conjunto de razones
- incluye
previousSessionFile
ExtensionRunner.emit() retorna tempranamente con el primer resultado de evento anterior que cancele.
Comportamiento de onSession en herramientas personalizadas
Sección titulada «Comportamiento de onSession en herramientas personalizadas»Los puentes del SDK conectan eventos de sesión de extensiones a callbacks onSession de herramientas personalizadas:
session_switch->onSession({ reason: "switch", previousSessionFile })session_branch->reason: "branch"session_start->reason: "start"session_tree->reason: "tree"session_shutdown->reason: "shutdown"
Estos callbacks son observacionales; no cancelan switch/fork.
Otras superficies de cancelación relevantes para este documento
Sección titulada «Otras superficies de cancelación relevantes para este documento»/forkse bloquea durante el streaming (el usuario debe esperar/abortar la respuesta actual primero).- El selector de
/resumepuede cancelarse si el usuario cierra el selector. --resume <id>entre proyectos puede cancelarse rechazando el prompt de fork./sharetiene ruta de aborto en la UI (Share cancelled) para el flujo de gist; no conecta semánticas de proceso-kill paragh gist createen esta ruta de código.
Comportamiento de sesión no persistente (en memoria)
Sección titulada «Comportamiento de sesión no persistente (en memoria)»Cuando el administrador de sesiones se crea con SessionManager.inMemory() (--no-session):
- La ruta del archivo de sesión está ausente.
/exporty/sharefallan conCannot export in-memory session to HTML(propagado a la UI de error del comando)./forkfalla porqueSessionManager.fork()requiere persistencia./dumpsigue funcionando porque serializa el estado del agente en memoria.- Las semánticas de resume/continue del CLI se omiten si
--no-sessionestá establecido, porque la creación del administrador devuelve en memoria inmediatamente.
Advertencias de implementación conocidas (a partir del código actual)
Sección titulada «Advertencias de implementación conocidas (a partir del código actual)»SelectorController.handleResumeSession()no verifica el resultado booleano desession.switchSession(...); un cambio cancelado por un hook puede aún proceder a través de la ruta de repintado/estado de la UI “Resumed session”.- Los fallos de
/sharecon compartir personalizado no degradan al respaldo de gist predeterminado; terminan el comando con error. - La tokenización de argumentos de
/exportes simplista y no preserva rutas entre comillas con espacios.