Command-History: stabile ID je Eintrag statt Index+Text-Abgleich
write_commands vergibt jedem Eintrag eine UUID; commands_delete löscht darüber. Doppelklick oder ein zweites Fenster laufen ins 'bereits entfernt' statt auf verschobene Indizes.
This commit is contained in:
+11
-1
@@ -276,7 +276,17 @@ fn call_write(req: &Value) -> Value {
|
||||
static SESSION_MARKED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
|
||||
|
||||
fn call_write_commands(req: &Value) -> Value {
|
||||
let commands = req["params"]["arguments"]["commands"].clone();
|
||||
// Jeder Eintrag bekommt beim Schreiben eine stabile ID — das Panel löscht
|
||||
// darüber, statt Positionen über Watcher-Latenz und Fenstergrenzen zu
|
||||
// reichen (der frühere Index+Text-Abgleich war ein Provisorium).
|
||||
let mut commands = req["params"]["arguments"]["commands"].clone();
|
||||
if let Some(arr) = commands.as_array_mut() {
|
||||
for c in arr {
|
||||
if let Some(obj) = c.as_object_mut() {
|
||||
obj.insert("id".into(), json!(uuid::Uuid::new_v4().to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
let count = commands.as_array().map(Vec::len).unwrap_or(0);
|
||||
let path = match env_path("AI_CONTROL_COMMANDS") {
|
||||
Ok(path) => path,
|
||||
|
||||
+15
-30
@@ -270,27 +270,12 @@ pub fn commands_read(project: String) -> String {
|
||||
}
|
||||
|
||||
/// Entfernt einen Befehl aus der Command-History (Löschen einer Kachel im
|
||||
/// Panel). `line` ist der Index der nicht-leeren JSONL-Zeile, `entry` der
|
||||
/// Index im commands-Array des Records; ein leer gewordener Record fällt mit
|
||||
/// weg. Der Watcher meldet den neuen Stand als `commands-update`.
|
||||
///
|
||||
/// `cmd` ist der angezeigte Befehlstext und wird vor dem Löschen abgeglichen:
|
||||
/// Die Indizes des Panels sind der Datei um bis zu ein Watcher-Intervall
|
||||
/// hinterher, und ein leer gewordener Record verschiebt alle folgenden. Ohne
|
||||
/// Abgleich löscht ein Doppelklick — oder das zweite Fenster auf derselben
|
||||
/// Liste — die falsche Kachel oder greift ins Leere.
|
||||
///
|
||||
/// Bewusst ein Provisorium, keine echte Identität: Zwei gleiche Befehle im
|
||||
/// selben Record sind so nicht unterscheidbar. Sauber wäre eine stabile ID, die
|
||||
/// beim Schreiben der JSONL vergeben wird, statt Positionen über die
|
||||
/// Fenstergrenze zu reichen.
|
||||
/// Panel) über seine stabile ID, die write_commands beim Schreiben vergibt.
|
||||
/// Ein leer gewordener Record fällt mit weg; der Watcher meldet den neuen
|
||||
/// Stand als `commands-update`. Doppelklick oder ein zweites Fenster auf
|
||||
/// derselben Liste laufen ins „bereits entfernt" statt auf falsche Indizes.
|
||||
#[tauri::command]
|
||||
pub fn commands_delete(
|
||||
project: String,
|
||||
line: usize,
|
||||
entry: usize,
|
||||
cmd: String,
|
||||
) -> Result<(), String> {
|
||||
pub fn commands_delete(project: String, id: String) -> Result<(), String> {
|
||||
let path = commands_file(&project);
|
||||
let text = std::fs::read_to_string(&path).map_err(|e| e.to_string())?;
|
||||
let mut records: Vec<serde_json::Value> = text
|
||||
@@ -298,18 +283,18 @@ pub fn commands_delete(
|
||||
.filter(|l| !l.trim().is_empty())
|
||||
.map(|l| serde_json::from_str(l).map_err(|e| e.to_string()))
|
||||
.collect::<Result<_, _>>()?;
|
||||
let cmds = records
|
||||
.get_mut(line)
|
||||
.ok_or("Befehl bereits entfernt")?["commands"]
|
||||
.as_array_mut()
|
||||
.ok_or("Record ohne commands")?;
|
||||
if cmds.get(entry).and_then(|c| c["cmd"].as_str()) != Some(cmd.as_str()) {
|
||||
let mut found = false;
|
||||
for rec in records.iter_mut() {
|
||||
if let Some(cmds) = rec["commands"].as_array_mut() {
|
||||
let before = cmds.len();
|
||||
cmds.retain(|c| c["id"].as_str() != Some(id.as_str()));
|
||||
found = found || cmds.len() != before;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return Err("Befehl bereits entfernt".into());
|
||||
}
|
||||
cmds.remove(entry);
|
||||
if cmds.is_empty() {
|
||||
records.remove(line);
|
||||
}
|
||||
records.retain(|r| r["commands"].as_array().is_none_or(|c| !c.is_empty()));
|
||||
let mut out = String::new();
|
||||
for rec in &records {
|
||||
out.push_str(&rec.to_string());
|
||||
|
||||
Reference in New Issue
Block a user