- Startseite
- Documentation
- Sitzungen
- Sitzungsoperationen: export, dump, share, fork, resume/continue
Sitzungsoperationen: export, dump, share, fork, resume/continue
Dieses Dokument beschreibt das für Operatoren sichtbare Verhalten der Sitzungsoperationen Export/Teilen/Fork/Fortsetzen, wie sie derzeit implementiert sind.
Implementierungsdateien
Abschnitt betitelt „Implementierungsdateien“../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
Operationsmatrix
Abschnitt betitelt „Operationsmatrix“| Operation | Einstiegspfad | Sitzungsmutation | Sitzungsdatei-Erstellung/-Wechsel | Ausgabeartefakt |
|---|---|---|---|---|
/dump | Interaktiver Slash-Befehl | Nein | Nein | Zwischenablage-Text |
/export [path] | Interaktiver Slash-Befehl | Nein | Nein | HTML-Datei |
--export <session.jsonl> [outputPath] | CLI-Start-Schnellpfad | Keine Laufzeit-Sitzungsmutation | Keine aktive Sitzung; liest Zieldatei | HTML-Datei |
/share | Interaktiver Slash-Befehl | Nein | Nein | Temporäre HTML + Share-URL/Gist |
/fork | Interaktiver Slash-Befehl | Ja (aktive Sitzungsidentität ändert sich) | Erstellt neue Sitzungsdatei und wechselt die aktuelle Sitzung dorthin (nur im persistenten Modus) | Kopiert das Artefaktverzeichnis in den neuen Sitzungsnamensraum, falls vorhanden |
/resume | Interaktiver Slash-Befehl | Ja (aktiver In-Memory-Zustand wird ersetzt) | Wechselt zu ausgewählter bestehender Sitzungsdatei | Keines |
--resume | CLI-Start (Auswahldialog) | Ja, nach Sitzungserstellung | Öffnet ausgewählte bestehende Sitzungsdatei | Keines |
--resume <id|path> | CLI-Start | Ja, nach Sitzungserstellung | Öffnet bestehende Sitzung; projektübergreifender Fall kann in aktuelles Projekt forken | Keines |
--continue | CLI-Start | Ja, nach Sitzungserstellung | Öffnet Terminal-Breadcrumb oder zuletzt verwendete Sitzung; erstellt eine neue, falls keine existiert | Keines |
Export und Dump
Abschnitt betitelt „Export und Dump“/export [outputPath] (interaktiv)
Abschnitt betitelt „/export [outputPath] (interaktiv)“Ablauf:
InputControllerleitet/export...anCommandController.handleExportCommandweiter.- Der Befehl teilt anhand von Leerzeichen und verwendet nur das erste Argument nach
/exportalsoutputPath. AgentSession.exportToHtml()ruftexportSessionToHtml(sessionManager, state, { outputPath, themeName })auf.- Bei Erfolg zeigt die UI den Pfad an und öffnet die Datei im Browser.
Verhaltensdetails:
- Die Argumente
--copy,clipboardundcopywerden explizit mit einem Hinweis auf/dumpabgelehnt. - Der Export bettet den Sitzungs-Header/Einträge/Blatt sowie den aktuellen
systemPromptund Tool-Beschreibungen aus dem Agent-Zustand ein. - Während des Exports werden keine Sitzungseinträge hinzugefügt.
Einschränkung:
- Das Argument-Parsing basiert auf Leerzeichen (
text.split(/\s+/)), sodass Pfade mit Leerzeichen in Anführungszeichen von diesem Befehlspfad nicht als einzelner Pfad erhalten bleiben.
--export <inputSessionFile> [outputPath] (CLI)
Abschnitt betitelt „--export <inputSessionFile> [outputPath] (CLI)“Ablauf in main.ts:
- Wird früh behandelt (vor interaktivem/Sitzungs-Start).
- Ruft
exportFromFile(inputPath, outputPath?)auf. SessionManager.open(inputPath)lädt die Einträge, dann wird HTML generiert und geschrieben.- Der Prozess gibt
Exported to: ...aus und beendet sich.
Verhaltensdetails:
- Eine fehlende Eingabedatei wird als
File not found: <path>angezeigt. - Dieser Pfad erstellt keine
AgentSessionund mutiert keine laufende Sitzung.
/dump (interaktiver Zwischenablage-Export)
Abschnitt betitelt „/dump (interaktiver Zwischenablage-Export)“Ablauf:
CommandController.handleDumpCommand()ruftsession.formatSessionAsText()auf.- Bei leerem String wird
No messages to dump yet.gemeldet. - Andernfalls wird über natives
copyToClipboardin die Zwischenablage kopiert.
Der Dump-Inhalt umfasst:
- System-Prompt
- Aktives Modell/Denk-Level
- Tool-Definitionen + Parameter
- Benutzer-/Assistenten-Nachrichten
- Denkblöcke und Tool-Aufrufe
- Tool-Ergebnisse und Ausführungsblöcke (außer
excludeFromContextBash/Python-Einträge) - Benutzerdefinierte/Hook-/Dateierwähnungs-/Branch-Zusammenfassungs-/Kompaktierungs-Zusammenfassungseinträge
Durch das Dumpen werden keine Sitzungspersistenz-Änderungen vorgenommen.
/share ist ausschließlich interaktiv und beginnt immer mit dem Export der aktuellen Sitzung in eine temporäre HTML-Datei.
Phase 1: Temporärer Export
Abschnitt betitelt „Phase 1: Temporärer Export“- Temporärer Dateipfad:
${os.tmpdir()}/${Snowflake.next()}.html - Verwendet
session.exportToHtml(tmpFile) - Falls der Export fehlschlägt (insbesondere bei In-Memory-Sitzungen), endet das Teilen mit einem Fehler.
Phase 2: Benutzerdefinierter Share-Handler (falls vorhanden)
Abschnitt betitelt „Phase 2: Benutzerdefinierter Share-Handler (falls vorhanden)“loadCustomShare() prüft ~/.xcsh/agent auf den ersten vorhandenen Kandidaten:
share.tsshare.jsshare.mjs
Anforderungen:
- Das Modul muss als Default-Export eine Funktion
(htmlPath) => Promise<CustomShareResult | string | undefined>bereitstellen.
Falls vorhanden und gültig:
- Die UI wechselt in den
Sharing...-Ladezustand. - Ergebnisinterpretation des Handlers:
- String => wird als URL behandelt, angezeigt und geöffnet
- Objekt =>
urlund/odermessagewerden angezeigt;urlwird geöffnet undefined/falsy => generische MeldungSession shared
- Die temporäre Datei wird nach Abschluss gelöscht.
Kritisches Fallback-Verhalten:
- Falls ein benutzerdefinierter Handler existiert, aber das Laden fehlschlägt, gibt der Befehl einen Fehler aus und kehrt zurück.
- Falls ein benutzerdefinierter Handler ausgeführt wird und einen Fehler wirft, gibt der Befehl einen Fehler aus und kehrt zurück.
- In beiden Fehlerfällen wird nicht auf GitHub Gist zurückgefallen.
- Das Gist-Fallback findet nur statt, wenn kein benutzerdefiniertes Share-Skript existiert.
Phase 3: Standard-Gist-Fallback
Abschnitt betitelt „Phase 3: Standard-Gist-Fallback“Nur wenn kein benutzerdefinierter Share-Handler gefunden wird:
- Validiert
gh auth status. - Zeigt
Creating gist...-Ladeanzeige. - Führt
gh gist create --public=false <tmpFile>aus. - Parst die Gist-URL, leitet die Gist-ID ab, erstellt die Vorschau-URL
https://gistpreview.github.io/?<id>. - Zeigt sowohl Vorschau- als auch Gist-URLs an; öffnet die Vorschau.
Abbruch-/Abort-Semantik beim Teilen:
- Der Ladeindikator hat einen
onAbort-Hook, der die Editor-UI wiederherstellt undShare cancelledmeldet. - Dem zugrunde liegenden
gh gist create-Befehl wird in diesem Codepfad kein Abort-Signal übergeben; der Abbruch erfolgt auf UI-Ebene und wird nach Rückkehr des Befehls geprüft.
/fork erstellt eine neue Sitzung aus der aktuellen und wechselt die aktive Sitzungsidentität.
Vorbedingungen und sofortige Prüfungen
Abschnitt betitelt „Vorbedingungen und sofortige Prüfungen“- Falls der Agent streamt, wird
/forkmit einer Warnung abgelehnt. - UI-Status-/Ladeindikatoren werden vor der Operation gelöscht.
Ablauf auf Sitzungsebene
Abschnitt betitelt „Ablauf auf Sitzungsebene“AgentSession.fork():
- Emittiert
session_before_switchmitreason: "fork"(abbrechbar). - Leert ausstehende Schreibvorgänge.
- Ruft
SessionManager.fork()auf. - Kopiert das Artefaktverzeichnis vom alten Sitzungsnamensraum in den neuen Namensraum (Best-Effort; Kopierfehler, die nicht ENOENT sind, werden protokolliert, sind aber nicht fatal).
- Aktualisiert
agent.sessionId. - Emittiert
session_switchmitreason: "fork".
Verhalten von SessionManager.fork():
- Erfordert den persistenten Modus und eine bestehende Sitzungsdatei.
- Erstellt eine neue Sitzungs-ID und einen neuen JSONL-Dateipfad.
- Schreibt den Header mit folgenden Änderungen neu:
- neue
id - neuer Zeitstempel
cwdunverändertparentSessionwird auf die vorherige Sitzungs-ID gesetzt
- neue
- Behält alle Nicht-Header-Einträge in der neuen Datei unverändert bei.
Nicht-persistentes Verhalten
Abschnitt betitelt „Nicht-persistentes Verhalten“- Der In-Memory-Sitzungsmanager gibt
undefinedvonfork()zurück. AgentSession.fork()gibtfalsezurück.- Die UI meldet
Fork failed (session not persisted or cancelled).
Fortsetzen und Weiterführen
Abschnitt betitelt „Fortsetzen und Weiterführen“Interaktives /resume
Abschnitt betitelt „Interaktives /resume“Ablauf:
- Öffnet den Sitzungsauswahldialog, befüllt über
SessionManager.list(currentCwd, currentSessionDir). - Bei Auswahl ruft
SelectorController.handleResumeSession(sessionPath)session.switchSession(sessionPath)auf. - Die UI löscht/baut Chat und Todos neu auf und meldet dann
Resumed session.
Hinweise:
- Dieser Auswahldialog listet nur Sitzungen im aktuellen Sitzungsverzeichnis-Bereich auf.
- Er verwendet keine globale projektübergreifende Suche.
CLI --resume
Abschnitt betitelt „CLI --resume“--resume (ohne Wert)
Abschnitt betitelt „--resume (ohne Wert)“main.tslistet Sitzungen für das aktuelle cwd/sessionDir auf und öffnet den Auswahldialog.- Der ausgewählte Pfad wird mit
SessionManager.open(selectedPath)vor der Sitzungserstellung geöffnet.
--resume <value>
Abschnitt betitelt „--resume <value>“Auflösungsreihenfolge in createSessionManager():
- Falls der Wert wie ein Pfad aussieht (
/,\oder.jsonl), direkt öffnen. - Andernfalls als ID-Präfix behandeln:
- im aktuellen Bereich suchen (
SessionManager.list(cwd, sessionDir)) - falls nicht gefunden und kein explizites
sessionDir, global suchen (SessionManager.listAll())
- im aktuellen Bereich suchen (
Verhalten bei projektübergreifendem ID-Match:
- Falls das cwd der gefundenen Sitzung vom aktuellen cwd abweicht, fragt die CLI:
Session found in different project ... Fork into current directory? [y/N]
- Bei Ja:
SessionManager.forkFrom(match.path, cwd, sessionDir)erstellt eine neue lokale geforkte Datei. - Bei Nein/Non-TTY-Standard: Der Befehl gibt einen Fehler aus.
CLI --continue
Abschnitt betitelt „CLI --continue“SessionManager.continueRecent(cwd, sessionDir):
- Löst das Sitzungsverzeichnis für das aktuelle cwd auf.
- Liest zuerst den Terminal-spezifischen Breadcrumb.
- Fällt auf die zuletzt geänderte Sitzungsdatei zurück.
- Öffnet die gefundene Sitzung; falls keine existiert, wird eine neue Sitzung erstellt.
Dies ist ein reines Start-Verhalten; es gibt keinen interaktiven /continue-Slash-Befehl.
Wie der Sitzungswechsel den Laufzeitzustand tatsächlich mutiert
Abschnitt betitelt „Wie der Sitzungswechsel den Laufzeitzustand tatsächlich mutiert“AgentSession.switchSession(sessionPath) führt den Laufzeitübergang durch, der von Resume-ähnlichen Operationen verwendet wird:
- Emittiert
session_before_switchmitreason: "resume"undtargetSessionFile(abbrechbar). - Trennt die Agent-Event-Subscription und bricht laufende Arbeit ab.
- Löscht ausstehende Steering-/Follow-up-/Next-Turn-Nachrichten.
- Leert ausstehende Schreibvorgänge des Sitzungsmanagers.
sessionManager.setSessionFile(sessionPath)und aktualisiertagent.sessionId.- Erstellt den Sitzungskontext aus den geladenen Einträgen.
- Emittiert
session_switchmitreason: "resume". - Ersetzt die Agent-Nachrichten aus dem Kontext.
- Stellt das Modell wieder her (falls in der aktuellen Registry verfügbar).
- Stellt das Denk-Level wieder her oder initialisiert es.
- Verbindet die Agent-Event-Subscription erneut.
Durch switchSession() selbst wird keine neue Sitzungsdatei erstellt.
Event-Emissionen und Abbruchpunkte
Abschnitt betitelt „Event-Emissionen und Abbruchpunkte“Switch/Fork-Lebenszyklus-Hooks
Abschnitt betitelt „Switch/Fork-Lebenszyklus-Hooks“Für newSession, fork und switchSession:
- Vorher-Event:
session_before_switch- Gründe:
new,fork,resume - Abbrechbar durch Rückgabe von
{ cancel: true }
- Gründe:
- Nachher-Event:
session_switch- Gleicher Grund-Satz
- Enthält
previousSessionFile
ExtensionRunner.emit() kehrt beim ersten abbrechenden Vorher-Event-Ergebnis frühzeitig zurück.
onSession-Verhalten benutzerdefinierter Tools
Abschnitt betitelt „onSession-Verhalten benutzerdefinierter Tools“Die SDK-Bridge leitet Extension-Sitzungsevents an onSession-Callbacks benutzerdefinierter Tools weiter:
session_switch->onSession({ reason: "switch", previousSessionFile })session_branch->reason: "branch"session_start->reason: "start"session_tree->reason: "tree"session_shutdown->reason: "shutdown"
Diese Callbacks sind observational; sie brechen keinen Switch/Fork ab.
Weitere für dieses Dokument relevante Abbruchoberflächen
Abschnitt betitelt „Weitere für dieses Dokument relevante Abbruchoberflächen“/forkwird während des Streamings blockiert (der Benutzer muss die aktuelle Antwort erst abwarten/abbrechen).- Der
/resume-Auswahldialog kann vom Benutzer durch Schließen des Dialogs abgebrochen werden. - Projektübergreifendes
--resume <id>kann durch Ablehnung der Fork-Aufforderung abgebrochen werden. /sharehat einen UI-Abbruchpfad (Share cancelled) für den Gist-Ablauf; es verdrahtet keine Prozess-Kill-Semantik fürgh gist createin diesem Codepfad.
Nicht-persistentes (In-Memory) Sitzungsverhalten
Abschnitt betitelt „Nicht-persistentes (In-Memory) Sitzungsverhalten“Wenn der Sitzungsmanager mit SessionManager.inMemory() (--no-session) erstellt wird:
- Der Sitzungsdateipfad ist nicht vorhanden.
/exportund/sharescheitern mitCannot export in-memory session to HTML(weitergeleitet an die Befehlsfehler-UI)./forkscheitert, daSessionManager.fork()Persistenz erfordert./dumpfunktioniert weiterhin, da es den In-Memory-Agent-Zustand serialisiert.- CLI-Resume/Continue-Semantiken werden umgangen, wenn
--no-sessiongesetzt ist, da die Manager-Erstellung sofort In-Memory zurückgibt.
Bekannte Implementierungseinschränkungen (Stand aktueller Code)
Abschnitt betitelt „Bekannte Implementierungseinschränkungen (Stand aktueller Code)“SelectorController.handleResumeSession()prüft nicht das boolesche Ergebnis vonsession.switchSession(...); ein durch einen Hook abgebrochener Wechsel kann dennoch den UI-Pfad “Resumed session” (Neuzeichnen/Status) durchlaufen.- Fehler beim benutzerdefinierten Teilen bei
/sharefallen nicht auf das Standard-Gist-Fallback zurück; sie beenden den Befehl mit einem Fehler. - Die Argument-Tokenisierung bei
/exportist vereinfacht und erhält keine Pfade mit Leerzeichen in Anführungszeichen.