using NozCli.Core.Client; using NozCli.Core.Security; using NozCli.Repl; using Spectre.Console; namespace NozCli.Commands; public class MvCommand : ICommand { public string Name => "mv"; public string Description => "Rename a note and update all inbound links"; public string Usage => "mv "; public async Task ExecuteAsync(string[] args, ReplContext ctx, CancellationToken ct = default) { if (args.Length < 2) { AnsiConsole.MarkupLine("[red]Usage:[/] mv "); return; } // Resolve short names to full slugs var oldSlug = ctx.ResolveSlug(args[0]); var newSlug = ctx.ResolveNewSlug(args[1]); if (!SlugGuard.IsValid(oldSlug) || !SlugGuard.IsValid(newSlug)) { AnsiConsole.MarkupLine("[red]Ungültiger Slug.[/] Nur Kleinbuchstaben, Ziffern und Bindestriche erlaubt."); return; } if (oldSlug == newSlug) { AnsiConsole.MarkupLine("[yellow]Quelle und Ziel sind identisch — nichts zu tun.[/]"); return; } if (!ctx.NoteCache.Any(n => n.Slug == oldSlug)) { AnsiConsole.MarkupLine($"[red]Notiz nicht gefunden:[/] {oldSlug}"); return; } if (ctx.NoteCache.Any(n => n.Slug == newSlug)) { AnsiConsole.MarkupLine($"[red]Ziel existiert bereits:[/] {newSlug}"); return; } AnsiConsole.MarkupLine($"[dim]Umbenennen:[/] [cyan]{oldSlug}[/] → [green]{newSlug}[/]"); NoteRenamer.Result result = default!; await AnsiConsole.Progress() .AutoClear(false) .HideCompleted(false) .StartAsync(async prog => { var task = prog.AddTask("Umbenennen…", maxValue: 100); result = await NoteRenamer.ExecuteAsync( ctx.Api, oldSlug, newSlug, onProgress: msg => { task.Description = msg; task.Increment(20); }, ct: ct); task.Value = 100; task.Description = "Fertig"; }); // Update local cache: swap old entry for a patched new one var oldEntry = ctx.NoteCache.FirstOrDefault(n => n.Slug == oldSlug); if (oldEntry is not null) { ctx.NoteCache.Remove(oldEntry); ctx.NoteCache.Add(oldEntry with { Slug = newSlug }); } var linkInfo = result.LinksUpdated > 0 ? $" [dim]· {result.LinksUpdated} Link(s) aktualisiert[/]" : ""; AnsiConsole.MarkupLine($"[green]✓[/] {oldSlug} → {newSlug}{linkInfo}"); } }