// Command legacymove clears wiki/sources/ of the retired layout (hyperguild // #209). Default is a dry run that prints the plan; -apply performs it after // archiving every page it touches; -rollback restores from an archive. package main import ( "flag" "fmt" "log/slog" "os" "strings" "time" "github.com/mathiasbq/hyperguild/ingestion/internal/legacymove" ) func main() { brain := flag.String("brain", "/var/lib/supervisor/brain", "brain directory") wing := flag.String("wing", "web-clip", "wing that receives video and article sources") apply := flag.Bool("apply", false, "perform the plan (default: dry run)") rollback := flag.String("rollback", "", "restore from this archive dir (brain-relative, e.g. archive/wing-migration-2026-10-20)") flag.Parse() if err := run(*brain, *wing, *apply, *rollback); err != nil { slog.Error("legacymove", "err", err) os.Exit(1) } } func run(brain, wing string, apply bool, rollback string) error { if rollback != "" { if err := legacymove.Rollback(brain, rollback); err != nil { return err } fmt.Println("rolled back from", rollback) return nil } items, err := legacymove.Plan(brain, wing) if err != nil { return err } counts := map[legacymove.Action]int{} for _, it := range items { counts[it.Action]++ } fmt.Printf("# legacy source plan\n\n%d pages: %d move, %d delete, %d left\n\n", len(items), counts[legacymove.Move], counts[legacymove.Delete], counts[legacymove.Skip]) fmt.Println("| action | from | to | why |") fmt.Println("|---|---|---|---|") for _, it := range items { fmt.Printf("| %s | %s | %s | %s |\n", it.Action, it.From, it.To, strings.ReplaceAll(it.Reason, "|", "/")) } if !apply { fmt.Println("\n_dry run: nothing was changed_") return nil } res, err := legacymove.Apply(brain, items, time.Now()) fmt.Printf("\nmoved %d, deleted %d; archive: %s\n", res.Moved, res.Deleted, res.ArchiveDir) return err }