-
Sitzungsstatus, Ungelesen-Markierungen und die Frage, ob eine Sitzung noch läuft, entscheidet jetzt das Backend, und alle Clients sehen dieselbe Antwort. Bisher rechnete sich das jeder Client aus dem zusammen, was er zufällig mitbekam, „ungelesen“ hieß also in Wahrheit „in diesem Fenster nicht gelesen“: Wer eine Sitzung im Browser las, ließ die Kopie auf dem Desktop ungelesen, und der dynamische Statusfilter schob diese Zeile immer wieder in die gemeinsame Liste zurück, wo selbst „Status aktualisieren“ sie nicht mehr herausbekam. Statusereignisse wurden außerdem erst registriert, sobald ein Client selbst eine Sitzung gestartet hatte, sodass ein frisch verbundener Browser nur für die von ihm geöffneten Sitzungen Punkte zeigte und für alle übrigen gar nichts. Das Backend führt jetzt pro Sitzung einen maßgeblichen Datensatz — den Agenten, seinen Zustand, ob sein Prozess lebt, und das Ungelesen-Kennzeichen —, beantwortet beim Verbinden oder Wiederverbinden eine Sammelabfrage und verteilt jede Änderung an alle. Die Clients melden, was sie beobachten; die Schlüsse zieht das Backend. Wer eine Sitzung auf dem Telefon liest, löscht damit die Markierung auf dem Desktop, ein frisch verbundener Browser zeigt die richtigen Punkte auch für Sitzungen, die er nie geöffnet hat, und die Schlichtungsregeln, die bisher im Frontend lagen, sind mitsamt ihren Begründungen und ihren Tests mit umgezogen: Ein hook, der einmal gemeldet hat, sperrt alles aus, was aus roher Ausgabe erschlossen wurde; fortlaufende Ausgabe bedeutet nur dann „arbeitet“, wenn die Sitzung einen Agenten hat, nicht Codex ist und noch keine maßgebliche Meldung vorliegt; und eine Sperrfrist von 1200 ms verhindert, dass eine gerade gestartete Aufgabe von einem unmittelbar hinterherkommenden Abschlussereignis wieder abgeräumt wird. Die Ausnahme ist das Auslesen des Bildschirms, denn dafür braucht es das gerenderte Zeichenraster, und das gibt es nur in einem Client: Derjenige Client, dem die Terminalgröße gehört, meldet, was er gelesen hat, und das Backend entscheidet, ob es die Meldung annimmt — von jedem anderen Client wird sie abgelehnt. Geht dabei etwas schief, gibt vlx-arbitration in localStorage auf frontend gesetzt die Schlichtung an die alte Frontend-Kette zurück.
-
Der Neustart einer Sitzung schließt ihren Tab auf dem anderen Client nicht mehr. pty://killed trug keinerlei Nutzdaten, deshalb konnte die Gegenseite einen Neustart nicht von einem Schließen unterscheiden: Sie behandelte alles als Schließen, entfernte den Bereich und spiegelte dieses Layout dann zurück. Das Ereignis sagt jetzt, welcher Client den Prozess beendet hat und warum, sodass ein Neustart den Bereich stehen lässt und auf den neuen Prozess wartet. Ein fehlender oder unbekannter Grund gilt weiterhin als Schließen — einen Bereich für eine Sitzung offen zu lassen, die nie wiederkommt, hinterlässt ein totes Terminal auf dem Bildschirm, und das ist schlimmer, als einen Bereich zu schließen, der gerade neu starten wollte.
-
Ein Browser, der sich mit einem Desktop verbindet, der gerade seinen Arbeitsbereich wiederhergestellt hat, startet nicht mehr jede Sitzung wirklich. Beim Wiederherstellen eines Arbeitsbereichs werden Platzhalterkarten gezeichnet, statt Prozesse zu starten, doch diese Entscheidung existierte nur auf dem Desktop; der Browser folgte dem gespiegelten Layout, konnte „läuft nicht“ nicht von „läuft, wurde hier nur nie geöffnet“ unterscheiden und hängte die Terminals ein — und ein Terminal einzuhängen heißt, es zu starten. Ein Blatt, das mit dem Layout eines anderen ankommt, zeigt jetzt eine Platzhalterkarte, wenn das Backend sagt, dass kein Prozess dahintersteht. Eine Sitzung selbst zu öffnen bleibt die Absicht, sie zu starten, und ein Terminal, auf das Sie gerade schauen, wird nie durch eine Karte ersetzt, wenn sein Prozess endet — Sie wollen vielleicht noch lesen, was es ausgegeben hat.
-
Eine geänderte Einstellung erreicht die anderen Clients sofort. Die maßgeblichen Einstellungen lagen immer schon im Backend, aber es änderte sie, ohne jemandem Bescheid zu sagen, sodass der andere Client es erst beim nächsten Start erfuhr. Über eine Fernverbindung ist das mehr als eine unterschiedliche Anzeige: „Statusfilter dynamisch erweitern“ auf dem einen Client abzuschalten brachte gar nichts, solange ein anderer weiter Zeilen in die gemeinsame Liste schob, und der Client mit der kleineren Grenze für gleichzeitig aktive Tabs räumte allen anderen die Hintergrund-Tabs weg. Beim Schreiben einer Einstellung wird jetzt verteilt, welcher Schlüssel sich geändert hat, und jeder Client liest ihn über denselben Weg neu ein, den er auch beim Start benutzt — die Regeln, die geschützte Werte vor Fernaufrufern verbergen, gelten also weiterhin, und die Verteilung trägt ausschließlich Schlüsselnamen, niemals Werte. Telefone, die bisher weder Einstellungen sendeten noch empfingen, machen jetzt ebenfalls mit.
-
Ein Browser wartet auf das gespiegelte Layout, bevor er sein eigenes wiederherstellt. Ein Fernfenster hat zwei Layout-Quellen — das in seinem eigenen localStorage und das, was der Host im Spiegelmodus schickt —, und was zuerst ankam, wurde vom jeweils anderen überschrieben. Das lokale zuerst aufzubauen kostete mehr als ein Flackern: Ein Terminal-Blatt einzuhängen startet einen echten Prozess, und bei einer Sitzung, deren Prozess längst weg war, hieß das, eine Shell zu starten, die nie jemand ansehen würde — und die dann auch blieb, denn ein Browser hängt seine Terminals nur ab, statt sie zu beenden. Der Browser wartet jetzt höchstens zwei Sekunden darauf, dass sich der erste Abgleich setzt, bevor er überhaupt etwas wiederherstellt; ist das Backend langsam oder nicht erreichbar, fällt er auf das lokale Layout zurück, statt vor einem leeren Fenster zu sitzen. Telefone und jeder Client mit abgeschaltetem Spiegeln werden sofort durchgelassen.
-
Eine SSH-Verbindung kann den Spiegelmodus für den Dienst einschalten, den sie startet. Der Schalter sitzt im Fernzugriffs-Panel, aber SSH startet auf dem entfernten Rechner einen Dienst ohne Oberfläche, und dort gibt es kein Panel zum Anklicken. Wer beim Klick auf „Fernverbindung herstellen“ die Wahltaste hält, bekommt im SSH-Formular jetzt ein Kästchen „Oberfläche über alle Clients spiegeln“, standardmäßig aus. Der Wert reist mit der Verbindung mit und lebt nur im Speicher des Dienstes, statt in die Datenbank des entfernten Rechners geschrieben zu werden: Wer zusätzlich die Datenbank des entfernten Desktops mitbenutzt, soll mit einer SSH-Verbindung nicht stillschweigend einen Schalter in fremden Panels umlegen. Die Wahl wird pro Host gemerkt, wer denselben Rechner also aus der Liste holt, bekommt sie zurück. Einen bereits laufenden Dienst weiterzuverwenden setzt jetzt voraus, dass Version, Datenmodus und Spiegelmodus alle übereinstimmen — weicht eines der drei ab, wird der alte Dienst ersetzt, was die darauf laufenden Sitzungen beendet; deshalb liegt diese Option zusammen mit dem Datenbankschalter hinter der Wahltaste.
-
Ein Client, der gespiegelt wird, sagt das auch. Tabs und Teilungen ordneten sich auf einem folgenden Client bisher neu, ohne dass irgendetwas auf dem Bildschirm erklärt hätte, woher die Änderung kam. Die Titelleiste trägt jetzt ein Badge „Gespiegelt“, mit einer Erklärung beim Überfahren mit der Maus. Der Host bekommt keines — er hat ja den Schalter.
-
Dateien lassen sich zwischen Ihrem Rechner und dem Rechner mit dem Terminal übertragen. Der Fernzugriff zeigte die Dateien der Gegenseite, bot aber keinen Weg, eine davon zu holen oder eine hinzulegen — es blieb nur ein Shell-Befehl im Terminal. Das Dateien-Panel bietet nun „Download“ im Kontextmenü einer Datei und „Upload“ in der Kopfzeile; wer Dateien vom Schreibtisch auf eine Ordnerzeile zieht, schickt sie ebenfalls dorthin. Beide Richtungen laufen über dieselbe authentifizierte Verbindung wie alles andere, funktionieren also im Browser im lokalen Netz, auf dem Telefon und im Fernverbindungsfenster gleichermaßen. Übertragen wird in Blöcken, mit einer Fortschrittsliste unter dem Baum, die auch dann weiterläuft, wenn Sie ein anderes Panel ansehen. „Download“ ist ein gewöhnlicher Download-Link, um den sich der Download-Manager des Browsers kümmert: Er schreibt fortlaufend auf die Festplatte, zeigt Tempo und Restzeit an und lässt sich anhalten und fortsetzen — bei jeder Dateigröße und in jedem Browser, auch auf dem Telefon. Der Link trägt ein Ticket, das für genau diese eine Datei ausgestellt wurde und nach wenigen Minuten verfällt, denn dieser Server hält Anmeldedaten in einem Header, und ein Browser, der einen Link abruft, sendet keinen. Ein Upload schreibt zunächst unter einem temporären Namen und wird erst nach vollständiger Übertragung umbenannt — eine abgebrochene Übertragung hinterlässt also nie eine halb geschriebene Datei dort, wo eine ganze stehen sollte; ein bereits vergebener Name wird abgelehnt, bevor etwas übertragen wird. Uploads zeigen Tempo und Restzeit an und überstehen einen Verbindungsabbruch: Ein fehlgeschlagener Block wird rund eine Minute lang mit wachsenden Pausen erneut versucht, wobei jedes Mal beim Server nachgefragt wird, wie weit die temporäre Datei tatsächlich gekommen ist, statt einen möglicherweise längst angekommenen Block noch einmal zu senden. Auch beim Aufgeben bleiben diese Bytes erhalten: Dieselbe Datei erneut auf denselben Ordner gezogen macht dort weiter, wo es aufgehört hat, sogar nach einem Neuladen — nur Abbrechen verwirft die Teildatei.
-
Antigravity- und Copilot-Sitzungen werden nach ihrer ersten Nachricht benannt. Beide fehlten in der automatischen Umbenennung, sodass in der Seitenleiste Reihen von „Antigravity 1, 2, 3“ standen. Antigravitys hook-Ereignisse enthalten überhaupt keinen Nutzertext, nur eine Unterhaltungs-ID und einen Pfad zum Transkript, deshalb wird die erste Nachricht stattdessen aus dem Transkript gelesen; der Metadatenblock, der darauf folgt, bleibt aus dem Titel heraus. Copilots Ereignisse enthalten ebenso wenig einen Ereignisnamen und werden an ihrer Form auseinandergehalten, deshalb gilt ein Rumpf mit einem prompt und ohne Werkzeugnamen jetzt als Absenden — womit der prompt, mit dem eine Sitzung gestartet wird, und Werkzeugaufrufe korrekt draußen bleiben.
-
Eine Antigravity-Sitzung öffnet sich wieder mit ihrer Historie. Zum Fortsetzen braucht es die Unterhaltungs-ID, und der Parser, der eine Sitzungs-ID aus den Startargumenten herausliest, kannte Antigravitys Schreibweise dafür nicht — --conversation=<id> hatte also nie einen Anker, auf den es hätte zeigen können, und jede wieder geöffnete Sitzung kam leer zurück.
-
vspawn --yes startet eine Unteraufgabe ohne die Bestätigungskarte. Wer „vor dem Starten bestätigen“ eingeschaltet lässt, musste sich in einem Durchlauf durch die Karte jeder einzelnen Untersitzung klicken. Das Flag — auch als -y oder --no-confirm zu schreiben — überspringt die Karte für diesen einen Aufruf und startet die Sitzung mit den Standardeinstellungen. An der Einstellung selbst ändert es nichts, der nächste Start ohne das Flag fragt also wieder nach.
-
Das Modellfeld auf der Karte für Unteraufgaben nimmt alles an, was Sie eintippen. Es war ein reines Aufklappmenü, es ließen sich also nur die Modelle aus der Liste wählen — und ein Agent versteht weit mehr Bezeichner als die: datierte Namen wie claude-opus-4-6, Namen mit Herstellerpräfix, lokal eingerichtete Aliasse. Jetzt ist es ein Textfeld, an dem die bekannten Modelle als Abkürzung in einem Aufklappmenü daneben hängen. Die Liste ist ein Vorschlag, keine Positivliste: Übergeben wird, was Sie eintippen, ein leeres Feld heißt gar kein --model, und die Liste filtert beim Tippen mit und klappt weg, sobald ein eigener Bezeichner zu nichts mehr passt.
-
Ein Aufklappmenü, überall dasselbe. Die Aufklappmenüs der App waren mehr als ein Dutzend Mal aus demselben Code kopiert worden und dann auseinandergelaufen: drei Panel-Hintergründe, vier Schatten, drei Hover-Farben, Auslöser mit 26, 28 und 32 Pixeln Höhe und Haken an ausgewählten Zeilen, die nur eine Mehrfachauswahl braucht. Eine einzige Komponente trägt jetzt die Branch-Auswahl beim Mergen, die Auswahl von Sprache, Standard-Shell und Schrift in den Einstellungen, die Agentenauswahl, die Worktree-Dialoge, den Agententyp bei neuen und wiederhergestellten Sitzungen und das letzte native Auswahlfeld im Formulardialog. Sie bringt außerdem eine Tastaturbedienung mit, die keines von ihnen hatte: Pfeiltasten zum Bewegen, Enter zum Auswählen, Escape zum Schließen, ohne den Dialog dahinter mitzuschließen, Pos1 und Ende zum Springen. Die beiden Menüs in der Statusleiste verhalten sich wie bisher, und der Statusfilter in der Seitenleiste behält seine Haken, denn er ist wirklich eine Mehrfachauswahl.
-
Das Passwortfeld im Fernzugriffs-Panel lässt sich anzeigen. Es war ein nacktes Passwortfeld, man konnte also nicht sehen, was man getippt hatte; den Augen-Knopf gab es zwar, aber nur innerhalb der Datei des Verbindungs-Panels. Beide teilen sich jetzt eine Komponente, und der Anzeigezustand wird zurückgesetzt, sobald das Panel schließt.
-
Die IP-Auswahl sieht nicht mehr wie ein Bedienelement des Systems aus. Sie war ein natives Auswahlfeld, und WKWebView steckt so etwas in Systemoptik, die auf einem dunklen Panel schlecht sitzt — dieselbe Klage wie bei den oben ersetzten Aufklappmenüs. Sie verwendet jetzt die gemeinsame Komponente, und ihre Beschriftung ist auf „IP“ verkürzt, weil der Text daneben ohnehin sagt, wofür sie da ist.
-
Die Suche nach Updates fragt jetzt jedes Mal wirklich beim Server nach. Ein durchlaufender Client war auf die erste Version festgenagelt, die er je gesehen hatte: Wer 0.1.101 gefunden hatte, bekam auch nach dem Erscheinen von 0.1.104 weiterhin 0.1.101 angeboten, und „Nach Updates suchen“ öffnete nur denselben Dialog erneut, weil der alte Code sofort zurückkehrte, sobald ein Hinweis bereits anstand. Jede Prüfung ist jetzt eine echte Anfrage. Eine neuere Version ersetzt den Hinweis auf dem Bildschirm, dieselbe Version oder ein laufender Download lassen ihn in Ruhe, und ein Server, der überhaupt kein Update meldet, nimmt einen veraltet gewordenen Hinweis wieder herunter — die Version wurde zurückgezogen, oder Sie haben sie zwischenzeitlich selbst installiert. Der Knopf „Manuell herunterladen“ öffnet jetzt die Download-Seite auf der Website; bisher reichte er das Paket des Updaters selbst heraus, das sich an Ort und Stelle auspackt und sich von Hand gar nicht installieren lässt.
-
Beim schnellen Abbauen von Terminals erscheint kein bildschirmfüllendes Fehler-Overlay mehr. Der Viewport von xterm plant beim Erzeugen einen Abgleich des Scrollbereichs ein und beim Zurücksetzen noch einen, bricht aber beim Verwerfen keinen von beiden ab. Ein Terminal, das innerhalb derselben Aufgabe geöffnet und wieder geschlossen wird — und genau das passiert, wenn der Sitzungsbaum während einer Fernverbindung neu aufgebaut wird —, führte diese Callbacks trotzdem aus, fand einen bereits geleerten Renderer vor und warf einen Fehler. Der Fehler kommt aus einem Timer, wo weder try/catch noch eine Error Boundary hinreichen, deshalb wird er global abgefangen und eng abgeglichen: Nur ein Stack oder eine Meldung, die genau diesen Abgleich benennt und dazu den Renderer oder seine Abmessungen erwähnt, wird als harmlos geschluckt und ins Anfrageprotokoll geschrieben. Echte Abstürze lassen das Overlay weiterhin erscheinen.