Files
codewhale/crates/tui/src/features.rs
T
Hunter Bown 7b91169017 refactor: move source files into workspace crates
- Move src/* into crates/tui/src/ to create a proper workspace structure
- Add .claude/ and .trimtab/ directories for Trimtab closed-loop workflow
- Add DEPENDENCY_GRAPH.md and update documentation
- Update Cargo.toml files to reflect new crate dependencies
- Update CI workflows and npm package scripts
- All tests pass, release build works
2026-03-11 20:00:38 -05:00

193 lines
4.7 KiB
Rust

// TODO(integrate): Wire feature flags into engine/tool registration — tracked as future work
#![allow(dead_code)]
//! Feature flags and metadata for DeepSeek TUI.
use std::collections::{BTreeMap, BTreeSet};
use std::fmt;
use serde::{Deserialize, Serialize};
/// Lifecycle stage for a feature flag.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Stage {
Experimental,
Beta,
Stable,
Deprecated,
Removed,
}
/// Unique features toggled via configuration.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Feature {
/// Enable the default shell tool.
ShellTool,
/// Enable background sub-agent tooling.
Subagents,
/// Enable web search tool.
WebSearch,
/// Enable apply_patch tool.
ApplyPatch,
/// Enable MCP tools.
Mcp,
/// Enable execpolicy integration/tooling.
ExecPolicy,
}
impl fmt::Display for Stage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let label = match self {
Self::Experimental => "experimental",
Self::Beta => "beta",
Self::Stable => "stable",
Self::Deprecated => "deprecated",
Self::Removed => "removed",
};
f.write_str(label)
}
}
impl Feature {
pub fn key(self) -> &'static str {
self.info().key
}
pub fn stage(self) -> Stage {
self.info().stage
}
pub fn default_enabled(self) -> bool {
self.info().default_enabled
}
fn info(self) -> &'static FeatureSpec {
FEATURES
.iter()
.find(|spec| spec.id == self)
.unwrap_or_else(|| unreachable!("missing FeatureSpec for {:?}", self))
}
}
/// Holds the effective set of enabled features.
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Features {
enabled: BTreeSet<Feature>,
}
impl Features {
/// Starts with built-in defaults.
pub fn with_defaults() -> Self {
let mut set = BTreeSet::new();
for spec in FEATURES {
if spec.default_enabled {
set.insert(spec.id);
}
}
Self { enabled: set }
}
pub fn enabled(&self, feature: Feature) -> bool {
self.enabled.contains(&feature)
}
pub fn enable(&mut self, feature: Feature) -> &mut Self {
self.enabled.insert(feature);
self
}
pub fn disable(&mut self, feature: Feature) -> &mut Self {
self.enabled.remove(&feature);
self
}
pub fn apply_map(&mut self, entries: &BTreeMap<String, bool>) {
for (key, enabled) in entries {
if let Some(feature) = feature_from_key(key) {
if *enabled {
self.enable(feature);
} else {
self.disable(feature);
}
}
}
}
pub fn enabled_features(&self) -> Vec<Feature> {
let mut list: Vec<_> = self.enabled.iter().copied().collect();
list.sort();
list
}
}
/// Keys accepted in `[features]` tables.
pub fn is_known_feature_key(key: &str) -> bool {
FEATURES.iter().any(|spec| spec.key == key)
}
pub fn feature_from_key(key: &str) -> Option<Feature> {
FEATURES
.iter()
.find(|spec| spec.key == key)
.map(|spec| spec.id)
}
pub fn feature_spec_by_key(key: &str) -> Option<&'static FeatureSpec> {
FEATURES.iter().find(|spec| spec.key == key)
}
/// Deserializable features table for TOML.
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
pub struct FeaturesToml {
#[serde(flatten)]
pub entries: BTreeMap<String, bool>,
}
/// Single registry of all feature definitions.
#[derive(Debug, Clone, Copy)]
pub struct FeatureSpec {
pub id: Feature,
pub key: &'static str,
pub stage: Stage,
pub default_enabled: bool,
}
pub const FEATURES: &[FeatureSpec] = &[
FeatureSpec {
id: Feature::ShellTool,
key: "shell_tool",
stage: Stage::Stable,
default_enabled: true,
},
FeatureSpec {
id: Feature::Subagents,
key: "subagents",
stage: Stage::Experimental,
default_enabled: true,
},
FeatureSpec {
id: Feature::WebSearch,
key: "web_search",
stage: Stage::Experimental,
default_enabled: true,
},
FeatureSpec {
id: Feature::ApplyPatch,
key: "apply_patch",
stage: Stage::Experimental,
default_enabled: true,
},
FeatureSpec {
id: Feature::Mcp,
key: "mcp",
stage: Stage::Experimental,
default_enabled: true,
},
FeatureSpec {
id: Feature::ExecPolicy,
key: "exec_policy",
stage: Stage::Experimental,
default_enabled: true,
},
];