Befunde aus dem Testbetrieb auf der Linux-VM behoben (#572)

- #578: Abgebrochene Laeufe (Schrittgrenze, Zeitueberschreitung, Abbruch,
  Ausnahme) tragen ihre bezahlten Token - vorher 0 in RunUsage, fuer das
  Budget unsichtbar.
- #580: WebFetch prueft die aufgeloeste Zieladresse beim Verbinden; ein
  erlaubter Name, der auf 127.0.0.1 aufloest, wird gesperrt.
- #575: Dateien entstehen unter Unix mit 0600 (AtomicFile, Protokolle,
  FileRW-Anhaengen, state.db), Protokollverzeichnisse mit 0700.
- #576: SIGTERM/SIGINT beenden auch mit Fenster geordnet.
- #593: OpenRouter-Statusdienst wird gestartet.
- #589: Auftragsnachricht nennt aktuelle Zeit, Zeitzone und Termin.
- #581: Unvollstaendiges Argument-JSON erreicht das Werkzeug nicht mehr;
  das Modell bekommt eine verstaendliche Rueckmeldung statt Parsertext.
- #591: Weboberflaeche liest die Felder, die API und Ereignisstrom liefern
  (Freigaben, Protokoll, Taskboard mit Termin, Werkzeug-Einstellungen,
  Tokennutzung); Ereignisstrom in camelCase.
- #592: Chat zeigt Nachrichten nicht mehr doppelt.
- #536 (teilweise): A2A-Antworten tragen Absender und Empfaenger, Parser
  wirft nicht mehr; Datums- und Volltextfilter in Agenten-Chats.
- deploy/publish.py: Packager-Pfad net10.0, Schalter --agent-file.
- Version 0.1.4.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-09-14 15:40:56 +02:00
co-authored by Claude Opus 5
parent e2567a466f
commit 6581fd0187
29 changed files with 1128 additions and 190 deletions
+16 -3
View File
@@ -1,5 +1,6 @@
using System.Collections.Concurrent;
using System.Text;
using ClawdDotNet.Core.Storage;
namespace ClawdDotNet.Core.Logging;
@@ -7,6 +8,10 @@ namespace ClawdDotNet.Core.Logging;
/// Schreibt Log-Einträge asynchron in datei- und datumsgetrennte Logfiles.
/// Struktur: {LogDirectory}/{Datum}/{Modul}.log
/// Thread-safe durch ConcurrentQueue + dediziertem Writer-Task.
///
/// <para>Verzeichnisse <c>0700</c>, Dateien <c>0600</c> (#575): Im Protokoll stehen Pfade,
/// Fehlermeldungen von Werkzeugen und Anfänge von Aufträgen. Vorher entstanden sie mit der
/// Standardmaske, auf der Test-VM also <c>0775</c>/<c>0664</c>.</para>
/// </summary>
public sealed class FileLogWriter : IAsyncDisposable
{
@@ -20,7 +25,7 @@ public sealed class FileLogWriter : IAsyncDisposable
public FileLogWriter(FileLoggerOptions options)
{
_options = options;
Directory.CreateDirectory(_options.LogDirectory);
AppPaths.EnsureDirectory(_options.LogDirectory);
_writerTask = Task.Run(ProcessQueueAsync);
}
@@ -73,7 +78,10 @@ public sealed class FileLogWriter : IAsyncDisposable
_options.LogDirectory,
entry.Timestamp.ToString(_options.DateFormat));
Directory.CreateDirectory(dateDir);
// Nur beim Anlegen einschränken: EnsureDirectory setzt die Rechte, und das je
// Zeile zu tun hiesse einen Systemaufruf je Protokolleintrag.
if (!Directory.Exists(dateDir))
AppPaths.EnsureDirectory(dateDir);
var safeModule = SanitizeModuleName(entry.Module);
var filePath = Path.Combine(dateDir, $"{safeModule}.log");
@@ -83,7 +91,12 @@ public sealed class FileLogWriter : IAsyncDisposable
lock (fileLock)
{
var line = entry.Format(_options.TimestampFormat) + Environment.NewLine;
File.AppendAllText(filePath, line, Encoding.UTF8);
// Wie vorher File.AppendAllText mit UTF-8: Die Präambel steht nur am Anfang
// einer neuen Datei, weil der StreamWriter sie nur bei Position 0 schreibt.
using var stream = OwnerOnlyFile.OpenAppend(filePath);
using var writer = new StreamWriter(stream, Encoding.UTF8);
writer.Write(line);
}
}