- Home
- Documentation
- Sessioni
- Cambio di sessione e lista delle sessioni recenti
Cambio di sessione e lista delle sessioni recenti
Questo documento descrive come coding-agent scopre le sessioni recenti, risolve i target di --resume, presenta i selettori di sessione e cambia la sessione runtime attiva.
Si concentra sul comportamento dell’implementazione attuale, inclusi i percorsi di fallback e le avvertenze.
File di implementazione
Sezione intitolata “File di implementazione”../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
Scoperta delle sessioni recenti
Sezione intitolata “Scoperta delle sessioni recenti”Ambito della directory
Sezione intitolata “Ambito della directory”SessionManager salva le sessioni in una directory con ambito cwd per impostazione predefinita:
~/.xcsh/agent/sessions/--<cwd-encoded>--/*.jsonl
SessionManager.list(cwd, sessionDir?) legge solo quella directory a meno che non venga fornita una sessionDir esplicita.
Due percorsi di listing con payload differenti
Sezione intitolata “Due percorsi di listing con payload differenti”Esistono due pipeline di listing differenti:
-
getRecentSessions(sessionDir, limit)(vista di benvenuto/riepilogo)- Legge solo un prefisso di 4KB (
readTextPrefix(..., 4096)) da ciascun file. - Analizza l’header + anteprima del primo testo utente.
- Restituisce un
RecentSessionInfoleggero con getter lazy pernameetimeAgo. - Ordina per
mtimedel file in ordine decrescente.
- Legge solo un prefisso di 4KB (
-
SessionManager.list(...)/SessionManager.listAll()(selettori di ripresa e corrispondenza ID)- Legge i file di sessione completi.
- Costruisce oggetti
SessionInfo(id,cwd,title,messageCount,firstMessage,allMessagesText, timestamp). - Esclude le sessioni con zero voci
message. - Ordina per
modifiedin ordine decrescente.
Comportamento di fallback dei metadati
Sezione intitolata “Comportamento di fallback dei metadati”Per i riepiloghi recenti (RecentSessionInfo):
- preferenza del nome visualizzato:
header.title-> primo prompt utente ->header.id-> nome file - il nome è troncato a 40 caratteri per le visualizzazioni compatte
- i caratteri di controllo/newline vengono rimossi/sanificati dai nomi derivati dal titolo
Per le voci della lista SessionInfo:
titleèheader.titleo l’ultimoshortSummarydi compattazionefirstMessageè il testo del primo messaggio utente o"(no messages)"
Risoluzione di --continue e preferenza del breadcrumb del terminale
Sezione intitolata “Risoluzione di --continue e preferenza del breadcrumb del terminale”SessionManager.continueRecent(cwd, sessionDir?) risolve il target in questo ordine:
- Legge il breadcrumb con ambito terminale (
~/.xcsh/agent/terminal-sessions/<terminal-id>) - Valida il breadcrumb:
- il terminale corrente può essere identificato
- il cwd del breadcrumb corrisponde al cwd corrente (confronto di percorsi risolti)
- il file referenziato esiste ancora
- Se il breadcrumb è invalido/mancante, ripiegamento sul file più recente per mtime nella directory di sessione (
findMostRecentSession) - Se nessuno trovato, crea una nuova sessione
La derivazione dell’ID del terminale preferisce il percorso TTY e ripiega su identificatori basati su variabili d’ambiente (KITTY_WINDOW_ID, TMUX_PANE, TERM_SESSION_ID, WT_SESSION).
Le scritture del breadcrumb sono best-effort e non fatali.
Risoluzione del target di ripresa all’avvio (main.ts)
Sezione intitolata “Risoluzione del target di ripresa all’avvio (main.ts)”--resume <valore>
Sezione intitolata “--resume <valore>”createSessionManager(...) gestisce --resume con valore stringa in due modalità:
-
Valore tipo percorso (contiene
/,\\, o termina con.jsonl)- direttamente
SessionManager.open(sessionArg, parsed.sessionDir)
- direttamente
-
Valore prefisso ID
- cerca corrispondenza in
SessionManager.list(cwd, sessionDir)tramiteid.startsWith(sessionArg) - se nessuna corrispondenza locale e
sessionDirnon è forzata, provaSessionManager.listAll() - viene usata la prima corrispondenza (nessun prompt di ambiguità)
- cerca corrispondenza in
Comportamento di corrispondenza cross-progetto:
- se il cwd della sessione trovata differisce dal cwd corrente, il CLI chiede se effettuare un fork nel progetto corrente
- sì ->
SessionManager.forkFrom(...) - no -> lancia un errore (
Session "..." is in another project (...))
Nessuna corrispondenza -> lancia un errore (Session "..." not found.).
--resume (senza valore)
Sezione intitolata “--resume (senza valore)”Gestito dopo la costruzione iniziale del session-manager:
- elenca le sessioni locali con
SessionManager.list(cwd, parsed.sessionDir) - se vuoto: stampa
No sessions founded esce anticipatamente - apre il selettore TUI (
selectSession) - se annullato: stampa
No session selecteded esce anticipatamente - se selezionato:
SessionManager.open(selectedPath)
--continue
Sezione intitolata “--continue”Usa direttamente SessionManager.continueRecent(...) (comportamento breadcrumb-first descritto sopra).
Dettagli interni della selezione tramite picker
Sezione intitolata “Dettagli interni della selezione tramite picker”Picker CLI (src/cli/session-picker.ts)
Sezione intitolata “Picker CLI (src/cli/session-picker.ts)”selectSession(sessions) crea una TUI standalone con SessionSelectorComponent e si risolve esattamente una volta:
- selezione -> risolve il percorso selezionato
- annullamento (Esc) -> risolve
null - uscita forzata (percorso Ctrl+C) -> ferma la TUI e
process.exit(0)
Picker interattivo in-sessione (SelectorController.showSessionSelector)
Sezione intitolata “Picker interattivo in-sessione (SelectorController.showSessionSelector)”Flusso:
- recupera le sessioni dalla directory di sessione corrente tramite
SessionManager.list(currentCwd, currentSessionDir) - monta
SessionSelectorComponentnell’area editor usandoshowSelector(...) - callback:
- selezione -> chiude il selettore e chiama
handleResumeSession(sessionPath) - annullamento -> ripristina l’editor e ri-renderizza
- uscita ->
ctx.shutdown()
- selezione -> chiude il selettore e chiama
Comportamento del componente selettore di sessione
Sezione intitolata “Comportamento del componente selettore di sessione”SessionList supporta:
- navigazione con frecce/pagina
- Invio per selezionare
- Esc per annullare
- Ctrl+C per uscire
- ricerca fuzzy su id sessione/titolo/cwd/primo messaggio/tutti i messaggi/percorso
Comportamento di rendering con lista vuota:
- renderizza un messaggio invece di andare in crash
- Invio su lista vuota non fa nulla (nessun callback)
- Esc/Ctrl+C funzionano comunque
Avvertenza: il testo dell’UI dice Press Tab to view all, ma questo componente attualmente non ha un gestore Tab e il wiring corrente elenca solo le sessioni dell’ambito corrente.
Esecuzione del cambio runtime (AgentSession.switchSession)
Sezione intitolata “Esecuzione del cambio runtime (AgentSession.switchSession)”switchSession(sessionPath) è il percorso principale di cambio in-process.
Ciclo di vita/transizione di stato:
- cattura
previousSessionFile - emette l’evento hook
session_before_switch(reason: "resume", cancellabile) - se annullato -> restituisce
falsesenza cambio - si disconnette dallo stream di eventi dell’agente corrente
- interrompe la generazione/flusso di tool attivo
- svuota i buffer dei messaggi di steering/follow-up/next-turn in coda
- scarica il session writer (
sessionManager.flush()) per persistere le scritture in sospeso sessionManager.setSessionFile(sessionPath)- aggiorna il puntatore al file di sessione
- scrive il breadcrumb del terminale
- carica le voci / migra / risolve blob / reindicizza
- se dati del file mancanti/invalidi: inizializza una nuova sessione a quel percorso e riscrive l’header
- aggiorna
agent.sessionId - ricostruisce il contesto tramite
buildSessionContext() - emette l’evento hook
session_switch(reason: "resume",previousSessionFile) - sostituisce i messaggi dell’agente con il contesto ricostruito
- ripristina il modello predefinito da
sessionContext.models.defaultse disponibile e presente nel registro dei modelli - ripristina il livello di thinking:
- se il branch ha già
thinking_level_change, applica il livello salvato della sessione - altrimenti deriva il livello di thinking predefinito dalle impostazioni, lo limita alla capacità del modello, lo imposta e aggiunge una nuova voce
thinking_level_change
- se il branch ha già
- riconnette i listener dell’agente e restituisce
true
Ricostruzione dello stato UI dopo il cambio interattivo
Sezione intitolata “Ricostruzione dello stato UI dopo il cambio interattivo”SelectorController.handleResumeSession esegue il reset dell’UI attorno a switchSession:
- ferma l’animazione di caricamento
- svuota il container di stato
- svuota l’UI dei messaggi in sospeso e la mappa dei tool in sospeso
- resetta il componente di streaming/riferimenti ai messaggi
- chiama
session.switchSession(...) - svuota il container della chat e ri-renderizza dal contesto della sessione (
renderInitialMessages) - ricarica i todo dagli artefatti della nuova sessione
- mostra
Resumed session
Quindi lo stato visibile della conversazione/todo viene ricostruito dal nuovo file di sessione.
Ripresa all’avvio vs cambio in-sessione
Sezione intitolata “Ripresa all’avvio vs cambio in-sessione”Ripresa all’avvio (--continue, --resume, apertura diretta)
Sezione intitolata “Ripresa all’avvio (--continue, --resume, apertura diretta)”- Il file di sessione viene scelto prima di
createAgentSession(...). sdk.tscostruisceexistingSession = sessionManager.buildSessionContext().- I messaggi dell’agente vengono ripristinati una volta durante la creazione della sessione.
- Modello/thinking vengono selezionati durante la creazione (inclusa la logica di ripristino/fallback).
- La modalità interattiva poi esegue
#restoreModeFromSession()per ri-entrare nello stato di modalità persistito (attualmente plan/plan_paused).
Cambio in-sessione (percorso selettore stile /resume)
Sezione intitolata “Cambio in-sessione (percorso selettore stile /resume)”- Usa
AgentSession.switchSession(...)su unAgentSessiongià in esecuzione. - Messaggi/modello/thinking vengono ricostruiti immediatamente sul posto.
- Vengono emessi gli eventi hook
session_before_switch/session_switch. - Chat/todo dell’UI vengono aggiornati.
- Nessuna chiamata dedicata di ripristino della modalità post-cambio viene effettuata nel flusso del selettore; il comportamento di ri-entrata nella modalità non è simmetrico con
#restoreModeFromSession()all’avvio.
Comportamento in caso di errore e casi limite
Sezione intitolata “Comportamento in caso di errore e casi limite”Percorsi di annullamento
Sezione intitolata “Percorsi di annullamento”- Annullamento picker CLI -> restituisce
null, il chiamante stampaNo session selected, il processo esce anticipatamente. - Annullamento picker interattivo -> editor ripristinato, nessun cambio di sessione.
- Annullamento hook (
session_before_switch) ->switchSession()restituiscefalse.
Percorsi con lista vuota
Sezione intitolata “Percorsi con lista vuota”- CLI
--resume(senza valore): lista vuota stampaNo sessions founded esce. - Selettore interattivo: lista vuota renderizza un messaggio e rimane annullabile.
File di sessione target mancante/invalido
Sezione intitolata “File di sessione target mancante/invalido”Quando si apre/cambia verso un percorso specifico (setSessionFile):
- ENOENT -> trattato come vuoto -> nuova sessione inizializzata a quel percorso esatto e persistita.
- header malformato/invalido (o voci analizzate effettivamente illeggibili) -> trattato come vuoto -> nuova sessione inizializzata e persistita.
Questo è un comportamento di recupero, non un fallimento hard.
Fallimenti hard
Sezione intitolata “Fallimenti hard”Il cambio/apertura può comunque lanciare eccezioni su veri errori di I/O (errori di permessi, errori di riscrittura, ecc.), che vengono propagati ai chiamanti.
Avvertenze sulla corrispondenza per prefisso ID
Sezione intitolata “Avvertenze sulla corrispondenza per prefisso ID”- La corrispondenza ID usa
startsWithe prende la prima corrispondenza nella lista ordinata. - Nessuna UI di disambiguazione se più sessioni condividono lo stesso prefisso.
SessionManager.list(...)esclude le sessioni con zero messaggi, quindi quelle sessioni non sono ripristinabili tramite corrispondenza ID/selettore lista.