Instanzmanager Stufe 5: Wechseln heisst nach vorn holen (#528, E-M2)

Vorher hiess "Instanz wechseln": Der laufende Prozess faehrt sich herunter
und startet sich mit einer anderen Instanz neu. Wer wechselte, beendete
zwangslaeufig die Instanz, aus der heraus er es tat - und genau dabei hat
sich die Anwendung am 2026-09-08 aufgehaengt (#529). Jetzt laufen alle, und
es kommt eine nach vorn.

Neu: POST /api/instanz/fenster, wieder ausschliesslich ueber den Socket.
Die Instanz holt ihr Fenster SELBST nach vorn; der Manager kennt kein
Fenstersystem und soll keines kennen. Kopflos laeuft die Bitte ins Leere,
und das ist die richtige Antwort. Das letzte Wort hat der Fenstermanager -
Windows laesst einen Hintergrundprozess den Vordergrund nicht einfach an
sich reissen; der kurze Ausflug ueber Topmost half im Versuch, unter Linux
entscheidet der Fenstermanager. Mehr als bitten kann eine Anwendung nicht.

ShutdownSignal ist zu InstanceControl geworden: beenden und Fenster sind
zwei Bitten desselben Absenders ueber denselben Weg. Beenden gilt einmal,
das Fenster beliebig oft - jeder Wechsel auf diese Instanz ist einer.

--managed schaltet den Wechsel im Instanzfenster ab. Der Manager gibt es
jedem Instanzprozess mit; das Fenster graut seinen Instanz-Schalter aus und
erklaert auf Nachfrage, wo gewechselt wird. Zwei Schloesser an derselben
Tuer: Der Knopf ist aus, und der Weg dahinter prueft es noch einmal - denn
hinter ihm wartet ein Selbst-Neustart.

instanceWindows in manager.json, vorbelegt auf true: Jede Instanz behaelt
ihr Fenster. Auf einer Maschine ohne Bildschirmsitzung gehoert false hin.

ABNAHME an echten Fenstern: Instanz ueber den Manager gestartet, PID 18128,
Fenstertitel "ClawdDotNet", Befehlszeile mit --managed. Fenster von aussen
minimiert (IsIconic True), dann POST /instanzen/Instance-Test/fenster:
IsIconic False, im Vordergrund - und PID unveraendert 18128. Nichts neu
gestartet. Das ist die Abnahmebedingung dieser Stufe.

Build ohne Warnungen, 780 Tests gruen, 8 uebersprungen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-09-08 23:39:50 +02:00
co-authored by Claude Opus 5
parent a511480b77
commit db7abf699f
18 changed files with 496 additions and 42 deletions
+19 -1
View File
@@ -16,6 +16,17 @@ internal static class CommandLine
/// <summary>Läuft ohne Fenster: nur Aufbau, Socket und Warten (#528, Stufe 2).</summary>
public const string HeadlessArgument = "--headless";
/// <summary>
/// Gestartet und beaufsichtigt vom Instanzmanager (#528, Stufe 5).
///
/// <para>Dann gehört der Instanzwechsel dorthin und nicht in dieses Fenster: Der
/// Manager hält die Fenster aller Instanzen im Hintergrund und holt das gewünschte
/// nach vorn. Ein Fenster, das sich selbst mit einer anderen Instanz neu startet,
/// nähme dabei genau die Instanz mit, aus der heraus jemand wechselt — und das ist
/// der Vorfall, mit dem dieses Vorhaben angefangen hat (#529).</para>
/// </summary>
public const string ManagedArgument = "--managed";
/// <summary>
/// Der Instanzpfad hinter <c>--instance</c>, oder <c>null</c>.
///
@@ -37,6 +48,13 @@ internal static class CommandLine
}
public static bool IsHeadless(IReadOnlyList<string>? args)
=> Has(args, HeadlessArgument);
/// <inheritdoc cref="ManagedArgument"/>
public static bool IsManaged(IReadOnlyList<string>? args)
=> Has(args, ManagedArgument);
private static bool Has(IReadOnlyList<string>? args, string flag)
=> args is not null
&& args.Any(a => string.Equals(a, HeadlessArgument, StringComparison.OrdinalIgnoreCase));
&& args.Any(a => string.Equals(a, flag, StringComparison.OrdinalIgnoreCase));
}