e2ffe4b380d130493f6c95cf5456b3ae30d55408
52
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
29d953a5eb |
Brett je Einheit, Stufe 3: Aufgaben sehen, wer sie sehen soll (#684)
- TaskBoard: das Brett einer Aufgabe wird nicht gespeichert, es folgt aus der Organisation - Einheit des Zustaendigen, sonst des Anlegers. Offene Aufgaben ziehen damit beim Umzug mit. Sichtbar: das eigene Brett, fuer eine Leitung alle darunter, und was man selbst angelegt hat (nach oben Gereichtes bleibt im Blick). - TaskItem.CreatedBy, in der Datei als created_by und in der DB. Ein Import aus einer Datei ohne das Feld behaelt, was die DB weiss. - Taskboard-Tool: task_list, task_find und die Dublettenpruefung sehen nur die eigenen Bretter - eine aehnliche Buchhaltungsaufgabe haelt keine Marketingaufgabe auf und bekommt keinen Kommentar von dort. task_update und task_comment antworten auf eine fremde Aufgabe wie auf eine unbekannte. - TaskboardService.ListAsync mit Sichtfilter: erst filtern, dann kappen. - WebUI: jede Aufgabe nennt ihr Brett, ein Filter waehlt eines aus. - Konzept (Abschnitt 3) und Einrichtungshandbuch nachgetragen. Ohne Einheiten aendert sich nichts - ein Brett fuer alle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
b2b8a34d9f |
Lagebild: Einheiten als verbundene Karten, Strukturbaum mit Suche und Filter (#711)
Rueckmeldung zur Teamuebersicht: wirkte veraltet, und die Verbindungen zwischen den Einheiten fehlten - zugeklappte Container versteckten ganze Ebenen, man haette sich bis zum Problem durchklicken muessen. - Jede Einheit ist immer eine Karte, verbunden als Organisationsbaum (ELK layered, orthogonale Linien, eckige Anschluesse). Keine Ebene wird versteckt. Zugeklappt wird nur die Agentenliste grosser Einheiten: sie zeigt, wer Aufmerksamkeit braucht, und "+n weitere". - Eine Linie traegt die Farbe des dringlichsten Zustands darunter - eine rote Linie fuehrt von oben zum Problem. - Links ein Strukturbaum mit Suche (Agent, Einheit, Modell) und Zustandsfilter; Treffer werden hervorgehoben, der Weg dorthin geoeffnet, der Rest abgeblendet. Enter springt zum ersten Treffer. - Leinwand mit Punktraster, Verschieben und Zoomen, schwebende Leisten (Live-Verbindungen, Einpassen, Zoom). Live-Verbindungen laufen von Zeile zu Zeile, gebuendelt mit Zaehler. - Hausstil bleibt (Radius 0, App-Akzent), hell und dunkel, bis Handybreite. - Cytoscape und cytoscape-elk entfernt: ein Canvas-Knoten kann keine Agentenliste, Suche oder den Hausstil tragen. Karten sind jetzt HTML. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
9cf9a2cfc2 |
Budgetende, Stufe 3: Nachholen nur im Spielraum des Tages, keine Kappung bei 500 (#716)
- TaskSchedule.OccurrencesBetween zaehlt, wie oft eine Aufgabe bis zu einem Zeitpunkt noch laeuft, einschliesslich eines jetzt faelligen Laufs. - BudgetHeadroom (ILateRunGate): Ein mitgenommener oder nachzuholender Lauf startet nur, wenn er in den Spielraum passt: Grenze minus Verbrauch minus Reservierung minus Bedarf der restlichen geplanten Laeufe bis Mitternacht minus 10 % Reserve. Das gilt je Agent und je Instanz, fuer Kosten und Tokens. Anderes Spaetwerk zaehlt nicht als Bedarf, sonst blockierten sich mitgenommene Aufgaben gegenseitig. - Der Scanner fragt den Spielraum nur fuer Spaetwerk und protokolliert, wenn es warten muss. Die Engine gibt ihren BudgetGuard heraus, damit Scanner und Engine dieselben Reservierungen sehen. - Ersetzt den pauschalen 25-%-Anteil aus dem Konzept (dort nachgezogen): Ein fester Anteil ist an vollen Tagen zu viel, an ruhigen zu wenig. Drei weitere stille Kappungen bei 500 beseitigt (ListAllAsync, ungekappt): Kostenprognose (Aufgaben ueber 500 fehlten), Waisenabgleich beim Import und task_find aus #674, wo Dubletten unter aelteren Aufgaben mit niedriger Prioritaet unsichtbar wurden. Tests: BudgetHeadroomTests (9), Scanner-Pforte (1), Dublette hinter 500 Aufgaben (1). 1.257 gruen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
b53396a754 |
Organisation-Konzept: Einstellungen an der Einheit ohne Uebertrumpfen
Festlegung des Nutzers: Einheiten-Einstellungen sind entweder Sammelwerte, die in die Agenten geschrieben werden (Vorgabe nur fuer neue Mitglieder, Warnung bei Ausreissern wie Spezialisten), oder Regeln ohne Gegenstueck am Agenten (Rechte-Obergrenze, beim Schreiben geprueft; Parallelitaet je Einheit). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
4415b26e7d |
Organisation-Konzept: Fuellarbeit und Grossaufgaben (#717)
Zeitlich flexible Arbeit mit Frist statt Termin fuellt ungenutztes Tagesbudget (Backfilling); ob Platz ist, entscheidet der Code aus Restbudget und Prognose. Grossaufgaben werden geteilt oder bekommen ein vom Menschen freigegebenes Sonderbudget als eigenen Topf. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
66c6d8e73b |
Organisation-Konzept: Budgetende (#716), Einheiten ohne eigene Konfiguration
- 8a: Was liegen bleibt, wenn das Budget endet. Ist-Zustand nachgesehen (einmalige Aufgaben werden still nachgeholt, wiederkehrende verfallen still), Vorschlag expire / catch_up_once / carry_over je Agent, der neue Tag hat Vorfahrt, Vermerk an der Aufgabe und als Tageszusammenfassung, Vorbeugen ueber die Prognose aus #608, Budgetreservierung als Rest aus #682. - 3: Festlegung des Nutzers, dass Einheiten keine eigene Konfiguration speichern; Einstellungen fuer eine Einheit werden gesammelt in die Agenten geschrieben. Drei Kollisionen als offen markiert: Rechte-Obergrenze, Parallelitaet je Einheit, Grenzen der Leitung. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
ac63e58141 |
Organisation-Konzept: Lagebild (#711), fremde Laufzeiten (#712, #713), Paperclip (#714, #715)
- 7a Fremde Laufzeiten: Claude Code u. a. als Laufzeit der Entwicklungsabteilung; gilt als weniger vertrauenswuerdig (Worktree/ Sandbox, Freigabelisten statt Rechte-Umgehung, Ergebnis ist ein Vorschlag, nach aussen nur ueber den ClawdDotNet-MCP-Server). Vorbehalte Kontingent und Nutzungsbedingungen als offene Entscheidung. - 9a Von Paperclip gelernt: Zielkette mit Pruefung ruhender Aufgabenbaeume, Rueckmeldung nach Vertrauensstufe (fremder Text steigt nicht in der Hierarchie auf), Courier Pattern; bewusst nicht uebernommen: Rechte- Umgehung als Voreinstellung, firmenweite Sichtbarkeit. - 10a Das Lagebild: Teamuebersicht mit Layout aus der Struktur, aufklappbaren Einheiten, Problemzustaenden aus dem Code und Seitenleiste vor dem Chat; Stufe 0 ohne Einheiten. - Reihenfolge, offene Entscheidungen und Itemliste nachgezogen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
6ae7040c54 |
Roadmap: zweiter Orchestrator-Vergleich und erzeugte Kopie nachgezogen
Die Begruendung zum Vergleich vom 2026-09-18 (OpenClaw 2.0, Grok Bot) lag unversioniert im Arbeitsbaum, zusammen mit der erzeugten Kopie vom 2026-09-19. Beides gehoert ins Repository - die Begruendung, weil sie von Hand geschrieben ist und bleibt, die Kopie, weil sie den Stand zeigt. Der Block zwischen den dc:roadmap-Markern bleibt erzeugt und wird beim naechsten Lauf ueberschrieben; die heute angelegten Items #673 bis #704 sind darin noch nicht enthalten. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
605f6a3e60 |
Security-Konzept: Zugangsdatenverwaltung (#703), Datei erstmals versioniert
Der Agent schickt Platzhalter, ClawdDotNet setzt sie im Werkzeug ein. Der Ansatz ist richtig, loest aber weniger als er verspricht - die sieben Luecken dazwischen sind die Arbeit. Die beiden wichtigsten: Ersetzt wird an benannten Stellen je Werkzeug, nie als Suchen-und-Ersetzen ueber alle Argumente; und jedes Geheimnis wird an ein Ziel gebunden, sonst schuetzt der Platzhalter den Wert vor dem Modell und liefert ihn an den Angreifer. Die Datei lag bisher unversioniert im Arbeitsbaum, obwohl fuenf Items (#651-#659) ueber doc_anchor auf sie verweisen. Damit war die Begruendung fuer niemanden ausserhalb dieses Rechners lesbar - genau das, was die Regeln in CLAUDE.md verhindern sollen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
d3bf833c12 |
Organisation: Abstimmung (#702) und Aufbewahren statt Loeschen (#700)
Die Abstimmung zaehlt keine Meinungen, sondern erzwingt unabhaengige Pruefungen aus verschiedenen Datenquellen. Daraus folgt die Regel, an der alles haengt: Es wird BLIND abgestimmt. Sieht ein Stimmberechtigter die Stimme eines anderen, stimmt ein guenstiges Modell dem zu, was es gerade gelesen hat - aus vier Pruefungen werden eine und drei Echos. Damit ist die Abstimmung das Gegenstueck zur Besprechung, wo jeder die Beitraege sieht. Und eine Kehrtwende bei #700: Vorgeschlagen war eine Frist mit Kehrbesen fuer Audit und Receipts. Richtig ist das Gegenteil. In einem Buero voller Menschen geht taeglich verloren, warum etwas so entschieden wurde - hier nicht. Bei hundert Agenten sind es 3,3 GB im Jahr; dafuer wirft man kein Wissen weg. Was bleibt, ist ein Archiv: heiss und kalt trennen, verdichtete Werte immer behalten, Geheimnisse gar nicht erst hineinschreiben, gezielt loeschen koennen. Folge: Die 14-Tage-Voreinstellung der Prompt-History gehoert auf unbegrenzt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
b8e1817c7d |
Organisation: viele gemeinsame Bereiche, Doctrine, Kostenanalyse (#698-#700)
Der Ordner SharedWorkspace wird zu SharedWorkspaces: mehrere benannte Bereiche mit Eigentuemer und Mitgliederliste, je Einheit einer als Normalfall, abteilungsuebergreifende ausdruecklich. Das Recht steht am Bereich, nicht am Agenten - Marketing sieht die Ablage der Buchhaltung nicht, und erfaehrt auch nicht, dass es sie gibt. Zwei offene Fragen entschieden: - Budgets bleiben am Agenten. Die Einheit rechnet auf und meldet Abweichungen vom eigenen Verlauf. Damit entfaellt die Zuteilungsrechnerei, und ein Umzug aendert keine einzige Grenze. - Eine Eskalation, die nicht geloest werden kann, darf es nicht geben. Nach einer Frist wird der Mensch gerufen, der entscheidet oder Stellungnahmen anfordert. "Bleibt sichtbar liegen" war zu schwach. Neu: Die Doctrine.md gibt einer Leitung ein Steuermittel neben Identity und Soul - eine Ebene tief, kurz, gedeckelt, und freigabepflichtig, wenn der schreibende Lauf fremde Inhalte gelesen hat. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
c37249e4b7 |
Organisation: Umzug, Ausnahmenliste und Gegenlesen (#683, #685, #687, #689)
Der Baum ist beliebig tief schachtelbar, und Einheiten wie Agenten muessen
sich nachtraeglich verschieben lassen - bei gestoppter Instanz, mit
Unterrichtung der Betroffenen und Eintrag im Audit. Das Konzept setzte das
schon voraus ("wer mehr Reichweite geben will, verschiebt im Baum"), ohne es
je zu beschreiben.
Beim Gegenlesen gefunden und aufgeloest:
- "Nur nach oben" gegen "zurueckgeben": Die zweite Antwort der Leitung ist
eine ENTSCHEIDUNG, die den Vorgang schliesst. Verboten ist der ungeloest
zurueckwandernde Vorgang.
- Konflikt gegen "nie ueber Ebenen hinweg": Ein Konflikt klettert nicht, er
wird zugestellt. Die Zustaendigkeit ergibt sich rechnerisch aus dem Baum;
dazwischenliegende Ebenen werden vermerkt, nicht befragt.
- Die Ausnahmen von "ein Agent kennt nur seine Einheit" stehen jetzt
vollstaendig beisammen - vier, alle lesend, keine gibt einen neuen
Gespraechspartner. Verstreute Ausnahmen vermehren sich.
- Stale Verweis "Vorbedingung fuer Stufe 4" auf Stufe 5 berichtigt, die
Kontrollpflicht vor die Oberflaeche gezogen.
Vier Punkte als zu grob markiert und mit Vorschlag versehen: Budget als
Deckel oder Zuteilung, woraus eine Freigabegrenze besteht, wie ein
Beschluss wirksam wird, was die Eskalationsgrenze tut, wenn sie greift.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
||
|
|
a14aeeac58 |
Stille Post vermeiden (#697) und Fehlerablage je Skript (#696)
Eine Meldung, die vier Ebenen durchlaeuft, wird viermal neu formuliert. Das faellt nicht auf, weil es keinen Fehler gibt, den man finden koennte - alle arbeiten korrekt, und die Spitze entscheidet ueber eine Nacherzaehlung der Nacherzaehlung. Die Regel: Jede Weitergabe haengt an, sie ersetzt nicht. Der Verweis auf den Ursprung wandert mit, der Inhalt bleibt liegen und wird geholt, wer ihn braucht. Eine Zusammenfassung darf danebenstehen, nie anstelle. Dieselbe Festlegung wie beim Aufgabenrumpf (#677), hier fuer den Weg. Beim Skriptfehler heisst das: Der Sandbox-Runner legt Exit-Code, stderr, Aufrufparameter, Dauer und RunId unter scripts/<id>/fehler/ ab - nicht der Agent. Der Zugang folgt dem Skript statt der Abteilung, damit der Entwickler alle Fehlschlaege seines Werkzeugs sieht, ohne in fremde Arbeitsbereiche zu duerfen. Durch die Befehlskette geht nur noch der Verweis. Nebenbei zwei doc_anchors nachgezogen, die durch fruehere Umnummerierung ins Leere zeigten (#687, #688). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
d25ae41f4b |
Skripte: wer eines braucht, baut es nicht (#695)
Korrektur der gestrigen Fassung: Dort stand, der zustaendige Agent schreibe und pflege sein Skript selbst. Ein Anzeigen-Agent, der programmiert und beliebigen Code ausfuehrt, hat Rechte, die seine Arbeit nicht braucht. Die Lieferkette: Bedarfsmeldung mit ausgearbeiteter Beschreibung an die eigene Leitung, von dort an die Entwicklung, dort schreiben und testen, Pruefung und Freigabe nach #657, Zuteilung an genau diesen einen Nutzer. Fehler gehen ueber dieselbe Kette zurueck. Technisch folgt daraus, dass scripts.run kein Schalter sein darf, sondern eine Liste benannter Skripte - ein Ja/Nein waere die Hintertuer, die die Trennung gerade schliesst. Und ein zweiter Gewinn, der als Entwurfsziel gelten soll: Der Agent, der fremde Inhalte liest, ist nie der Agent, der ausfuehrbaren Code hervorbringt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
8479f6ef2a |
Organisation: Faehigkeiten statt Anschluesse, Kontrollpflicht der Leitung (#693, #694)
Korrektur der vorigen Fassung: Plattformen werden NICHT angebunden, auch nicht als MCP-Server je Plattform - das verlagert die Pflege nur nach aussen. Das Produkt gibt Faehigkeiten (API, Webseite, Datenbank, Mail); was spezifisch ist, schreibt sich die Instanz selbst. Damit sind Sandbox (#654), Shell (#196) und Skriptpruefung (#657) nicht nur Sicherheitsvorhaben, sondern der eigentliche Werkzeugkasten. Die Reihenfolge bleibt zwingend: erst die Sandbox, dann das Schreiben. Neu: Eine Leitung delegiert nicht nur, sie prueft stichprobenartig (#693) - gegen AuditLog und Transkripte, nie gegen die Selbstauskunft, denn ein Modell hat am 14.09. dreizehn Werkzeugantworten erfunden. Aus einem Befund folgen abgestufte Mittel: meist ein schaerferer Auftragstext, seltener ein anderes Modell, zuletzt Stilllegung. Vorgeschlagen von der Leitung, ausgefuehrt nach Freigabe. Dazu der A/B-Vergleich im Betrieb (#694), gemessen an Dingen, die das Modell nicht selbst behauptet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
0c854f4a1e |
Organisation: Baukasten-Trennung, Eskalation und Entscheidungsinstanz (#689-#692)
Das Produkt bringt Baum, Mittel, Werkzeugkasten und Grenzen mit; welche Abteilungen es gibt, ist eine Zeile in einer Datei. Im Code steht nirgends das Wort "Einkauf". Daraus folgt die Organisationsvorlage (#691) - ein ganzes Haus als weitergebbare Datei. Der Eskalationsfall aus dem Vorschlag zerfaellt in drei Mittel (#689): Eskalation geht nach oben, ein Konflikt wird bei der niedrigsten gemeinsam uebergeordneten Stelle entschieden - eine Regel, die fuer jedes Organigramm gilt, ohne dass jemand Wege konfiguriert -, und ein Beschluss ist dauerhaft, sonst wird dieselbe Frage naechste Woche erneut durch vier Ebenen getragen. Die Spitze ist eine Rolle, kein CEO-Agent (#690): Mensch, Agent oder Mensch mit Frist. Wer entscheidet, fuehrt nicht aus und aendert die Struktur nicht. Vorbedingung des ganzen Falls: Das Datenbank-Werkzeug kann heute nicht nach dem Schema fragen (#676). "Ich finde kein Feld dafuer" ist damit eine Vermutung, und eine Organisation soll keine Einbildungen eskalieren. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
af46847cb5 |
Organisation: 50-100 Agenten als Ziel, "hoechstens 5" zurueckgezogen (#682-#688)
Die Regel im InstanceSetupGuide war in der Beobachtung richtig und in der Folgerung falsch: quadratisch steigen die Verbindungen, nicht die Agenten. Ein Agent, der drei Nachbarn und eine Leitung kennt, kostet gleich viel, ob die Instanz zehn oder hundert Agenten hat. docs/Organisation-Konzept.md haelt fest, was heute bei 50 Agenten bricht (flaches Adressbuch, synchrones send_message, Delegationstiefe 3, unbegrenzte Parallelitaet, Kappung bei 500, zwei Arbeitsbereiche, ein Brett, zwei Budgetebenen, eine Freigabe-Warteschlange) und schlaegt die fehlende Ebene vor: die Einheit. Zwei davon sind schon heute Fehler und gehoeren sofort behoben (#682). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
fa90fb2768 |
Konzepte: Basisagenten (#679, #680) und Werkzeugproben (#681)
Zwei Nutzervorschlaege aus dem Testbetrieb, beide mit Ankern im Bestand: Die Aufsicht ist das dritte Profil des AgentInspector (#204), neben dem Security-Profil (#658); die Werkzeugproben fuellen Stufe 2 des Probelaufs fuer neue Agenten (#649) und loesen den "Evals-Test-Runner" aus dem Orchestrator-Konzept ein. Zwei Entscheidungen tragen die Dokumente: - Erkennen ist Code (#646), Deuten ist Modell (#680). Wer das verwischt, bezahlt ein Sprachmodell fuers Zeilenzaehlen. - Die Eignungsprobe gehoert zum Werkzeug, nicht in eine zentrale Liste, und wird gegen das Audit geprueft, nie gegen die Selbstauskunft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
060dc6a6ad |
FileRW list sortiert und gedeckelt (#673), Taskboard task_find (#674)
Die Betriebskontrolle im Testbetrieb meldete Stundendateien als fehlend, die es gab: 105 Eintraege in der Reihenfolge des Dateisystems, vierzeilig als eingeruecktes JSON. list liefert jetzt die 50 zuletzt geaenderten Eintraege, neueste zuerst, eine Zeile je Eintrag, mit Gesamtzahl im Kopf; pattern, sort, order und limit steuern das. Dabei aufgefallen (#675): Directory.GetFiles wertet Trennzeichen im Muster aus - pattern "../*" fuehrte an der Pfadpruefung vorbei aus dem Verzeichnis heraus, in list wie in read_many. Muster mit '/', '\' oder '..' werden jetzt abgewiesen. Und derselbe Befund ist keine zweite Aufgabe (#674): task_find beantwortet die Frage vor dem Anlegen, task_create legt bei gleichbedeutendem Titel einer offenen Aufgabe keine zweite an, sondern vermerkt das erneute Auftreten an der bestehenden. force=true geht trotzdem, Erledigtes blockiert nichts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
24e457b11f |
FileRW: Sammel-Lesen (#663) und Hinweis auf den anderen Workspace (#662)
#663: Neue Aktion read_many liest mehrere Dateien in einem Aufruf - entweder paths (Liste) oder path (Verzeichnis) mit pattern. Gedeckelt auf 50 Dateien und 200.000 Zeichen; was nicht mehr hineinpasst, wird namentlich genannt, damit der Agent gezielt nachholen kann. Anlass: Der Tagesabschluss im Testbetrieb las 24 Stundendateien einzeln und starb zweimal an der Schrittgrenze - die soll Endlosschleifen abfangen, nicht ehrliche Arbeit. #662: Schlaegt read oder list fehl, weil der Pfad im anderen Workspace liegt, sagt die Fehlermeldung das - aber nur, wenn der Agent diesen Workspace auch benutzen darf. Guenstige Modelle vergassen workspace "shared" regelmaessig und verbrauchten mit jedem Rateversuch einen Schritt. Dateipruefung, Endungen und Workspace-Grenze gelten in read_many unveraendert; eine verbotene Endung wird uebergangen statt den Lauf zu kippen. Version 0.1.14. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
2f0361278b |
Freigaben buendeln statt Weckflut (#643), Freigabemodell ueber Werkzeugrechte (#641)
#643: Entscheidungen wecken den Agenten nur noch bei Ablehnung oder gescheiterter Ausfuehrung, gesammelt in einer Aufgabe je Agent (5 min Ruhefenster), frisch per @new:agent statt im fortgefuehrten Chatverlauf. Eine einmalige Aufgabe, deren Lauf wegen Budget oder Herunterfahren gar nicht stattfand, bleibt faellig (Wiedervorlage nach 30 min) statt mit gesetztem Marker liegenzubleiben. #641: Rechte stehen in der Werkzeugkonfiguration des Agenten (erlaubt/verboten). Erlaubtes laeuft, Nicht-Erlaubtes wird einzeln vorgelegt statt verweigert, Verbotenes gar nicht erst. "Gleichartiges kuenftig erlauben" erteilt eine widerrufbare Dauerfreigabe je Agent/Werkzeug/Operation; nach drei gleichartigen Freigaben schlaegt die Oberflaeche sie vor. Aenderungen an Agenten bleiben ausnahmslos freigabepflichtig. Database: Operation ist das SQL-Schluesselwort; die eigene Zugriffspruefung greift nur noch ohne Freigabestelle (AgentToolContext.FreigabeGeprueft). WebUI: Rechte-Tabelle je Werkzeug, Dauerfreigaben mit Widerruf. Version 0.1.11. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
0b6ea73ec1 |
Entscheidungen aus dem Testbetrieb umgesetzt (#572): #577 #579 #581 #589 #193 #205 #594 #595 #597 #598 #599 #588
- Engine: leere Antworten nachfassen, Aufgaben enden mit Ergebniszeile (EmptyResponse/Incomplete), gleiche Fehlschlaege erkennen (RepeatedFailure), Zeitzeile vor Chatnachrichten, Werkzeugergebnisse gerahmt, Vorpruefung vor dem Staging, Belegkosten wie RunUsage - Staging: gescheiterte Freigaben als Failed; AgentEditor-Aenderungen freigabepflichtig, Selbstbearbeitung gesperrt (allowSelfEdit) - Taskboard: Termine beim Anlegen pruefen, naechster/letzter Lauf, pausieren, Sofortlauf, Kostenprognose, Hinweis auf wachsenden Kontext; Jobs-Reiter und /api/jobs entfernt - Release: Instanzmanager samt Weboberflaeche im Paket, setup.json fragt manager.json ab, Token nicht mehr ins systemd-Journal Version 0.1.6. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
fb185ca84d |
Sicherungen mit dem Lizenzschluessel verschluesselt, optional per FTP (#530)
Eine Sicherung des Managers ist jetzt als Ganzes mit dem Lizenzschluessel verschluesselt. Beim Zurueckspielen wird der eigene Schluessel probiert; passt er nicht, fragt die Oberflaeche nach dem Lizenzschluessel der Quellinstallation. Der Lizenzschluessel ist der eine Wert, den jede Installation ohnehin hat, und er liegt im Manager, nicht neben den Archiven. Damit faellt der Grund weg, aus dem die taegliche Sicherung bisher keine Zugangsdaten enthielt: Eine Passphrase haette gespeichert werden muessen, und neben den Sicherungen waere sie wirkungslos gewesen. Jetzt reisen die Zugangsdaten mit, und eine Sicherung uebersteht den Maschinenwechsel ohne Passphrase. LicenseBackupCipher: eigener Behaelter .clawdbak. Kopf mit Schluesselprobe, das Manifest als eigener Abschnitt, das ZIP in 1-MiB-Stuecken mit AES-256-GCM und Endmarke. PBKDF2 aus Lizenzschluessel und festem Salt, der Schluessel normiert. Kein RAR (braucht das lizenzpflichtige Herstellerprogramm), kein ZIP mit Kennwort (kann .NET nicht schreiben, ZipCrypto ist gebrochen, und mit abgeleitetem Schluessel braechte 7-Zip-Vertraeglichkeit nichts). Zurueckspielen: Die Schluesselprobe laeuft VOR dem Anhalten der Instanz. Passt der Schluessel nicht, antwortet der Endpunkt mit 422 und dem Code fremde_lizenz, und ein Fenster verlangt den Schluessel der Quelle. ManagerBackups: Gefuehrte Instanzen sichern sich nicht mehr selbst, weil nur der Manager den Schluessel hat; er liest ihre Einstellungen aus InstanceSettings.json. Einmal am Tag auch ueber einen Neustart des Managers hinweg. Ohne Lizenzschluessel wird nichts gesichert, auch nicht ersatzweise unverschluesselt. FTP (FluentFTP, schon im Loesungsbaum): TLS wo angeboten, requireTls erzwingt es; Upload unter .part-Namen und danach umbenannt; Aufraeumen auf dem Server je Instanz; ein gescheiterter Upload laesst die lokale Sicherung stehen. Das Kennwort liegt verschluesselt in manager.json und geht nie an die Oberflaeche. Welche Datei zu welcher Instanz gehoert, entscheidet ein Zeitstempel nach dem Namen und nicht das Praefix - Test und Test_2 werden nicht mehr verwechselt. Grenze, bewusst und dokumentiert (Konzept 9.10): Wer Lizenzschluessel und Archiv hat, hat die Zugangsdaten. Der Schluessel ist dem Hersteller bekannt und gilt fuer alle Instanzen einer Installation. Nicht ueber die Oberflaeche abgenommen: Fenster fuer die fremde Lizenz und FTP gegen einen echten Server stehen als Block H in #537. 860 Tests gruen, 0 Warnungen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
99f8a89fd0 |
Schluesselbund: ein Hauptschluessel, mehrfach verpackt (#190)
SecretKeyStore.Wrap band den Hauptschluessel unter Windows per DPAPI ans Benutzerkonto und gab ihn sonst ungewrappt zurueck - eine Zeile, die man beim Lesen ueberspringt und die auf dem Zielsystem "im Klartext" bedeutet. Dahinter steht jetzt ein SecretKeyRing: derselbe Hauptschluessel, mehrfach verpackt, je Fach ein ISecretProvider (dpapi, passphrase, file). Fuer Aufrufer aendert sich nichts - GetOrCreateKey gibt weiterhin 32 Byte zurueck. Genau dafuer war die Naht da. WARUM MEHRERE FAECHER UND NICHT EIN BESSERES Ein Schluessel an der Maschine ueberlebt keinen Umzug; einer an einer Passphrase verlangt bei jedem Start jemanden, der tippt - und Dauerbetrieb ohne Menschen ist der Zweck (#214). Der Bund entscheidet sich nicht: Im Alltag oeffnet das Maschinenfach ohne Rueckfrage, nach einem Umzug die Passphrase, und beide fuehren zu DEMSELBEN Schluessel. Alle enc:v2-Werte bleiben lesbar. Und deshalb darf die Schluesseldatei jetzt ueberhaupt in eine Sicherung: Sobald ein Wiederherstellungsfach da ist, steht der Hauptschluessel in keiner Fassung im Klartext darin. Nicht zu verwechseln mit der Sicherung mit Passphrase: Die schluesselt jeden WERT einzeln ins Archiv um, fuer den Transport einer Instanz. Das Wiederherstellungs- fach schluesselt den HAUPTSCHLUESSEL um, damit eine bestehende Installation weiterlaeuft - unbeaufsichtigt ueber CLAWD_SECRET_PASSPHRASE. Die Unterscheidung steht in docs/Roadmap.md bei #190. Beide Altformate werden uebernommen: 32 rohe Byte werden zum Fach file, ein DPAPI-Block zum Fach dpapi. Derselbe Schluessel, nur anders verpackt. Zwei Zusagen, mit Tests festgehalten: - Geht KEIN Fach auf, wird abgebrochen statt ein neuer Schluessel erzeugt. Ein neuer Hauptschluessel machte jeden bestehenden Wert wortlos unlesbar. - Ein Umzug legt den Schluessel NICHT im Klartext ab, nur damit der naechste Start bequemer wird. Beim automatischen Weg wird nur hinzugefuegt, nie weggenommen; weggenommen wird nur in SetRecoveryPassphrase, wo ein Mensch gerade getippt hat. #190 bleibt offen: Unter Linux greift weiterhin das Fach file. Neu ist, dass es beim Start als Warnung im Protokoll steht statt unsichtbar zu sein. Womit das Maschinenfach dort gefuellt wird, ist Entscheidung #180 - diese Schnittstelle ist die Stelle, an der die Antwort eingesetzt wird. 834 Tests gruen, 0 Warnungen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
e3403087c2 |
Handschlag: --managed hebelt die Lizenzpruefung nicht mehr aus (#535)
Mit E-M3 wanderte die Lizenzpruefung in den Manager: Eine gefuehrte Instanz prueft nicht mehr selbst, weil der Manager es zentral getan hat. Woran sie "gefuehrt" erkannte, war der Schalter --managed - und ein Schalter ist keine Erkennung. ClawdDotNet --managed startete damit eine Instanz ganz ohne Lizenzpruefung. Vor E-M3 gab es die Luecke nicht; sie ist mit der Zentralisierung entstanden. ManagerHandshake unterschreibt Instanzverzeichnis und Ablauf mit HMAC-SHA256. An die Signierstelle kommt der Manager nur, wenn seine Lizenzpruefung bestanden hat - StartInstanceAsync weist vorher mit StartRefusal.NoLicense ab. Dass die Unterschrift existiert, ist der Beweis. - Gebunden an das Verzeichnis, und geprueft wird gegen das tatsaechliche, nicht gegen das behauptete: Sonst unterschriebe man das Argument statt der Sache. - Fuenf Minuten gueltig, der Ablauf geht in die Unterschrift ein. - Ueber die Umgebung statt ueber die Befehlszeile: Eine Befehlszeile steht in jeder Prozessliste. - Ungueltig heisst "nicht gefuehrt", nicht Abbruch. Dann prueft die Instanz ihre Lizenz selbst - der Weg von vor E-M3, also kein neuer Fehlerfall. AppHost.IsManaged ist jetzt der gepruefte Befund. CanSwitchInstance und der Wechseldialog haengen daran statt am Schalter. Die Grenze steht ausdruecklich im Konzept (9.9): Der Schluessel liegt in jeder ausgelieferten Programmdatei. Es geht um den gewoehnlichen Weg an der Lizenz vorbei, nicht um jemanden mit Werkzeugen und Willen. Abgenommen an echten Prozessen, Unterschrift fuer den Positivfall unabhaengig in Python gerechnet: ohne Unterschrift "Lizenz erforderlich"; mit gueltiger kommt die Instanz hoch; Unterschrift fuer ein fremdes Verzeichnis und hochgedrehter Ablauf scheitern beide. 820 Tests gruen, 0 Warnungen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
dcffcdcff5 |
Instanzmanager: Weboberflaeche kennt Instanzen, geordnetes Ende, Puls (#528, #531)
Weboberflaeche (#531): X-Instanz an der einen fetch-Stelle, Instanzauswahl in der Kopfzeile, Verwaltungsansicht mit Anlegen/Starten/Anhalten/Fenster, Herkunft der Ereignisse, Sicherungs- und Einstellungsansicht. 402/409/502 werden eigen behandelt. Sicherungen im Manager (#530): Auflisten, Anlegen, Wiederherstellen, Loeschen. Das Zurueckspielen haelt die Instanz vorher an und startet sie danach wieder. Geordnetes Ende (Konzept 9.8). Zwei Befunde waren der Anlass: Der Manager konnte eine Instanz MIT FENSTER nie geordnet beenden. Control.ShutdownRequested war nur in HeadlessRun verdrahtet, nicht in der Avalonia-Anwendung - und ein Fenster ist die Vorgabe. Die Bitte wurde mit 202 beantwortet, niemand hoerte zu, und der Manager schoss den Prozess nach Ablauf seiner Frist jedes Mal ab. InstanceSupervisor.StopAsync hielt Socket-Schweigen fuer einen Todesnachweis und meldete "beendet", ohne den Prozess anzufassen. Bei einer verstummten Instanz ist der Socket von vornherein still - der Neustart haette einen zweiten Prozess auf dieselbe state.db gesetzt. Genau der Schaden, gegen den #528 gebaut ist. - ShutdownCoordinator: erst die Tuer schliessen, dann auf offene Arbeiten warten, Frist zwei Minuten. Vorher brach TaskScanner.DisposeAsync mitten in ProcessAsync ab, sodass die Aufgabe bis zum Lease-Ablauf auf "running" stehenblieb. - GET /api/instanz/puls hinter dem Socket-Gate: Phase und offene Arbeiten. Weiter gefragt statt gemeldet - ein Puls, den die Instanz von sich aus schickt, fehlt genau dann, wenn sie haengt. - Eskalationsleiter: drei Durchgaenge ohne Antwort, einmal um ein Ende bitten, nach 30s beenden und den Vollzug abwarten, gemeldet als Absturz. - EnsureDeadAsync vor jedem Start. Weiteres aus dem Review: - .gitignore verankert: "Instances/" passte auch auf src/ClawdDotNet.Core/Instances/. InstanceEndpoint.cs und InstanceLayout.cs waren dadurch nie eingecheckt. - Das WebUI-Token stand im Protokoll des Managers. Konsole ja, Datei nein. - Ein Klick auf "Instanz anlegen" loeste requestSubmit() zweimal aus. - [Obsolete] auf WebServerPort wieder entfernt: sechs Warnungen, die niemand abstellen konnte, solange E-M5 nicht fertig ist. - Die Wiederherstellung bricht nicht mehr ab, wenn der Browser weggeht. - Entwicklungspfade zum Instanzmanager aus Segmenten statt mit Rueckstrichen, und der Port kommt aus manager.json statt fest aus der Zeile. Offen und gemeldet: --managed hebelt die Lizenzpruefung aus (#535). 806 Tests gruen, 0 Warnungen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
d44bbeac1d |
Uebergabehinweise fuer den Frontend-Agenten (#531)
Der C#-Teil des Instanzmanagers ist fertig; was fehlt, ist die Oberflaeche. Abschnitt 11 im Konzeptpapier ist die Uebergabe dafuer: der Auftrag in einem Satz, die harte Grenze (keine .cs-Datei, git status darf nur wwwroot zeigen), die vollstaendige API mit den Antwortcodes, die eine eigene Behandlung verdienen, eine Reihenfolge, zwei Fallen und die drei Punkte, die ausdruecklich liegen bleiben, weil sie C# sind. Der WebUI-Leitfaden war an vier Stellen ueberholt und haette den naechsten Agenten in die Irre geschickt: wwwroot liegt nicht mehr in ClawdDotNet.Web, die Oberflaeche laeuft nicht mehr im Prozess der Instanz, Port und Token stehen in manager.json statt in InstanceSettings.json, und es gibt nicht mehr ein /api fuer eine Instanz. Ein Korrekturblock steht jetzt vorweg und verweist auf Abschnitt 11; der Rest des Leitfadens - kein innerHTML, kein Paketmanager, Token nur im sessionStorage, Farben aus app.css - gilt unveraendert. Die Arbeit selbst ist #531 und steht auf der Roadmap. Was nur in einer Datei steht, ist keine eingeplante Arbeit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
7d4e8b3096 |
Autostart durch Manager, mit Sicherungsautomat (#528)
Entschieden vom Benutzer am 2026-09-08. Der Schalter heisst autostartByManager und steht in InstanceSettings.json - bei der Instanz, nicht beim Manager. ZWEI DINGE IN EINEM SCHALTER, weil es dieselbe Zusage ist: Der Manager startet diese Instanz, wenn er selbst hochkommt, und er startet sie wieder, wenn sie abstuerzt. Ohne den Schalter ruehrt er nichts an - ein Manager, der nach einem Neustart der Maschine alles hochfaehrt, was er findet, startet auch das, was jemand mit Absicht angehalten hat. Ausgeschaltet vorbelegt. DER SICHERUNGSAUTOMAT ist der eigentliche Inhalt. Wieder hochzufahren ist die einfache Haelfte; die schwierige ist zu erkennen, wann man es lassen muss. Nach drei Neustarts in zehn Minuten (maxRestartsInWindow, restartWindowMinutes) setzt der Manager aus und meldet es. Die Instanz bleibt dann aus, bis jemand sie von Hand startet - und dieser Start raeumt den Zaehler ab, denn wer von Hand startet, hat entweder etwas geaendert oder weiss, was er tut. Das Zeitfenster wandert: Eine Instanz, die einmal im Monat abstuerzt und wieder hochkommt, laeuft nie in die Grenze. Nur bei einem Absturz, nicht wenn eine Instanz verstummt. Eine stumme Instanz lebt noch; sie neu zu starten hiesse, sie erst abzuschiessen, und ob der Manager das von sich aus darf, ist nicht entschieden. Als offene Frage aufgeschrieben - genau dieser Zustand war der Anlass des Vorhabens. Der Schalter steht bei der Instanz, weil er eine Eigenschaft dieser Instanz ist und weil die Instanzdatei dem Instanzprozess gehoert: Sie vom Manager schreiben zu lassen, waehrend die Instanz laeuft, waeren zwei Schreiber auf einer Datei. Der Manager liest ihn nur; geaendert wird er auf der Einstellungsseite der Instanz. EIN DEFEKT, den erst diese Tests gezeigt haben: StartAsync gab "laeuft schon" zurueck, wenn die Aufsicht die Instanz fuer laufend hielt - ohne nachzusehen. Zwischen zwei Aufsichtsdurchgaengen liegen aber Sekunden, und in denen kann sie wegbrechen. Wer in dieser Luecke "starten" verlangte, bekam einen Erfolg, hinter dem nichts stand, und der naechste Durchgang meldete einen Absturz, den niemand mehr erwartete. Jetzt wird gefragt, bevor zugestimmt wird. UND EIN TESTDOUBLE, das die Wirklichkeit nicht abbildete: Der falsche Socket antwortete unabhaengig davon, ob ein Prozess lief. Damit war jeder Testaufbau, der die Antwort vor dem Hochfahren hinterlegte, stillschweigend ein anderer Test als beabsichtigt - eine Antwort sagt dem Manager "laeuft bereits", er uebernimmt, und der Starter wird nie angefasst. Dreimal passiert. Der falsche Socket haengt jetzt am falschen Starter. Sicherungen im Manager sind als #530 zurueckgestellt, mit Ausloeser. Vorab entschieden ist dort nur eines: Zurueckspielen ausschliesslich bei inaktiver Instanz. 19 neue Tests. Build ohne Warnungen, 793 Tests gruen, 8 uebersprungen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
db7abf699f |
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> |
||
|
|
a511480b77 |
Instanzmanager Stufe 4: eine Adresse, ein Zugang, alle Instanzen (#528, E-M5)
Der Managerprozess. ClawdDotNet.Instanzmanager ist eine Konsolenanwendung: Lizenz pruefen, uebernehmen was laeuft, Weboberflaeche aufhaengen, warten. Beim Herunterfahren beendet er keine Instanz. Zwei neue Projekte. ClawdDotNet.Manager.Web traegt die Weboberflaeche - ohne jeden Verweis auf ClawdDotNet.Web, denn dort haengt App und daran sechzehn Werkzeugprojekte. ClawdDotNet.ManagerApp ist der Einstiegspunkt. wwwroot ist aus der Instanz in den Manager gezogen. DER SCHNITT DER HTTP-FLAECHE: Unter /api/verwaltung steht, was den Manager angeht - auflisten, anlegen, starten, anhalten. Alles andere unter /api geht unveraendert an eine Instanz. Er leitet weiter, er implementiert nicht. Welche Instanz gemeint ist, sagt die Kopfzeile X-Instanz; laeuft genau eine, ist sie gemeint, und laufen mehrere, wird nachgefragt statt geraten - eine Anfrage an die falsche Instanz ist schlimmer als eine abgelehnte. Der zusammengefuehrte Ereignisstrom haelt je laufender Instanz eine Zuleitung und schreibt an jedes Ereignis, von wem es kommt. Ergaenzt statt verpackt: Ein Umschlag waere einfacher gewesen, haette aber jede Ansicht der Weboberflaeche zum Umschreiben gezwungen. ABNAHME gegen laufende Prozesse: 401 ohne Token, Oberflaeche ohne Token 200, Instanz ueber den Manager gestartet und angehalten, /api/info und /api/status unverfaelscht durchgereicht, /events/logs mit "instanz":"Instance-Test" an jeder Zeile. Manager abgeschossen: Instanz laeuft weiter. Manager neu gestartet: "1 Instanzen bekannt, 1 laufen bereits" - uebernommen. E-M6 damit in beide Richtungen belegt. DREI DEFEKTE, die erst der Lauf gezeigt hat: 1. Der Manager hing an einer Konsolenabfrage nach dem Lizenzschluessel. Ein Test auf Console.IsInputRedirected reicht dafuer NICHT: Er beantwortet "ist die Eingabe umgeleitet", nicht "kann jemand antworten" - ein Prozess ganz ohne Konsole, der gefaehrlichste Fall, ist nicht umgeleitet. Der Manager fragt jetzt gar nicht. 2. Eine unlesbare manager.json wurde stillschweigend durch Vorgaben ersetzt: falsches Instanzverzeichnis, anderer Port, Lizenzfrage - und nichts sagte, woran es lag. LoadProblem meldet den Grund jetzt. 3. Der Instanzprozess erbte CLAWD_CONFIG_DIR vom Manager und legte sich in dessen Konfigurationsverzeichnis eine eigene Settings.json an. Eine Umgebungsvariable vererbt sich, ein Argument nicht - der Manager nimmt sein Verzeichnis jetzt ueber --config. SharedLoggerProvider ist nach Core gezogen: Es gibt jetzt zwei Webhosts, die dasselbe brauchen, und sie duerfen einander nicht kennen. NOCH OFFEN in dieser Stufe: Die Weboberflaeche kennt noch keine Instanzen - Instanzauswahl, X-Instanz und die Verwaltungsansicht sind Arbeit an wwwroot. Und webServerPort steht noch in der Instanz. Build ohne Warnungen, 775 Tests gruen, 8 uebersprungen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
cb56175d20 |
Instanzmanager: Lizenz und Sub-Token wandern in den Manager (#528, E-M3)
Neues Projekt ClawdDotNet.Licensing. LicenseGate, LicenseWatch, LicenseInfo und ILicensePrompt sind aus ClawdDotNet.App dorthin gezogen, weil zwei Prozesse dieselbe Lizenzpruefung brauchen und keiner von beiden den anderen kennen darf. In Core konnte es nicht landen - dann zoege jedes der sechzehn Werkzeugprojekte das Deploymentcenter-SDK mit. Dabei ist die Kopplung an SettingsManager verschwunden. LicenseGate kennt jetzt nur ILicenseStore: Serveradresse lesen, Schluessel lesen und schreiben, speichern. Die Anwendung fuehrt ihn in Settings.json, der Manager in manager.json. Der Torwaechter prueft Schluessel; Dateien verwaltet er nicht. Auch die Anwendungsversion kommt als Parameter statt aus einem globalen Zugriff - diese Schicht weiss nicht, welche Anwendung sie benutzt. ManagerCore ist die Klammer: eigene Einstellungen, Lizenz, Register, Meldeweg. Drei Regeln: - Ohne gueltige Lizenz startet er keine Instanz. Laufende werden trotzdem in die Liste genommen - man soll sie sehen und anhalten koennen. - Ein Widerruf haelt alle an. Der einzige Fall, in dem der Manager das von sich aus tut. Ein Serverausfall gehoert ausdruecklich nicht dazu; das SDK trennt Urteil und gescheiterten Versuch, und nur das Urteil kommt hier an. Sonst naehme ein Netzproblem saemtliche Installationen mit. - Ohne hinterlegte Lizenzpruefung sperrt er nichts, sonst gaebe es eine Henne-Ei-Sperre, bevor jemand einen Schluessel eintragen kann. Sub-Token je Instanz: Der Manager haelt das Master-Token und tauscht es beim ANLEGEN einer Instanz gegen ein eigenes (watchdog:ping, bugtracker:report, einzeln widerrufbar). Beim Anlegen und nicht beim ersten Start, weil die Instanzdatei dann zweifelsfrei niemandem gehoert - sie spaeter zu schreiben, waehrend der Instanzprozess laeuft, hiesse zwei Schreiber auf einer Datei. Fuer Instanzen, die es vor dem Manager schon gab, wird es vor dem Start nachgeholt. Danach fragt er ueber whoami nach, ob das Token an ein Projekt gebunden ist (SDK 2.8.1). Ein fehlgeschlagener Tokenbezug haelt die Instanz nicht auf. NOCH NICHT VOLLSTAENDIG: Die Instanzen pruefen die Lizenz weiterhin selbst. Das laesst sich erst abschalten, wenn eine Instanz feststellen kann, ob ein Manager da ist - vorher entstuende eine Fassung ganz ohne Durchsetzung. Und ein Testfehler, der zweimal derselbe war: Die Socket-Antwort war hinterlegt, BEVOR der Manager hochfuhr. Damit sagt man "diese Instanz laeuft bereits", der Manager uebernimmt sie, der Starter wird nie angefasst - und der Test prueft etwas anderes, als er behauptet. Es gibt jetzt eine Hilfsmethode, die das ausschliesst. Build ohne Warnungen, 774 Tests gruen, 8 uebersprungen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
72b0764d1a |
Instanzmanager: Register, Einstellungen und stellvertretende Meldung (#528)
Der zweite Teil von Stufe 3. Die Aufsicht ueber eine einzelne Instanz stand schon; jetzt gibt es die Klammer darum und den Weg nach draussen. InstanceRegistry haelt je Instanz eine Aufsicht. Zwei Zusagen, beide aus E-M6: Beim Start wird UEBERNOMMEN, nicht gestartet - ein Manager, der beim Hochkommen alles hochfaehrt, was er findet, startet nach einem Neustart der Maschine auch das, was jemand mit Absicht angehalten hat. Und beim Beenden wird nichts beendet: Wer den Manager schliesst, will den Manager schliessen. Einzige Ausnahme ist StopAllAsync fuer einen Grund, der alle betrifft - und der heisst Lizenzwiderruf. SupervisionReporter macht aus einem Befund eine Bugtracker-Meldung, stellvertretend: mit Prozesskennung, Abschiedscode und dem Ausschnitt aus dem Instanzprotokoll, der noch auf der Platte liegt. Der Idempotenzschluessel ist stabil je Instanz und Art - stuerzt dieselbe Instanz wiederholt ab, zaehlt der Server hoch, statt den Bugtracker mit Zwillingen zu fuellen. Ein leerer Protokollauszug ist dabei die aussagekraeftigste Zeile der Meldung und wird ausdruecklich als solche geschrieben. Genau das war der Zustand am 2026-09-08: Der Prozess wurde erschlagen, bevor sein Schreibpuffer geleert war, und hinterliess nichts. manager.json traegt die Felder aus Abschnitt 6 des Konzepts und sonst nichts. Lizenzschluessel, Master-Token und Web-Token liegen darin verschluesselt und zur Laufzeit im Klartext - dieselbe Bauart wie die Anwendungseinstellungen, mit Absicht. Unsinnige Aufsichtswerte werden eingefangen, weil die Datei von Hand bearbeitbar ist. InstanceLayout ist nach Core gezogen (ResolveLogDirectory, ResolveBackupDirectory). Der Manager braucht das Protokollverzeichnis einer Instanz fuer den Auszug in der Meldung und darf ClawdDotNet.App nicht kennen; dieselbe Rechnung an zwei Stellen zu fuehren waere die schlechtere Antwort. AppHost leitet nur noch weiter. EIN DEFEKT, den erst die eigenen Tests gezeigt haben: Eine angehaltene Instanz erschien im Register als "Instance-Alpha" statt "Alpha". Die Aufsicht kennt den Namen erst, wenn die Instanz einmal geantwortet hat, und eine angehaltene tut das nie - waehrend genau diese Ansicht der Manager anzeigt. Das Register fuehrt den Namen jetzt aus InstanceSettings.json mit. Und ein Testdouble, das zu viel behauptet hat: Der falsche Socket antwortete fuer jedes Verzeichnis dieselbe Instanz. Das laesst Tests gruen werden, die im Betrieb zwei Instanzen verwechseln wuerden; er antwortet jetzt je Verzeichnis. 29 neue Tests. Build ohne Warnungen, 766 Tests gruen, 8 uebersprungen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
4ef6d714a8 |
Instanzmanager Stufe 3: Prozessaufsicht, Start und Stopp (#528)
Der Anlass des ganzen Vorhabens: Am 2026-09-08 hat sich eine Instanz aufgehaengt und wurde von Windows beendet. Zu diesem Vorgang steht keine einzige Zeile in den Instanzprotokollen, kein Bugtracker-Eintrag, kein Watchdog-Alarm - weil Meldeweg und Watchdog in genau dem Prozess lebten, ueber den sie haetten berichten sollen. Ab jetzt sieht jemand anders hin. Neu ist ClawdDotNet.Manager mit genau EINEM Projektverweis: Core. Das ist keine Sparsamkeit, sondern die halbe Architektur - App schleppt sechzehn Werkzeugprojekte hinter sich her, und "keine Werkzeuge im Manager" soll eine Eigenschaft des Bauplans sein und keine Absichtserklaerung. DIE ENTSCHEIDUNG, AN DER ALLES HAENGT: Die Aufsicht fragt den Socket, nicht die Prozessliste. Die Prozessliste sagt, dass etwas da ist. Sie sagt nicht, ob es noch arbeitet - und genau das war der Zustand, den niemand bemerkt hat. Ein Durchgang kennt drei Antworten: Socket antwortet, sie laeuft. Socket schweigt und der Prozess ist weg, Absturz mit Abschiedscode. Socket schweigt und der Prozess lebt, verstummt - aber erst nach mehreren Fehlversuchen in Folge, denn ein Alarm bei jedem Aussetzer ist nach einer Woche der Alarm, den niemand mehr liest. Ein Start gilt erst, wenn die Instanz antwortet. Zwischen "der Prozess laeuft" und "die Instanz laeuft" liegen Datenbank, Agenten und Kestrel; wer nur auf Process.Start wartet, haelt eine Instanz fuer gestartet, die gleich an einer kaputten Konfiguration scheitert. Angehalten wird durch Bitten. Neu auf der Instanzseite: POST /api/instanz/beenden, ausschliesslich ueber den Socket - ueber TCP gibt es den Endpunkt nicht, auch mit gueltigem Token nicht, und er antwortet dort 404 statt 403. Die Lebensdauer einer Instanz gehoert dem Manager; eine Browsersitzung soll den Prozess, der sie bedient, nicht beenden koennen. Ausgeloest wird der Wunsch erst nach dem Absenden der Antwort (Response.OnCompleted), sonst bekaeme der Manager statt einer Zusage einen Verbindungsabbruch und hielte ihn fuer einen Fehlschlag. Wiederfinden nach einem Managerausfall (E-M6): Die Zustandsdatei instance-state.json ist der Hinweis, der Socket ist der Beweis. Erst wird gefragt, wer da antwortet; nur bei gleicher Instanzkennung wird die Prozesskennung aus der Datei angefasst. Andersherum fuehrt eine wiederverwendete Nummer nach einem Neustart der Maschine geradewegs dazu, ein fremdes Programm zu beaufsichtigen und beim Anhalten zu beenden. Selbsttaetiger Neustart ist bewusst NICHT gebaut. Die Abnahmebedingung lautet "merkt es und meldet es", und zum Neustarten trifft das Konzept keine Entscheidung; eine Instanz in einer Schleife wieder hochzufahren, die jedes Mal abstuerzt, waere die falsche Vorgabe fuer etwas, das niemand entschieden hat. Als offene Frage aufgeschrieben. ABNAHME, mit echten Prozessen gemessen: Manager startet Instanz Test in 0,7 s, identifiziert sie ueber die Named Pipe, schreibt die Zustandsdatei (pid 54476, id d68af6fd). Prozess von aussen abgeschossen. Naechster Durchgang: Crashed, Code -1, meldenswert, Zustandsdatei weggeraeumt. Dazu 20 Tests gegen gesteuerte Prozesse - ein Absturz zum gewuenschten Zeitpunkt und eine wiederverwendete Prozesskennung sind mit einem echten Programm nicht herzustellen. Noch offen in dieser Stufe: Instanzen anlegen, Lizenz im Manager, Sub-Token je Instanz, und der Managerprozess selbst. Build ohne Warnungen, 737 Tests gruen, 8 uebersprungen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
8686d13999 |
Instanzmanager Stufe 2: Kestrel auf dem Socket, Instanz kopflos (#528)
Eine Instanz ist jetzt ohne Port ansprechbar. InstanceEndpoint liefert die Adresse: unter Linux <Instanz>/manager.sock, unter Windows eine Named Pipe, deren Name aus einem SHA-256-Fingerabdruck des Instanzpfades entsteht. Zwei Instanzen bekommen damit zwangslaeufig zwei Adressen, ohne dass jemand etwas vergeben muss - genau der Unterschied zur Vorbelegung 7001, um die sich zwei Instanzen stillschweigend streiten. Der Socket ist immer da, auch ohne Weboberflaeche. Er gehoert nicht zu #494, sondern ist die Steuerflaeche der Instanz: webUiEnabled schaltet den TCP-Zugang, nicht den Socket. WebUiHost heisst deshalb jetzt InstanceHttpHost - ein Kestrel, zwei Zugaenge. Ueber TCP gilt Token-Pflicht, ueber den Socket nicht: Dort steht die Grenze am Dateisystem (0600 unter Linux, CurrentUserOnly bei der Named Pipe, explizit gesetzt statt auf die Vorgabe vertraut). Wer die Socketdatei oeffnen darf, sieht ohnehin in das Verzeichnis, in dem alles liegt, was ein Token schuetzen wuerde. Woran die beiden Zugaenge auseinandergehalten werden, ist der Punkt, an dem ein Irrtum teuer waere. Bei Socket-Verbindungen stehen in HttpContext.Connection keine IP-Adressen - daraus zu schliessen "keine IP, also Socket" waere eine Vermutung an der Stelle, an der ein Torwaechter steht, und sie irrt in die falsche Richtung: Im Zweifel liesse sie eine TCP-Anfrage ohne Token durch. Der Socket-Zuhoerer haengt deshalb jeder Verbindung selbst eine Marke an (LocalTransport, Verbindungs- Zwischenschicht ueber ListenOptions.Use); wo sie fehlt, gilt Token-Pflicht. Ein belegter Port kostet nur noch die Weboberflaeche. Vorher gab TryStart in dem Fall null zurueck und die ganze HTTP-Flaeche war weg. Seit dem Socket ist das die falsche Rangfolge: Ihn zu verlieren, weil eine zweite Instanz laeuft, hiesse die Instanz unerreichbar zu machen - in genau dem Fall, fuer den es den Manager gibt. Kopfloser Betrieb ueber --headless --instance <Pfad>. Die Verzweigung sitzt in Program.Main vor BuildAvaloniaApp, damit auf einem Server ohne Bildschirmsitzung kein Fenstersystem angefasst wird. Gefragt wird nichts: Instanz aus dem Argument, Lizenz ueber das bereits vorhandene NonInteractiveLicensePrompt, Telegram-Anmeldung aus. Nachgemessen, nicht angenommen: Kopflose Instanz auf Instance-Test gestartet, kein Fenster, und eine rohe HTTP/1.1-Anfrage aus einem fremden Prozess (PowerShell, direkt auf die Pipe) bekam 200 OK auf /api/info, ohne Token. Das ist die Abnahmebedingung fuer Stufe 2. Korrektur zur eigenen Ankuendigung: webServerPort entfaellt nicht mit Stufe 2, sondern mit Stufe 4. Solange kein Manager die Weboberflaeche traegt, hiesse Wegnehmen, sie ersatzlos abzuschalten. Zwei Luecken bleiben offen und gehoeren auf die Linux-Testmaschine: Die Socketdatei-Faelle sind unter Windows gegenstandslos und werden dort mit sichtbarer Begruendung uebersprungen - der Unix-Domain-Socket selbst ist auf der Entwicklungsmaschine also ungeprueft, obwohl er die Zielplattform ist. Und das geordnete Ende auf SIGTERM liess sich hier nicht ausloesen: Windows kennt das Signal fuer einen fensterlosen Prozess nicht. Build ohne Warnungen, 714 Tests gruen, 8 uebersprungen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
facd21459c |
Instanzmanager Stufe 1: Protokolle und Sicherungen je Instanz (#528)
Mehrere Instanzen sollen unabhaengig voneinander laufen. Heute tun sie das nicht: Sie teilen sich Protokollverzeichnis, Sicherungsordner und Sicherungszeitplan. In einer gemeinsamen Startup.log standen abwechselnd Zeilen zweier Instanzen, ohne Kennzeichnung, welche gerade spricht -- im Mehrinstanzbetrieb ist damit jede Fehlersuche Ratearbeit. Genau in dieser Lage ist der Aufhaenger aus #529 entstanden. Fuenf Schluessel wandern aus AppSettings nach InstanceSettings.json: logDirectory, backupDirectory, backupKeepCount, autoBackupEnabled, autoBackupTime. Leer heisst jetzt <Instanz>/Logs beziehungsweise <Instanz>/Backups; ein relativer Wert zaehlt weiterhin gegen das Instanzverzeichnis, nicht gegen das Arbeitsverzeichnis des Prozesses (#375 bleibt gewahrt). autoBackupEnabled und autoBackupTime standen in der Planung nicht, sind aber mitgegangen: Ein Schalter, der die taegliche Sicherung fuer eine Instanz einschaltet und sie damit fuer alle einschaltet, ist derselbe Fehler wie ein Ordner fuer alle -- und zwei von vier Sicherungsfeldern zu verschieben hinterliesse eine Einstellungsseite, auf der die Haelfte anwendungsweit gilt. Keine Uebernahme der Altwerte, aber eine Ansage: SettingsManager. AbandonedKeys meldet die aufgegebenen Schluessel, solange sie noch in Settings.json stehen, und der Start protokolliert einmal, was nicht mehr gilt und wohin diese Instanz stattdessen schreibt. Ein anwendungsweiter Pfad, in alle Instanzen kopiert, waere wieder ein Ordner fuer alle. webServerPort bleibt vorerst stehen. Es entfaellt mit Stufe 2, sobald Kestrel auf dem Socket hoert; vorher wegzunehmen hiesse, die Weboberflaeche ohne Ersatz abzuschalten. Korrektur an der eigenen Befundlage: "Instanz A wirft die Sicherungen von Instanz B weg" war zu breit. Beide Rotationen filtern bereits nach dem Praefix backup_<Instanzname>_. Der reale Defekt ist enger, und ein Praefix ist keine Grenze: backup_Test_2_*.zip faengt mit backup_Test_ an, also zaehlt Test im gemeinsamen Ordner die Archive von Test_2 mit. Belegt in BackupSchedulerTests, das den alten Zustand eigens wiederherstellt. Nachgeprueft an der laufenden Installation, nicht nur im Test: Nach dem Umbau schreibt Instance-Test nach Instances/Instance-Test/Logs, das alte gemeinsame Verzeichnis bekommt keine Zeile mehr, und die Warnung zu den aufgegebenen Schluesseln erscheint genau einmal. Enthaelt ausserdem, was seit der Weboberflaeche liegengeblieben war: - #526: Instanzgeheimnisse wurden beim Speichern verschluesselt und beim Laden nie entschluesselt. LoadInstanceConfig hatte kein ConfigSecrets.Unprotect; ConfigLoader.LoadAsync macht es richtig, wird zur Laufzeit aber gar nicht aufgerufen. Der OpenRouter-Schluessel ging so verschluesselt an die API. - Ein offener Ereignisstrom hielt das Beenden fuenf Sekunden auf. Die Stroeme hingen nur an RequestAborted, das beim geordneten Herunterfahren nicht feuert; jetzt zusaetzlich an ApplicationStopping. Der Fang in WebUiHost gilt dazu ohne Bedingung auf RequestAborted -- mit ihr waere jeder offene Strom beim Beenden als Fehler im Bugtracker gelandet. - Nach der Anmeldung blieb die Weboberflaeche leer: #anmeldung { display:flex } schlaegt als ID-Selektor das hidden-Attribut. - docs/Instanzmanager-Konzept.md: Befund, die Entscheidungen E-M1 bis E-M6, der Schnitt zwischen Manager und Instanz und die sechs Stufen. Build ohne Warnungen, 709 Tests gruen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
928da7e6af |
Standardport fuer WebUI auf 7001 geaendert
- InstanceConfig.WebServerPort von 8080 auf 7001 vorbelegt - Dokumentation und WebUiOptionsTests nachgezogen |
||
|
|
1e9cb789c8 |
Weboberflaeche hinzugefuegt und Fachlogik nach App herausgeloest (#493, #494)
- ClawdDotNet.Web: Kestrel im Prozess der Anwendung, Token-Absicherung (TokenGate mit FixedTimeEquals), Endpunkte unter /api, Ereignisstrom unter /events (Server-Sent Events) und fortlaufendes Log-Streaming. - Weboberflaeche (wwwroot/): Vollstaendiges Single-Page-Frontend mit nativem HTML5, CSS3 und ES-Modulen ohne Buildschritt (strikt textContent, #-Routing, sofortiger Login-Sprung bei fehlendem Token, Light/Dark-Theme, lokale Barlow-Schriften). - ClawdDotNet.App: Fachlogik aus den Avalonia-ViewModels in Dienste herausgeloest (AgentAdministration, JobAdministration, ServiceAdministration, RunCoordinator) und ueber InstanceChange synchronisiert. - Tests: ClawdDotNet.Web.Tests und ClawdDotNet.App.Tests hinzugefuegt, alle 684 Tests erfolgreich. |
||
|
|
740649789e |
Eine Roadmap statt neun verteilter Listen
Der Stand lag ueber eine Bestandsaufnahme, drei Konzeptpapiere, vier Umsetzungsplaene und zwei Deploymentcenter-Dokumente verteilt - jedes mit eigener Reihenfolge, teils widersprueglich. Alle offenen Punkte daraus sind in docs/Roadmap.md zusammengefuehrt. Aufbau der neuen Roadmap - Statusvokabular: erledigt / beschlossen-offen / Entscheidung noetig / zurueckgestellt / Idee. Damit steht das Geparkte sichtbar drin, statt in einem Konzeptpapier zu verschwinden. - Herkunft-Spalte traegt das alte Kuerzel (S4, K2, B9, T4, F-A1, C1, DC1), damit die archivierten Papiere auffindbar bleiben, ohne sie zu lesen. - Abschnitt 1 Reihenfolge, 2 offene Entscheidungen, 3 die Vorhaben nach Bereich, 4 Ideenspeicher, 5 Chronik des Erledigten, 6 Modell-Einstufung, 7 Herkunftskarte. Was dabei sichtbar wurde - Neun Entscheidungen blockieren Arbeit, ohne dass sie Aufwand kosten - allen voran Matrix oder Rocket.Chat. Sie stehen jetzt gesammelt in Abschnitt 2 statt verstreut in den Diskussionsteilen der Konzepte. - B8 (keine Tiefenbegrenzung bei AgentComm) ist unveraendert offen. Das ist keine Theorie: A haelt sein Gate, waehrend es auf B wartet - ruft B nun A, warten beide bis zum Timeout. Der Testfall A13 dafuer fehlt bis heute. - Die vier Umsetzungsplaene vom 2026-08-05 sind alle unumgesetzt und waren in keiner Roadmap verzeichnet. Archiv Sechs Dokumente ziehen nach docs/archiv/: Bestandsaufnahme, Konzepte Backup/Finanz/Analyse, Linux-Portierung-Analyse, Lizenz-HardwareId-v2 (gegenstandslos - LicenseLabrador ist ersetzt), Deploymentcenter-Review und der 2.4-Integrationsplan. Sie bleiben als Begruendung lesbar, werden aber nicht mehr fortgeschrieben; das README ordnet jedes einzeln ein und warnt, dass ihre Quelltext-Verweise ins Leere gehen koennen. Bauplan bleibt Bauplan Taskboard, Audit, Staging, Memory, Agentenkommunikation, RocketChat und Deploymentcenter-Integration bleiben in docs/ - sie sind die Detailvorgabe fuer die Umsetzung, nicht Vorhabenlisten. Jedes bekommt oben eine Zeile, die seine Rolle und den Umsetzungsstand nennt und auf die Roadmap zeigt. Dasselbe fuer die vier Umsetzungsplaene: die Reihenfolge gilt in der Roadmap, nicht im Plan. Nebenbei repariert: Taskboard-Konzept und Teststrategie verwiesen auf AgentScheduler und ToolJobScheduler, die seit der Scanner-Konsolidierung geloescht sind. Alle Dokument-Verweise in docs/ sind geprueft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
2853541629 |
Fruehjahrsputz: WinForms-Altlast entfernt, Dokumentation nachgezogen
Die Avalonia-Portierung ist abgeschlossen, damit ist die in ClawdDotNet.slnx angekuendigte Aufgabe "WinForms-Oberflaeche entfernen" faellig. Der Stand davor liegt unter dem Tag vor-fruehjahrsputz-2026-08. Entfernt (56 Dateien, seit dem Herausloesen der Anwendungsschicht nicht mehr Teil des Builds): ClawdDotNet.csproj, Program.cs, sieben frm_*-Formulare, UI/, Models/, EmbeddedUI/, Properties/, Resources/, Services/, das alte Anwendungssymbol und Deploy-Build.ps1 (ersetzt durch deploy/publish.py). Dazu configs/*.json - Beispielkonfigurationen aus der Zeit vor dem Instanzverzeichnis, auf die nur noch die alten Prompts verwiesen. Die vier Entwicklungs-Prompts der Anfangszeit ziehen nach docs/archiv/ um, mit README, das ihren Stand einordnet. Eine Regel darin gilt weiter - die Pflichtfelder fetchedAt/dataAsOf/source der Internet-Tools -, deshalb Archiv statt Loeschen; der WebSearch-Plan verweist auf den neuen Pfad. Toter Code - PlaceholderPageViewModel samt Ansicht: Es gibt keinen Platzhalter-Bereich mehr, seit alle neun Seiten portiert sind. - Snappier als direkter Paketverweis: MongoDB.Driver loest es ohnehin auf dieselbe Fassung auf, der Verweis hob nichts an. Zwei Fehler, die dabei sichtbar wurden - Die taegliche Sicherung lief ins Leere. Die Oberflaeche bot sie an und schrieb Uhrzeit, Zielordner und Anzahl in die Einstellungen, aber der BackupScheduler wurde nirgends erzeugt. Jetzt am AppHost verdrahtet und in den geordneten Abbau aufgenommen. - SettingsPageViewModel hielt die vier Sicherungs-Einstellungen doppelt. Aus der Ansicht waren sie laengst verschwunden, gelesen und beim Speichern zurueckgeschrieben wurden sie weiter: Wer die Uhrzeit auf der Sicherungs-Seite aenderte und danach die Einstellungen speicherte, bekam den alten Wert zurueck. Pakete: keine bekannten Sicherheitsluecken mehr - SQLitePCLRaw.bundle_e_sqlite3 auf 2.1.13 angehoben. Microsoft.Data.Sqlite bringt 2.1.11 mit, darin steckt GHSA-2m69-gcr7-jv3q (NU1903, hoch). - SharpCompress bleibt als direkter Verweis stehen. Beim Aufraeumen erst als ungenutzt entfernt - dabei kam die von MongoDB.Driver gezogene Fassung 0.30.1 mit GHSA-6c8g-7p36-r338 zurueck. Der Verweis ist eine Anhebung, kein Ballast; das steht jetzt als Kommentar dabei. Dokumentation - Roadmap mit Statusblock: A1 und A3 erledigt, A2 nur zur Haelfte - Gate, Policy und Dienst greifen, aber keine Ansicht ruft ApproveAsync auf, ein gestagter Aufruf liegt unbeantwortet. Das ist jetzt Punkt 1 der Reihung. Rocket.Chat steht und kollidiert mit A5 (Matrix) - Entscheidung faellig. - Avalonia-Portierungsleitfaden -> Oberflaechen-Leitfaden: kein Auftrag mehr, sondern Beschreibung des Stands. - Bestandsaufnahme und Linux-Analyse als datierte Befunde gekennzeichnet; der teure Teil der Linux-Analyse (8.900 Zeilen WinForms) ist hinfaellig. - Verweise auf frm_*, WebView2 und ClawdDotNet.csproj in den lebenden Dokumenten richtiggestellt. Build fehlerfrei, 585 Tests gruen (6 uebersprungen). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
33d95a6c3f |
UI-Entwurf umgesetzt, Rocket.Chat-Tool, Deploymentcenter 2.4
Sicherungspunkt vor dem Aufraeumen. Buendelt die Arbeit, die seit dem Abschluss der Avalonia-Portierung im Arbeitsverzeichnis lag. Oberflaeche - Entwurf aus Mockup/ umgesetzt: Theme.axaml (Farben je Thema, Barlow als mitgelieferte Schrift), Icons.axaml (Symbolgeometrien), Shell.axaml (eigene ControlThemes statt Fluent umzufaerben). - Neue Steuerelemente StrokeIcon und BlueprintFrame, Seiten fuer Token-Verbrauch und Agenten-Chats, Werkzeug-Einstellungen als Seite statt eigenem Fenster, Texteditor-Fenster. - ThemeManager mit hellem und dunklem Thema; die beiden Pinsel-Konverter entfallen, weil ein fester Farbwert den Themenwechsel nicht ueberlebt. Rocket.Chat - Neues Tool-Projekt (Client, Konfiguration, Workspace-Dateien) nach der Bauform des Telegram-Tools: rocketchat_poll als Tool-Job, geweckt wird nur, wenn wirklich etwas anliegt. - send_file ist freigabepflichtig, send_message bewusst nicht: Der Raum ist Arbeitsraum, der Schutz sitzt an der Raum-Allowlist. - Konzept-Doc um die Messung gegen die echte Instanz 8.7 ergaenzt; drei Annahmen waren falsch und sind korrigiert. Deploymentcenter - DC6 (Update anwenden) und DC7 (Erstinstallation ueber setup.json) erledigt, DC3 fuer win-x64/dev; deploy/publish.py als Release-Strecke. - AppHost.DisposeAsync gegen doppeltes Herunterfahren gesperrt - sonst ueberschreibt eine zweite Abmeldung den Wartungszustand am Watchdog. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
b5bf97ae74 | feat(ui): complete Avalonia UI port with 7 main pages, tool settings & top MenuBar | ||
|
|
61a93ffa58 |
Umsetzungsplaene fuer vier neue Agenten-Tools angelegt
Aus Richards Ideensammlung, nach Sichtung des vorhandenen Codes: - FileRW-Papierkorb + Cleanup-Job: delete verschiebt nach .trash statt endgueltig zu loeschen, Aufraeumen ueber IToolJobProvider/ToolJobScheduler. Macht Loeschen reversibel und erlaubt damit, FileRW.delete im Staging von Approve auf Auto herunterzustufen. - AgentInspector: lesende Aufsicht ueber andere Agenten. Beleg-basiert (Audit/Receipts/Taskboard) statt datei-basiert; harte Allowlist, damit AgentSettings.json mit den API-Keys nicht in einen LLM-Kontext geraet. - AgentEditor-Haertung: Identity/Soul-Aenderungen ueber die vorhandene StagingPolicy freigabepflichtig machen, Selbstbearbeitung sperren, Audit + restore ergaenzen. Das Tool selbst existiert bereits. - WebSearch: Suche als eigenes Tool, Lesen bleibt bei WebFetch hinter der Domain-Whitelist. Kein agent-reach (Klartext-Cookies, Fremdprozess). Trennung Rechercheagent / handelnder Agent gegen Prompt Injection. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
1157d28588 |
Konfig- und Zustandsdateien atomar schreiben
File.WriteAllText kuerzt die Zieldatei zuerst auf null und fuellt sie dann. Bricht der Vorgang dazwischen ab, ist der alte Inhalt weg und der neue unvollstaendig. Das ist im Betrieb bereits eingetreten: In der Instanz TradingTeam lag eine TokenUsage.json.corrupt_..., die die Fehlerbehandlung beiseitegelegt hatte. Der Verbrauch bis dahin war verloren. AtomicFile schreibt in eine Nebendatei, erzwingt das Schreiben auf die Platte und ersetzt dann. Umgestellt sind ChatHistory, ChatContext, alle Instanz- und Agentenkonfigurationen, Identity und Soul, die App-Einstellungen sowie der Stock-Index. Zum Ersetzen wurde das Windows-Verhalten gemessen statt vermutet. Mit einem Leser, der die Zieldatei geoeffnet haelt: Freigabe des Lesers File.Move File.Replace Read scheitert scheitert ReadWrite scheitert scheitert ReadWrite | Delete scheitert funktioniert File.Move verlangt die Zieldatei exklusiv und scheitert deshalb immer, sobald jemand sie geoeffnet hat. Daher File.Replace — und ein Lesehelfer AtomicFile.ReadAllText, der das Loeschen freigibt, damit unsere eigenen Leser keinen Schreiber blockieren. Die Leser in InstanceDirectoryManager und beim Laden der Chatverlaeufe nutzen ihn jetzt. Zusaetzlich ein Schloss je Zieldatei: Zwei gleichzeitige Schreibvorgaenge auf dieselbe Datei sind ohnehin ein Rennen, ohne Serialisierung scheitern sie aber zusaetzlich mit "Zugriff verweigert". Fuer fremde Leser wie Virenscanner bleibt eine Wiederholung mit Wartezeit. 366 Tests gruen (218 Core, 148 Tools). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
4747835fa1 |
K1: Langzeitgedaechtnis fuer Agenten
Geplante Agenten begannen bei jedem Cron-Lauf bei null. Ein Agent, der alle 30 Minuten lief, wusste nichts von seinem letzten Durchgang — er rief dieselben Quellen ab, zog dieselben Schluesse und konnte keine Entwicklung ueber Zeit verfolgen. Das war zugleich die groesste Faehigkeitsluecke und eine dauerhafte Token-Verschwendung. Speicher-Fundament SqliteStorage buendelt den Zugang zur Instanz-Datenbank und aktiviert WAL, busy_timeout und Connection-Pooling. Vorher oeffnete jeder Aufruf eine Verbindung ohne diese Einstellungen; bei mehreren gleichzeitig schreibenden Agenten gab das "database is locked". Das sah nach einer Grenze von SQLite aus, war aber nur fehlende Konfiguration. Zwei Tests decken das gezielt ab. Gedaechtnis Typisierte Tabelle statt JSON in einer Wert-Spalte — nur so laesst sich filtern, sortieren und spaeter auswerten. Das Schema ist schlicht gehalten, damit eine MySQL-Variante spaeter dieselbe Struktur mit wenigen Dialektunterschieden bekommen kann. Der wichtigste Teil ist der optionale Schluessel: Erneutes Merken darunter aktualisiert den Eintrag, statt einen zweiten anzulegen. Ohne das wuechse das Gedaechtnis eines halbstuendlich laufenden Agenten um 48 Eintraege pro Tag zur selben Sache. Beobachtungen ohne Schluessel sammeln sich weiterhin an, wenn ein Verlauf entstehen soll. Der Abruf sortiert nach Wichtigkeit, dann Aktualitaet — wesentlich, weil das Ergebnis begrenzt wird und bei einer Kappung das Wichtigste ueberleben muss. Zusaetzlich greift eine Zeichenobergrenze, damit ein Abruf den Kontext nicht sprengt. Die Trennung privat/geteilt ist absichtlich dieselbe wie beim FileRW-Tool, damit das Konzept fuer Agenten wiedererkennbar bleibt. Beim Testen fiel auf, dass das Maskieren der LIKE-Platzhalter falsch war: Die Zeichen wurden entfernt statt maskiert, wodurch eine Suche nach einem Prozentzeichen zu einem leeren Muster und damit zu einem Treffer auf alles wurde. Jetzt mit ESCAPE-Klausel. 338 Tests gruen (190 Core, 148 Tools). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
8604fa30c7 |
S7: Zugangsdaten in Konfigurationsdateien verschluesseln
OpenRouter-Schluessel, Datenbank-Verbindungszeichenfolgen samt Passwort, Mail-Zugangsdaten und das Telegram-2FA-Passwort lagen im Klartext in AgentSettings.json und InstanceSettings.json. Wer die Dateien lesen konnte — ein Backup, eine Dateifreigabe, ein versehentlicher Commit — hatte alle Zugaenge. SecretProtector nutzt DPAPI im Benutzerkontext: Die Werte lassen sich nur vom selben Windows-Benutzer auf demselben Rechner lesen. Das schuetzt gegen Weitergabe der Datei, nicht gegen einen Angreifer, der bereits als dieser Benutzer laeuft — fuer einen lokal laufenden Dienst die angemessene Stufe. Verschluesselte Werte tragen ein Praefix. Dadurch bleibt Klartext aus bestehenden Konfigurationen lesbar und wird beim naechsten Speichern automatisch uebernommen; vorhandene Installationen laufen ohne Zutun weiter. Ein Wert, der sich nicht entschluesseln laesst — etwa nach Benutzer- oder Rechnerwechsel — wird gemeldet statt stillschweigend als Klartext durchgereicht. Sonst ginge ein unbrauchbarer Schluessel an die API und der Fehler waere schwer zuzuordnen. ConfigSecrets entscheidet anhand der Feldnamen, welche Werte betroffen sind. Das ist noetig, weil die Tool-Konfiguration ein freies Woerterbuch ist. Beim Speichern werden die Werte nur fuer den Schreibvorgang verschluesselt und danach wieder entschluesselt, damit die laufende Instanz weiterarbeiten kann. 309 Tests gruen (161 Core, 148 Tools). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
cbb8ac22bc |
SSRF-Schutz, Pfadpruefung und Retry-Logik
S5 — Die Domain-Whitelist wurde nur auf die Ausgangs-URL angewendet, HttpClient folgte Weiterleitungen aber selbst. Eine erlaubte Domain konnte damit auf beliebige interne Adressen weiterleiten: Router, NAS, der Git-Server im LAN, Cloud-Metadatendienste. Der Agent haette deren Inhalt zurueckgeliefert. UrlGuard prueft Schema, private und lokale Netzbereiche sowie die Whitelist. AllowAutoRedirect ist abgeschaltet; Weiterleitungen werden einzeln aufgeloest und JEDER Zwischenschritt erneut geprueft, begrenzt auf fuenf Spruenge. Nebenbei behoben: Die alte www-Behandlung ersetzte die Zeichenfolge ueber den ganzen Hostnamen, aus mywww.example.com wurde myexample.com. Und die Subdomain-Pruefung achtet jetzt auf den Punkt, sodass example.com.attacker.net nicht mehr als Treffer fuer example.com durchgeht. S6 — Die Pfadpruefung in FileRW verglich nur Zeichenketten-Praefixe. Ohne abschliessenden Verzeichnistrenner erlaubte ein Root wie Agent-X\Workspace damit auch Zugriffe auf Agent-X\Workspace-Backup. WorkspacePath vergleicht jetzt auf Verzeichnisgrenzen und lehnt zusaetzlich absolute Pfade, UNC-Freigaben und Alternate Data Streams ab. Das Dateisystem wird in den Tests bewusst nicht abstrahiert — sie sollen die echte Windows-Pfadsemantik pruefen. Eine Abstraktion wuerde genau die Fehlerklasse verstecken, um die es geht. B12 — Der Client warf bei jedem Nicht-2xx sofort; ein einzelnes HTTP 429 beendete damit einen kompletten geplanten Lauf, obwohl Rate-Limits und kurze 5xx bei OpenRouter Normalbetrieb sind. RetryPolicy wiederholt 408/425/429/5xx mit exponentiellem Backoff und Streuung, respektiert ein Retry-After des Servers und deckelt die Wartezeit. Dauerhafte Fehler wie 401 werden nicht wiederholt. Die Wartefunktion ist injizierbar, damit die Tests nicht wirklich warten. 264 Tests gruen (116 Core, 148 Tools). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
e5067cae70 |
Sicherheitsluecken S1, S2 und S3 schliessen
Neues Testprojekt tests/ClawdDotNet.Tools.Tests. Die Angriffsfaelle aus der Bestandsaufnahme bleiben darin dauerhaft als Testfaelle dokumentiert — zusammen mit Gegenproben, damit die Fixes nicht zu streng werden und legitime Nutzung blockieren. S3 — DirectAPI gab die abgerufene URL als Quelle an das Modell zurueck, samt API-Schluessel im Query-String. Der Schluessel landete damit im Konversationskontext, wurde bei jedem Folgeschritt erneut gesendet, in ChatContext.json geschrieben und in die Logs uebernommen. UrlSanitizer maskiert sensible Query-Parameter; auch die Fehlermeldungen sind betroffen und werden bereinigt. S2 — Die Kanal-/Video-Angabe wurde ungeprueft in eine Argument-Zeichenkette fuer yt-dlp interpoliert. UseShellExecute=false verhindert Shell-Metazeichen, nicht aber Options-Injection: yt-dlp kennt die Option --exec, die beliebige Befehle ausfuehrt. Kritisch, weil der Agent untrusted Inhalte verarbeitet — eine Prompt-Injection darin konnte ihn dazu bringen, genau so einen Wert zu setzen. YouTubeUrl validiert Handles und URLs gegen die zulaessigen YouTube-Hosts und lehnt alles ab, was mit einem Bindestrich beginnt. Die Argumente gehen jetzt einzeln ueber ProcessStartInfo.ArgumentList, die Adresse steht hinter dem Optionsende-Trenner. Der ffmpeg-Aufruf wurde ebenso umgestellt. S1 — Die Tabellen-Whitelist suchte den erlaubten Namen als Teilzeichenkette irgendwo im Statement, auch in Kommentaren. Bei einer Freigabe fuer prices genuegte deshalb ein DELETE auf users mit einem Kommentar, der prices enthielt, um eine beliebige Tabelle zu loeschen. Umgekehrt galten harmlose Abfragen, die ein Schluesselwort nur als Wert enthielten, faelschlich als Schreibzugriff. SqlGuard entfernt zuerst Kommentare und String-Literale, lehnt mehrere Statements ab, bestimmt die Operation am ersten Schluesselwort und extrahiert Tabellennamen gezielt hinter FROM/JOIN/INTO/UPDATE/TABLE — inklusive kommagetrennter Listen mit Aliassen. JEDE referenzierte Tabelle muss freigegeben sein, nicht irgendeine. Ohne Whitelist wird nichts durchgelassen. Die MongoDB-Pruefung vergleicht den Collection-Namen jetzt exakt statt per Teilzeichenkette. 178 Tests gruen (91 Core, 87 Tools). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
69b5704add |
Prompt-Caching, Tool-Ergebnis-Kappung und Kostenerfassung
T1 — Prompt-Caching. Bisher wurde bei jedem Schritt eines Runs der komplette Prompt neu berechnet, inklusive Tool-Definitionen und System-Prompt, die sich nie aendern. Bei zehn Schritten und einem 15k-Praefix sind das 150.000 statt 15.000 Eingabe-Tokens. ChatMessage bekommt dafuer einen eigenen JsonConverter: Der Inhalt geht weiterhin als String raus, bei gesetztem CacheBreakpoint jedoch als Blockarray mit cache_control. Beim Lesen werden beide Formate akzeptiert, damit bestehende ChatContext.json weiter geladen werden koennen. PromptCache setzt zwei Breakpoints: einen auf den System-Prompt (deckt Tool-Definitionen und System-Prompt ab) und einen rollierenden auf die letzte Nachricht mit Inhalt. Vorherige Markierungen werden vorher entfernt, damit sie sich nicht ansammeln. Aktivierung ueber promptCaching: auto (Default, aktiv fuer Modelle mit Unterstuetzung), on oder off. Der wichtigste Test dazu prueft die Praefix-Stabilitaet: Der System-Prompt muss ueber alle Schritte zeichengleich serialisiert werden. Ein einziger Zeitstempel darin wuerde den Cache still verwerfen — die Kosten blieben unveraendert, ohne dass es irgendwo auffiele. T9 — Usage liest prompt_tokens_details.cached_tokens; die Zahl wird bis in AgentRunResult durchgereicht. Ohne sie liesse sich die Wirkung nicht belegen. T2 — Tool-Ergebnisse werden jetzt zentral in ExecuteToolCallAsync gekappt (maxToolResultChars, Default 16.000). Bisher konnte ein einzelner WebFetch mit dem 512-KB-Standardlimit rund 130.000 Tokens in EINER Antwort erzeugen; die Compaction griff erst danach, bezahlt war der Request laengst. T3 — Die Zusammenfassung beim Kompaktieren laeuft ueber ein konfigurierbares summaryModel (Default gemini-2.5-flash) statt ueber das teure Agentenmodell. B4 — AgentRunResult fuehrt Prompt- und Completion-Tokens getrennt; die Kostenanzeige schaetzte bisher 50/50, real liegt das Verhaeltnis eher bei 95:5. Die veraltete Preistabelle bleibt offen. Neue Einstellungen sind im PropertyGrid sichtbar und werden vom AgentEditor bei neuen Agenten mitgeschrieben. Alle 91 Tests gruen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
6bbe9f9a80 |
B2 beheben: Chat-Laeufe pro Agent serialisieren
Der Konversationskontext _chatContexts[agentId] ist eine geteilte List<ChatMessage>. Nur der Lookup lief unter Lock, alle Add-Aufrufe im Schleifenkoerper waren ungeschuetzt. Da WebView, ToolJob-Wakeups und AgentComm denselben Agenten gleichzeitig ansprechen koennen, verschraenkten sich ihre Nachrichten zu einer ungueltigen Tool-Sequenz, die die API mit HTTP 400 ablehnt. ChatAsync laeuft jetzt hinter einem SemaphoreSlim(1,1) pro Agent; verschiedene Agenten bleiben unabhaengig. Die Timeout-Uhr startet erst nach dem Eintritt, damit Wartezeit in der Warteschlange den Lauf nicht aufzehrt. Zwei Folgeprobleme mit demselben Ursprung: - _runningChats hielt nur EINE CancellationTokenSource je Agent; der zweite Lauf ueberschrieb den ersten. AbortChat brach dadurch nur einen ab, der andere lief bis ins Run-Timeout. Jetzt eine Liste, die auch wartende Laeufe erfasst. - ExecuteToolCallAsync fing OperationCanceledException mit ab und gab sie als Tool-Ergebnis zurueck, wodurch der Abbruch erst einen Schritt spaeter griff. Cancellation wird nun durchgereicht. Ausserdem: send_message an den eigenen Agenten wird abgelehnt — es waere mit dem neuen Gate in einen Deadlock gelaufen. Neu: GetChatContext(agentId) als Momentaufnahme des Kontexts, fuer Diagnose und Kontextgroessen-Anzeige. Build-Fix: Das WinForms-Projekt globbt **/*.cs und kompilierte dadurch die Test-Quellen mit. tests\** wird jetzt wie src\** ausgeschlossen. Alle 49 Tests gruen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
eae13771cf |
B1, B14 und B3 beheben: Compaction-Paarung und Token-Semantik
B1 — Die Compaction behielt blind die letzten 6 Nachrichten. Fiel diese Grenze mitten in eine Tool-Sequenz, entstand eine tool-Antwort ohne zugehoerigen assistant-tool_call; die API lehnt das mit HTTP 400 ab. FindSafeTailStart verschiebt die Grenze jetzt rueckwaerts auf eine Blockgrenze. B14 — Bei Konversationen mit hoechstens 6 Nachrichten enthielt der Tail auch die system-Nachricht, die anschliessend ein zweites Mal angehaengt wurde. Ergebnis war ein doppelter System-Prompt und eine duplizierte Konversation — die Compaction vergroesserte den Kontext, statt ihn zu verkleinern. Der Tail beginnt nun grundsaetzlich hinter dem System-Prompt; liegt davor nichts Nennenswertes, wird die Kompaktierung uebersprungen. Gefunden durch den Property-Test. Nebeneffekt: Zusammengefasst wird nur noch der Teil, der tatsaechlich wegfaellt. Der Tail bleibt woertlich erhalten und musste bisher doppelt bezahlt werden. B3 — maxTokens zaehlte kumulativ ueber alle Schritte, wurde aber wie eine Kontextgrenze konfiguriert. Da jeder Schritt den vollen Kontext erneut sendet, brach ein Chat mit 20k Kontext nach vier Schritten ab. Aufgeteilt in maxCumulativeTokens (Kostenbudget, Default 500k) und maxContextTokens (Kontextgroesse). Alte Konfigurationen werden beim Laden migriert, die Fehlermeldungen unterscheiden jetzt Schritt- und Kostenlimit. Alle 31 Tests gruen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |