Add dry run support via --simulate