- Accueil
- Documentation
- Sessions
- Opérations de session : export, dump, share, fork, resume/continue
Opérations de session : export, dump, share, fork, resume/continue
Ce document décrit le comportement visible par l’opérateur pour les opérations d’exportation, de partage, de duplication et de reprise de session telles qu’elles sont actuellement implémentées.
Fichiers d’implémentation
Section intitulée « Fichiers d’implémentation »../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
Matrice des opérations
Section intitulée « Matrice des opérations »| Opération | Chemin d’entrée | Mutation de session | Création/changement de fichier de session | Artefact de sortie |
|---|---|---|---|---|
/dump | Commande slash interactive | Non | Non | Texte dans le presse-papiers |
/export [path] | Commande slash interactive | Non | Non | Fichier HTML |
--export <session.jsonl> [outputPath] | Chemin rapide au démarrage CLI | Pas de mutation de session active | Pas de session active ; lit le fichier cible | Fichier HTML |
/share | Commande slash interactive | Non | Non | HTML temporaire + URL de partage/gist |
/fork | Commande slash interactive | Oui (l’identité de la session active change) | Crée un nouveau fichier de session et bascule la session courante vers celui-ci (mode persistant uniquement) | Copie le répertoire d’artefacts vers le nouveau espace de noms de session si présent |
/resume | Commande slash interactive | Oui (l’état en mémoire actif est remplacé) | Bascule vers le fichier de session existant sélectionné | Aucun |
--resume | Démarrage CLI (sélecteur) | Oui après création de session | Ouvre le fichier de session existant sélectionné | Aucun |
--resume <id|path> | Démarrage CLI | Oui après création de session | Ouvre une session existante ; le cas multi-projet peut créer une duplication dans le projet courant | Aucun |
--continue | Démarrage CLI | Oui après création de session | Ouvre le fil de progression du terminal ou la session la plus récente ; en crée une nouvelle si aucune n’existe | Aucun |
Exportation et vidage
Section intitulée « Exportation et vidage »/export [outputPath] (interactif)
Section intitulée « /export [outputPath] (interactif) »Flux :
InputControllerroute/export...versCommandController.handleExportCommand.- La commande divise sur les espaces blancs et n’utilise que le premier argument après
/exportcommeoutputPath. AgentSession.exportToHtml()appelleexportSessionToHtml(sessionManager, state, { outputPath, themeName }).- En cas de succès, l’interface affiche le chemin et ouvre le fichier dans le navigateur.
Détails de comportement :
- Les arguments
--copy,clipboardetcopysont explicitement rejetés avec un avertissement invitant à utiliser/dump. - L’exportation intègre l’en-tête de session, les entrées, la feuille ainsi que le
systemPromptcourant et les descriptions d’outils issues de l’état de l’agent. - Aucune entrée de session n’est ajoutée pendant l’exportation.
Mise en garde :
- L’analyse des arguments est basée sur les espaces (
text.split(/\s+/)), donc les chemins entre guillemets contenant des espaces ne sont pas préservés comme un seul chemin par ce chemin de commande.
--export <inputSessionFile> [outputPath] (CLI)
Section intitulée « --export <inputSessionFile> [outputPath] (CLI) »Flux dans main.ts :
- Traité en amont (avant le démarrage interactif/de session).
- Appelle
exportFromFile(inputPath, outputPath?). SessionManager.open(inputPath)charge les entrées, puis le HTML est généré et écrit.- Le processus affiche
Exported to: ...et se termine.
Détails de comportement :
- Un fichier d’entrée manquant génère
File not found: <path>. - Ce chemin ne crée pas d’
AgentSessionet ne mute aucune session en cours d’exécution.
/dump (exportation interactive vers le presse-papiers)
Section intitulée « /dump (exportation interactive vers le presse-papiers) »Flux :
CommandController.handleDumpCommand()appellesession.formatSessionAsText().- Si la chaîne est vide, signale
No messages to dump yet. - Sinon, copie dans le presse-papiers via le
copyToClipboardnatif.
Le contenu du vidage inclut :
- Le prompt système
- Le modèle actif et le niveau de réflexion
- Les définitions d’outils et leurs paramètres
- Les messages utilisateur/assistant
- Les blocs de réflexion et les appels d’outils
- Les résultats d’outils et les blocs d’exécution (sauf les entrées bash/python
excludeFromContext) - Les entrées de type personnalisé, hook, mention de fichier, résumé de branche et résumé de compaction
Aucun changement de persistance de session n’est effectué par le vidage.
/share est uniquement interactif et commence toujours par exporter la session courante vers un fichier HTML temporaire.
Phase 1 : export temporaire
Section intitulée « Phase 1 : export temporaire »- Chemin du fichier temporaire :
${os.tmpdir()}/${Snowflake.next()}.html - Utilise
session.exportToHtml(tmpFile) - Si l’exportation échoue (notamment pour les sessions en mémoire), le partage se termine avec une erreur.
Phase 2 : gestionnaire de partage personnalisé (si présent)
Section intitulée « Phase 2 : gestionnaire de partage personnalisé (si présent) »loadCustomShare() vérifie ~/.xcsh/agent pour le premier candidat existant :
share.tsshare.jsshare.mjs
Prérequis :
- Le module doit exporter par défaut une fonction
(htmlPath) => Promise<CustomShareResult | string | undefined>.
Si présent et valide :
- L’interface passe à l’état de chargement
Sharing.... - Interprétation du résultat du gestionnaire :
- chaîne => traitée comme URL, affichée et ouverte
- objet =>
urlet/oumessageaffichés ;urlouverte undefined/falsy =>Session sharedgénérique
- Le fichier temporaire est supprimé après l’exécution.
Comportement de repli critique :
- Si le gestionnaire personnalisé existe mais que son chargement échoue, la commande génère une erreur et retourne.
- Si le gestionnaire personnalisé s’exécute et lève une exception, la commande génère une erreur et retourne.
- Dans les deux cas d’échec, il ne se rabat pas sur le gist GitHub.
- Le repli sur le gist n’intervient que lorsqu’aucun script de partage personnalisé n’est trouvé.
Phase 3 : repli par défaut sur le gist
Section intitulée « Phase 3 : repli par défaut sur le gist »Uniquement lorsqu’aucun gestionnaire de partage personnalisé n’est trouvé :
- Valide
gh auth status. - Affiche le chargement
Creating gist.... - Exécute
gh gist create --public=false <tmpFile>. - Analyse l’URL du gist, en dérive l’identifiant, construit l’URL de prévisualisation
https://gistpreview.github.io/?<id>. - Affiche à la fois les URLs de prévisualisation et du gist ; ouvre la prévisualisation.
Sémantique d’annulation/abandon dans le partage :
- Le chargeur dispose d’un hook
onAbortqui restaure l’interface de l’éditeur et signaleShare cancelled. - La commande
gh gist createsous-jacente ne reçoit pas de signal d’abandon dans ce chemin de code ; l’annulation est au niveau de l’interface et est vérifiée après le retour de la commande.
Duplication (Fork)
Section intitulée « Duplication (Fork) »/fork crée une nouvelle session à partir de la session courante et change l’identité de la session active.
Préconditions et vérifications immédiates
Section intitulée « Préconditions et vérifications immédiates »- Si l’agent est en train de diffuser,
/forkest rejeté avec un avertissement. - Les indicateurs d’état/chargement de l’interface sont effacés avant l’opération.
Flux au niveau de la session
Section intitulée « Flux au niveau de la session »AgentSession.fork() :
- Émet
session_before_switchavecreason: "fork"(annulable). - Vide les écritures en attente.
- Appelle
SessionManager.fork(). - Copie le répertoire d’artefacts de l’ancien espace de noms de session vers le nouveau (au mieux ; les échecs de copie autres que ENOENT sont journalisés, pas fatals).
- Met à jour
agent.sessionId. - Émet
session_switchavecreason: "fork".
Comportement de SessionManager.fork() :
- Requiert le mode persistant et un fichier de session existant.
- Crée un nouvel identifiant de session et un nouveau chemin de fichier JSONL.
- Réécrit l’en-tête avec :
- nouveau
id - nouvel horodatage
cwdinchangéparentSessiondéfini sur l’identifiant de la session précédente
- nouveau
- Conserve toutes les entrées non-en-tête inchangées dans le nouveau fichier.
Comportement non persistant
Section intitulée « Comportement non persistant »- Le gestionnaire de session en mémoire retourne
undefineddepuisfork(). AgentSession.fork()retournefalse.- L’interface signale
Fork failed (session not persisted or cancelled).
Reprise et continuation
Section intitulée « Reprise et continuation »/resume interactif
Section intitulée « /resume interactif »Flux :
- Ouvre le sélecteur de session alimenté via
SessionManager.list(currentCwd, currentSessionDir). - Lors de la sélection,
SelectorController.handleResumeSession(sessionPath)appellesession.switchSession(sessionPath). - L’interface efface/reconstruit le chat et les tâches, puis signale
Resumed session.
Notes :
- Ce sélecteur ne liste que les sessions dans la portée du répertoire de session courant.
- Il n’utilise pas la recherche globale multi-projet.
CLI --resume
Section intitulée « CLI --resume »--resume (sans valeur)
Section intitulée « --resume (sans valeur) »main.tsliste les sessions pour le répertoire de travail/session courant et ouvre le sélecteur.- Le chemin sélectionné est ouvert avec
SessionManager.open(selectedPath)avant la création de session.
--resume <value>
Section intitulée « --resume <value> »Ordre de résolution dans createSessionManager() :
- Si la valeur ressemble à un chemin (
/,\, ou.jsonl), ouvrir directement. - Sinon, traiter comme préfixe d’identifiant :
- recherche dans la portée courante (
SessionManager.list(cwd, sessionDir)) - si non trouvé et sans
sessionDirexplicite, recherche globale (SessionManager.listAll())
- recherche dans la portée courante (
Comportement de correspondance d’identifiant multi-projet :
- Si le répertoire de travail de la session trouvée diffère du répertoire de travail courant, la CLI demande :
Session found in different project ... Fork into current directory? [y/N]
- En cas de oui :
SessionManager.forkFrom(match.path, cwd, sessionDir)crée un nouveau fichier dupliqué local. - En cas de non/sans TTY par défaut : la commande génère une erreur.
CLI --continue
Section intitulée « CLI --continue »SessionManager.continueRecent(cwd, sessionDir) :
- Résout le répertoire de session pour le répertoire de travail courant.
- Lit d’abord le fil de progression étendu au terminal.
- Se rabat sur le fichier de session modifié le plus récemment.
- Ouvre la session trouvée ; si aucune n’existe, crée une nouvelle session.
Il s’agit d’un comportement au démarrage uniquement ; il n’existe pas de commande slash interactive /continue.
Comment le changement de session mute réellement l’état d’exécution
Section intitulée « Comment le changement de session mute réellement l’état d’exécution »AgentSession.switchSession(sessionPath) effectue la transition d’exécution utilisée par les opérations de type reprise :
- Émet
session_before_switchavecreason: "resume"ettargetSessionFile(annulable). - Déconnecte l’abonnement aux événements de l’agent et abandonne le travail en cours.
- Efface les messages de pilotage, de suivi et de tour suivant en file d’attente.
- Vide les écritures du gestionnaire de session courant.
sessionManager.setSessionFile(sessionPath)et met à jouragent.sessionId.- Construit le contexte de session à partir des entrées chargées.
- Émet
session_switchavecreason: "resume". - Remplace les messages de l’agent à partir du contexte.
- Restaure le modèle (s’il est disponible dans le registre courant).
- Restaure ou initialise le niveau de réflexion.
- Reconnecte l’abonnement aux événements de l’agent.
Aucun nouveau fichier de session n’est créé par switchSession() lui-même.
Émissions d’événements et points d’annulation
Section intitulée « Émissions d’événements et points d’annulation »Hooks du cycle de vie de changement/duplication
Section intitulée « Hooks du cycle de vie de changement/duplication »Pour newSession, fork et switchSession :
- Événement avant :
session_before_switch- raisons :
new,fork,resume - annulable en retournant
{ cancel: true }
- raisons :
- Événement après :
session_switch- même ensemble de raisons
- inclut
previousSessionFile
ExtensionRunner.emit() retourne tôt au premier résultat d’événement avant annulant.
Comportement onSession des outils personnalisés
Section intitulée « Comportement onSession des outils personnalisés »Le pont SDK transmet les événements de session d’extension aux callbacks onSession des outils personnalisés :
session_switch->onSession({ reason: "switch", previousSessionFile })session_branch->reason: "branch"session_start->reason: "start"session_tree->reason: "tree"session_shutdown->reason: "shutdown"
Ces callbacks sont observationnels ; ils n’annulent pas le changement/la duplication.
Autres surfaces d’annulation pertinentes pour ce document
Section intitulée « Autres surfaces d’annulation pertinentes pour ce document »/forkest bloqué pendant la diffusion (l’utilisateur doit attendre ou abandonner la réponse courante en premier).- Le sélecteur
/resumepeut être annulé par l’utilisateur en fermant le sélecteur. --resume <id>multi-projet peut être annulé en refusant l’invite de duplication./sharedispose d’un chemin d’abandon dans l’interface (Share cancelled) pour le flux gist ; il ne câble pas la sémantique de fin de processus pourgh gist createdans ce chemin de code.
Comportement des sessions non persistantes (en mémoire)
Section intitulée « Comportement des sessions non persistantes (en mémoire) »Lorsque le gestionnaire de session est créé avec SessionManager.inMemory() (--no-session) :
- Le chemin du fichier de session est absent.
/exportet/shareéchouent avecCannot export in-memory session to HTML(propagé vers l’interface d’erreur de commande)./forkéchoue carSessionManager.fork()requiert la persistance./dumpfonctionne toujours car il sérialise l’état de l’agent en mémoire.- Les sémantiques de reprise/continuation CLI sont contournées si
--no-sessionest défini, car la création du gestionnaire retourne immédiatement une instance en mémoire.
Mises en garde d’implémentation connues (selon le code actuel)
Section intitulée « Mises en garde d’implémentation connues (selon le code actuel) »SelectorController.handleResumeSession()ne vérifie pas le résultat booléen desession.switchSession(...); un changement annulé par un hook peut tout de même progresser vers le chemin de repeint/statut de l’interface « Resumed session ».- Les échecs de partage personnalisé dans
/sharene se dégradent pas vers le repli par défaut sur le gist ; ils terminent la commande avec une erreur. - La tokenisation des arguments de
/exportest simpliste et ne préserve pas les chemins entre guillemets contenant des espaces.