Stufe 2 (#764): Huelle ClawdDotNet.Shell mit eingebettetem Chromium

Avalonia 11.3.17 + CefGlue.Next 152 in eigenem Ordner shell/. Startet den
Manager (ManagerStarter, nach Core gezogen), holt ueber den lokalen Socket
einen Einmal-Link und zeigt die WebUI angemeldet; Taskleistensymbol mit
Zustand. ClawdDotNet ohne Schalter startet die Huelle, sonst den Browser.
publish.py baut sie mit (--no-shell zum Weglassen), unter Linux mit den
Chromium-Ressourcen neben libcef.so. --selftest fuer die Pruefung ohne Blick.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-10-03 18:49:04 +02:00
co-authored by Claude Opus 5.5
parent 775c4dbc8e
commit c9c56ea53b
10 changed files with 579 additions and 141 deletions
+46 -2
View File
@@ -36,6 +36,7 @@ from pathlib import Path
REPO = Path(__file__).resolve().parent.parent
PROJECT = REPO / "src" / "ClawdDotNet.Desktop" / "ClawdDotNet.Desktop.csproj"
MANAGER_PROJECT = REPO / "src" / "ClawdDotNet.ManagerApp" / "ClawdDotNet.ManagerApp.csproj"
SHELL_PROJECT = REPO / "src" / "ClawdDotNet.Shell" / "ClawdDotNet.Shell.csproj"
CONFIG = REPO / "deploy" / "packager.config.json"
PACKAGER = Path(
"J:/Softwareprojekte/Deploymentcenter/client-dotnet/Deploymentcenter.Packager"
@@ -59,7 +60,7 @@ def run(cmd: list[str], **kw) -> None:
sys.exit(f"Abgebrochen (Rueckgabewert {result.returncode}): {cmd[0]}")
def publish(rid: str, out_dir: Path) -> None:
def publish(rid: str, out_dir: Path, include_shell: bool = True) -> None:
if out_dir.exists():
shutil.rmtree(out_dir)
out_dir.mkdir(parents=True)
@@ -90,6 +91,9 @@ def publish(rid: str, out_dir: Path) -> None:
])
merge_manager(manager_dir, out_dir)
if include_shell:
publish_shell(rid, out_dir, stamp)
# #795: Die systemd-Vorlagen gehoeren ins Linux-Paket - sonst steht die Anleitung in
# einem Repository, das auf der Zielmaschine niemand hat.
if rid.startswith("linux"):
@@ -100,6 +104,44 @@ def publish(rid: str, out_dir: Path) -> None:
print(f" systemd-Vorlagen: {len(list(units.glob('*.service')))} nach systemd/")
def publish_shell(rid: str, out_dir: Path, stamp: str) -> None:
"""#764: Die Huelle - Fenster mit eingebettetem Chromium - nach shell/.
Eigener Ordner, weil sie Avalonia 11.3 mitbringt (CefGlue ist dagegen gebaut) und der
Instanzprozess weder Avalonia noch Chromium laden soll. Kein merge_manager: Die
Bibliotheken der Huelle sollen gerade NICHT neben denen der Instanz liegen.
build statt publish: Das Chromium-Laufzeitpaket kopiert seine Dateien nur im
AfterBuild-Ziel mit gesetzter Plattform; ein publish liess sie aus (23 MB statt
~370 MB, und kein libcef). Unter Linux sucht Chromium icudtl.dat und die .pak-Dateien
neben libcef.so, das Paket legt sie nach Resources/ - sie werden hochgezogen.
"""
shell_dir = out_dir / "shell"
if shell_dir.exists():
shutil.rmtree(shell_dir)
run([
"dotnet", "build", str(SHELL_PROJECT),
"-c", "Release", "-r", rid, "--self-contained", "false",
"-o", str(shell_dir), "--nologo", "-v", "q", stamp,
])
resources = shell_dir / "Resources"
if rid.startswith("linux") and resources.is_dir():
for item in resources.iterdir():
target = shell_dir / item.name
if target.exists():
shutil.rmtree(target) if target.is_dir() else target.unlink()
shutil.move(str(item), str(target))
resources.rmdir()
for pdb in shell_dir.rglob("*.pdb"):
pdb.unlink()
size = sum(f.stat().st_size for f in shell_dir.rglob("*") if f.is_file())
print(f" Huelle: {size / 1_048_576:.1f} MB nach shell/")
def merge_manager(src: Path, dst: Path) -> None:
"""Legt den Manager neben die Instanz.
@@ -183,6 +225,8 @@ def main() -> None:
parser.add_argument("--agent-file", type=Path,
help="vorhandene Kopie des update-agent statt Download; "
"die Pruefsumme wird trotzdem gegen installer.json geprueft")
parser.add_argument("--no-shell", action="store_true",
help="die Huelle (Fenster mit Chromium, ~370 MB) nicht mitliefern")
parser.add_argument("--dry-run", action="store_true",
help="nur bauen und pruefen, nicht hochladen")
args = parser.parse_args()
@@ -193,7 +237,7 @@ def main() -> None:
out_dir = Path(tempfile.gettempdir()) / f"clawddotnet-publish-{args.rid}"
print("\n[1/3] dotnet publish")
publish(args.rid, out_dir)
publish(args.rid, out_dir, include_shell=not args.no_shell)
print("\n[2/3] update-agent")
if args.no_agent: