#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub(crate) enum Category {
Model,
Providers,
Agent,
ToolLimits,
Appearance,
Plugins,
Sidecar,
}
impl Category {
pub fn label(&self) -> &'static str {
match self {
Category::Model => "Model",
Category::Providers => "Providers",
Category::Agent => "Agent",
Category::ToolLimits => "Tool Limits",
Category::Appearance => "Appearance",
Category::Plugins => "Plugins",
Category::Sidecar => "Sidecar",
}
}
}
pub(crate) const CATEGORIES: [Category; 7] = [
Category::Model,
Category::Providers,
Category::Agent,
Category::ToolLimits,
Category::Appearance,
Category::Plugins,
Category::Sidecar,
];
pub(crate) fn visible_categories(
claims: &[synaps_cli::skills::registry::LifecycleClaim],
) -> Vec<Category> {
let any_namespaced = claims.iter().any(|c| c.settings_category.is_some());
CATEGORIES
.iter()
.copied()
.filter(|c| !(any_namespaced && *c == Category::Sidecar))
.collect()
}
pub(crate) enum EditorKind {
Cycler(&'static [&'static str]),
ModelPicker,
ThemePicker,
Text { numeric: bool },
}
pub(crate) struct SettingDef {
pub key: &'static str,
pub label: &'static str,
pub category: Category,
pub editor: EditorKind,
#[allow(dead_code)]
pub help: &'static str,
}
pub(crate) use super::defs::ALL_SETTINGS;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_setting_belongs_to_known_category() {
for def in ALL_SETTINGS {
assert!(CATEGORIES.contains(&def.category));
}
}
#[test]
fn plugins_category_is_present() {
assert!(CATEGORIES.contains(&Category::Plugins));
}
#[test]
fn plugins_category_label() {
assert_eq!(Category::Plugins.label(), "Plugins");
}
#[test]
fn sidecar_category_is_present() {
assert!(CATEGORIES.contains(&Category::Sidecar));
}
#[test]
fn sidecar_category_label() {
assert_eq!(Category::Sidecar.label(), "Sidecar");
}
#[test]
fn sidecar_settings_belong_to_sidecar_category() {
let sidecar_keys = ["sidecar_toggle_key"];
for def in ALL_SETTINGS {
if sidecar_keys.contains(&def.key) {
assert_eq!(def.category, Category::Sidecar, "setting '{}' should be in Sidecar", def.key);
}
}
let keys: Vec<&str> = ALL_SETTINGS.iter().map(|d| d.key).collect();
for k in sidecar_keys {
assert!(keys.contains(&k), "missing sidecar setting: {}", k);
}
}
fn mk_claim(plugin: &str, command: &str, cat: Option<&str>) -> synaps_cli::skills::registry::LifecycleClaim {
synaps_cli::skills::registry::LifecycleClaim {
plugin: plugin.to_string(),
command: command.to_string(),
settings_category: cat.map(str::to_string),
display_name: command.to_string(),
importance: 0,
}
}
#[test]
fn visible_categories_returns_all_seven_when_no_claims() {
let v = visible_categories(&[]);
assert_eq!(v.len(), 7);
assert!(v.contains(&Category::Sidecar));
}
#[test]
fn visible_categories_hides_sidecar_when_claim_has_settings_category() {
let claim = mk_claim("sample-sidecar", "capture", Some("capture"));
let v = visible_categories(&[claim]);
assert_eq!(v.len(), 6);
assert!(!v.contains(&Category::Sidecar));
assert_eq!(v[0], Category::Model);
assert_eq!(*v.last().unwrap(), Category::Plugins);
}
#[test]
fn visible_categories_keeps_sidecar_when_claim_has_no_settings_category() {
let claim = mk_claim("p", "ocr", None);
let v = visible_categories(&[claim]);
assert_eq!(v.len(), 7);
assert!(v.contains(&Category::Sidecar));
}
}