use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ConstraintSeverity {
Block,
Warn,
Log,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ConstraintCheck {
GrepForbidden {
pattern: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
file_glob: Option<String>,
},
GrepRequired {
pattern: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
file_glob: Option<String>,
},
FileScope {
#[serde(default)]
allowed_paths: Vec<String>,
},
Command {
cmd: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
cwd: Option<String>,
#[serde(default = "default_timeout_secs")]
timeout_secs: u64,
},
}
fn default_timeout_secs() -> u64 {
30
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct Constraint {
#[serde(alias = "id")]
pub id: String,
#[serde(alias = "name")]
pub name: String,
#[serde(alias = "description")]
pub description: String,
#[serde(alias = "check")]
pub check: ConstraintCheck,
#[serde(alias = "severity")]
pub severity: ConstraintSeverity,
#[serde(default = "default_true", alias = "enabled")]
pub enabled: bool,
}
fn default_true() -> bool {
true
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct ConstraintViolation {
#[serde(default, skip_serializing_if = "Option::is_none", alias = "file")]
pub file: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "line")]
pub line: Option<u32>,
#[serde(alias = "detail")]
pub detail: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct ConstraintResult {
#[serde(alias = "constraint_id")]
pub constraint_id: String,
#[serde(alias = "constraint_name")]
pub constraint_name: String,
#[serde(alias = "passed")]
pub passed: bool,
#[serde(alias = "severity")]
pub severity: ConstraintSeverity,
#[serde(default, alias = "violations")]
pub violations: Vec<ConstraintViolation>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct ResourceLimits {
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "max_wall_time_secs"
)]
pub max_wall_time_secs: Option<u64>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "max_files_modified"
)]
pub max_files_modified: Option<u64>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "max_agentic_time_ms"
)]
pub max_agentic_time_ms: Option<u64>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "warning_threshold"
)]
pub warning_threshold: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct NewConstraintProposal {
#[serde(alias = "constraint")]
pub constraint: Constraint,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct BuiltinOverrideProposal {
#[serde(alias = "builtin_suffix")]
pub builtin_suffix: String,
#[serde(alias = "enabled")]
pub enabled: bool,
#[serde(alias = "reason")]
pub reason: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ConstraintProposal {
NewConstraint(NewConstraintProposal),
BuiltinOverride(BuiltinOverrideProposal),
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct ValidateConfigRequest {
#[serde(alias = "toml")]
pub toml: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct ValidateConfigResponse {
#[serde(alias = "valid")]
pub valid: bool,
#[serde(default, alias = "errors")]
pub errors: Vec<String>,
#[serde(default, alias = "constraints")]
pub constraints: Vec<Constraint>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct ReadConfigResponse {
#[serde(alias = "toml")]
pub toml: String,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "path")]
pub path: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct WriteConfigRequest {
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "project_path"
)]
pub project_path: Option<String>,
#[serde(alias = "toml")]
pub toml: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[schemars(deny_unknown_fields)]
pub struct WriteConfigResponse {
#[serde(alias = "valid")]
pub valid: bool,
#[serde(default, alias = "errors")]
pub errors: Vec<String>,
#[serde(alias = "path")]
pub path: String,
}