Bugfix-Runde Panel/Archiv: Datenverlust, Suche, Löschen, Markdown

- ProjectConfig reicht unbekannte Keys durch (serde flatten). Bisher verlor
  jeder read-modify-write die Felder neuerer Versionen; so ging archiveHome
  bei der Pool-Zuweisung durch einen älteren Build verloren.
- Archiv-Suche: Nutzereingabe wird in einen FTS5-Ausdruck übersetzt, der nicht
  scheitern kann. ai-control, C++ oder eine halbe Phrase warfen bisher einen
  Syntaxfehler — bei der Live-Suche in jedem Tippzwischenstand.
- commands_delete: Befehlstext als Identität, Indizes werden geprüft. Bisher
  Panik oder Löschen der falschen Kachel, wenn die Panel-Indizes der Datei
  hinterherhingen.
- Archivieren überschreibt keine Datei mehr: Der Stempel hat Minutenauflösung,
  bei Kollision wird -2, -3, ... angehängt.
- archive_panel prüft erst auf leeres Panel, dann wird das Archiv-Home gesetzt;
  bisher blieb ein umkonfiguriertes Home trotz Meldung "nicht archiviert".
- Kaputte .claude.json eines Pools wird nicht mehr durch eine frische ersetzt;
  nur eine fehlende Datei rechtfertigt das.
- Archiv-Formular leert beim Schließen — sonst galten Ordner und Schlagwörter
  des vorigen Dokuments unbemerkt fürs nächste.
- Markdown fürs Panel entschärft (src/markdown.ts): rohes HTML wird als Text
  ausgegeben, Link- und Bildziele auf harmlose Schemata beschränkt. Das Panel
  teilt sich den Webview mit dem Terminal, dessen term_write in die PTY
  schreibt; ohne CSP war das ein Weg von Fremdinhalt zu Befehlsausführung.

Regressionstests je Fix: 73 Rust-Tests, 35 Frontend-Tests.
This commit is contained in:
marcusH
2026-07-19 23:04:17 +02:00
parent 1345ef799c
commit b127269e89
14 changed files with 306 additions and 28 deletions
+13 -4
View File
@@ -257,10 +257,19 @@ fn register_mcp_server(pool_dir: &std::path::Path) {
"alwaysLoad": true,
});
let cfg = pool_dir.join(".claude.json");
let mut v = fs::read_to_string(&cfg)
.ok()
.and_then(|s| serde_json::from_str::<serde_json::Value>(&s).ok())
.unwrap_or_else(|| serde_json::json!({}));
// Nur eine fehlende Datei rechtfertigt ein frisches Objekt. Ist sie da, aber
// unlesbar oder kaputtes JSON (abgebrochener Schreibvorgang, volle Platte),
// wird sie in Ruhe gelassen: Sie ist claudes Live-State mit Projekt-Zustand
// und MCP-Einträgen Dritter. Sie hier zu ersetzen macht aus einem
// reparierbaren Schaden einen endgültigen.
let mut v = match fs::read_to_string(&cfg) {
Ok(s) => match serde_json::from_str::<serde_json::Value>(&s) {
Ok(v) => v,
Err(_) => return,
},
Err(e) if e.kind() == std::io::ErrorKind::NotFound => serde_json::json!({}),
Err(_) => return,
};
let Some(obj) = v.as_object_mut() else { return };
let Some(servers) = obj
.entry("mcpServers")