Archiv-Wiki im Panel: vier Tabs, FTS5-Suche, strukturierbares Archiv

- Archiv-Home pro Projekt (archiveHome in ai-control.json); archive_panel
  mit Ordner, Beschreibung und Schlagwörtern (Frontmatter + Zeitstempel-Stem)
- Archiv-Index (archive_index.rs): Scan mit Frontmatter, Wikilinks,
  Backlinks; Wiki-Seiten als strukturierte Daten (Übersicht/Tag-Seiten)
- FTS5-Suche (archive_search.rs, rusqlite bundled): in-memory-Index pro
  Anfrage; MCP search_archive und Panel-Suchfeld (search_run) teilen die Engine
- Panel: vier Puffer/Ansichten (Dokument, Befehle, Suche, Wiki) mit Tabs im
  Fenster-Header; gemeinsame Verdrahtung panel-wiring.ts, Kachel-CSS,
  Wiki-View mit Tag-Chips, Ordner-Sektionen und Backlinks
- Archivieren speichert offene Bearbeitung (flush); Tab-Wechsel speichert
  statt zu blockieren; Fehler sichtbar als Panel-Toast
- Abgelöstes Fenster: rahmenlos (Linux), eigene Kopfleiste mit Tabs und
  Fensterknöpfen, Theme-Kopplung über gemeinsames themes.ts
- MCP-Tools show_commands, show_archive; Befehls-History mit Kachel-Löschen
This commit is contained in:
marcus hinz
2026-07-19 15:25:40 +02:00
parent d4d455fa08
commit 994d5070f0
29 changed files with 3471 additions and 571 deletions
+8 -5
View File
@@ -29,13 +29,16 @@ pub(crate) struct ProjectConfig {
pub(crate) pool: Option<String>,
#[serde(default, skip_serializing_if = "TerminalConfig::is_empty")]
pub(crate) terminal: TerminalConfig,
/// Zielordner fürs Archivieren von Panel-Entwürfen (~-relativ gespeichert).
/// Archiv-Home des Projekts: Zielordner fürs Archivieren von Panel-Entwürfen
/// (~-relativ gespeichert). Liest den früheren Key `archiveDir` weiterhin ein,
/// geschrieben wird nur noch `archiveHome`.
#[serde(
default,
rename = "archiveDir",
rename = "archiveHome",
alias = "archiveDir",
skip_serializing_if = "Option::is_none"
)]
pub(crate) archive_dir: Option<String>,
pub(crate) archive_home: Option<String>,
}
#[derive(Serialize, Deserialize, Default, Clone)]
@@ -223,7 +226,7 @@ pub(crate) fn create_project_full_in(
reg.insert(name.to_string(), dir.clone());
save_registry(paths, &reg)?;
let cfg = ProjectConfig { pool: pool.map(str::to_string), terminal, archive_dir: None };
let cfg = ProjectConfig { pool: pool.map(str::to_string), terminal, archive_home: None };
if cfg.pool.is_some() || !cfg.terminal.is_empty() {
write_project_config_in(paths, name, &cfg)?;
}
@@ -431,7 +434,7 @@ pub(crate) fn assign_pool_in(paths: &Paths, project: &str, pool: &str) -> Result
pub(crate) fn unassign_pool_in(paths: &Paths, project: &str) -> Result<(), String> {
let mut cfg = read_project_config_in(paths, project)?;
cfg.pool = None;
if cfg.terminal.is_empty() && cfg.archive_dir.is_none() {
if cfg.terminal.is_empty() && cfg.archive_home.is_none() {
let cfg_path = project_config_path(paths, project)?;
return fs::remove_file(&cfg_path).map_err(|e| format!("{}: {e}", cfg_path.display()));
}