(hooks_path: &Path)
| 586 | } |
| 587 | |
| 588 | fn remove_legacy_project_hooks(hooks_path: &Path) -> Result<()> { |
| 589 | if !hooks_path.exists() { |
| 590 | return Ok(()); |
| 591 | } |
| 592 | let mut hooks = load_jsonc_file_strict(hooks_path)?; |
| 593 | let Some(events) = hooks |
| 594 | .get_mut("hooks") |
| 595 | .and_then(|value| value.as_object_mut()) |
| 596 | else { |
| 597 | return Ok(()); |
| 598 | }; |
| 599 | |
| 600 | let mut removed = false; |
| 601 | for value in events.values_mut() { |
| 602 | let Some(entries) = value.as_array_mut() else { |
| 603 | continue; |
| 604 | }; |
| 605 | let before = entries.len(); |
| 606 | entries.retain(|entry| !is_legacy_tracedecay_hook(entry)); |
| 607 | removed |= entries.len() != before; |
| 608 | } |
| 609 | events.retain(|_, value| value.as_array().is_none_or(|entries| !entries.is_empty())); |
| 610 | |
| 611 | if !removed { |
| 612 | return Ok(()); |
| 613 | } |
| 614 | if events.is_empty() { |
| 615 | std::fs::remove_file(hooks_path).map_err(|e| TraceDecayError::Config { |
| 616 | message: format!("failed to remove {}: {e}", hooks_path.display()), |
| 617 | })?; |
| 618 | eprintln!( |
| 619 | "\x1b[32m✔\x1b[0m Removed legacy Cursor hooks from {}", |
| 620 | hooks_path.display() |
| 621 | ); |
| 622 | } else if backup_and_write_json(hooks_path, &hooks) { |
| 623 | eprintln!( |
| 624 | "\x1b[32m✔\x1b[0m Removed legacy Cursor hooks from {}", |
| 625 | hooks_path.display() |
| 626 | ); |
| 627 | } |
| 628 | Ok(()) |
| 629 | } |
| 630 | |
| 631 | fn remove_legacy_project_rule(rule_path: &Path) -> Result<()> { |
| 632 | if !rule_path.exists() { |
no test coverage detected