`(event, hook subcommand)` pairs parsed from the embedded plugin `hooks/hooks.json` template, so the doctor check can never drift from the hooks the bundle actually registers.
()
| 723 | /// `hooks/hooks.json` template, so the doctor check can never drift from the |
| 724 | /// hooks the bundle actually registers. |
| 725 | fn cursor_plugin_hook_expectations() -> Vec<(String, String)> { |
| 726 | let files = embedded_plugin_files(); |
| 727 | let raw = files |
| 728 | .iter() |
| 729 | .find(|(relative, _)| *relative == "hooks/hooks.json") |
| 730 | .map_or("{}", |&(_, contents)| contents); |
| 731 | let template: serde_json::Value = serde_json::from_str(raw).unwrap_or_else(|_| json!({})); |
| 732 | let Some(events) = template.get("hooks").and_then(|hooks| hooks.as_object()) else { |
| 733 | return Vec::new(); |
| 734 | }; |
| 735 | events |
| 736 | .iter() |
| 737 | .flat_map(|(event, entries)| { |
| 738 | entries |
| 739 | .as_array() |
| 740 | .into_iter() |
| 741 | .flatten() |
| 742 | .filter_map(|entry| { |
| 743 | entry["command"] |
| 744 | .as_str() |
| 745 | .and_then(|command| command.strip_prefix("tracedecay ")) |
| 746 | .map(|subcommand| (event.clone(), subcommand.to_string())) |
| 747 | }) |
| 748 | }) |
| 749 | .collect() |
| 750 | } |
| 751 | |
| 752 | fn doctor_check_plugin_hooks(dc: &mut DoctorCounters, hooks_path: &Path) { |
| 753 | if !hooks_path.exists() { |