KeiSeiKit-1.0/_primitives/_rust/kei-agent-runtime/src/capability.rs
Parfii-bot a4e667de10 KeiSeiKit-public — clean state
Single-commit clean baseline after security scrub of niche-tells,
project codenames, internal jargon, and contributor-email leaks.

Contents:
- 100 Rust crates (_primitives/_rust/)
- 37 agent manifests (_manifests/) + generated specs (_generated/)
- 67 user-invocable skills (skills/)
- 33 hooks (hooks/)
- Composition blocks (_blocks/)
- Documentation (docs/, README.md)
- TS adapter packages (_ts_packages/)
- Assembler (_assembler/)
- Roles (_roles/)
- Templates (_templates/)
- Forgejo CI (.forgejo/)

Author: Denis Parfionovich <info@greendragon.info>

License: see LICENSE.
2026-05-01 12:09:03 +08:00

141 lines
4.2 KiB
Rust

//! Capability trait + context / result types.
//!
//! Per schema §Capability trait contract (Rust). One trait, dispatched by
//! string name via `registry::get()`. Gates return `GateDecision`;
//! verifies return `VerifyResult`. Defaults are no-op so gate-only and
//! verify-only capabilities omit the other half.
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
/// Shared Capability trait. Gate + verify methods both default to no-op
/// so impls only override what they implement.
pub trait Capability: Send + Sync {
/// Namespaced capability name: `<category>::<slug>` (e.g. `policy::no-git-ops`).
fn name(&self) -> &'static str;
/// PreToolUse gate; called by `kei-capability check <name>`.
fn check(&self, _ctx: &GateContext) -> GateDecision {
GateDecision::NotApplicable
}
/// On-return verify; called by `kei-capability verify <name>`.
fn verify(&self, _ctx: &VerifyContext) -> VerifyResult {
VerifyResult::Pass
}
}
/// Context passed to `Capability::check()` — constructed by the hook binary
/// from Claude Code's tool-use JSON payload.
pub struct GateContext<'a> {
pub tool_name: &'a str,
pub tool_input: &'a Value,
pub task: &'a TaskSpec,
pub env: &'a HashMap<String, String>,
}
/// Gate outcome. `Deny` exits 2 in the hook binary; `Allow`/`NotApplicable` exit 0.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GateDecision {
Allow,
Deny { reason: String },
NotApplicable,
}
/// Context passed to `Capability::verify()` — constructed from env vars by the
/// hook binary, or programmatically by `verify::verify_task`.
pub struct VerifyContext<'a> {
pub agent_id: &'a str,
pub task: &'a TaskSpec,
pub worktree_path: &'a Path,
pub main_repo: &'a Path,
pub run_mode: RunMode,
pub simulated_merge_path: Option<PathBuf>,
}
impl<'a> VerifyContext<'a> {
/// Active run dir: simulated-merge path if present, otherwise the worktree.
pub fn run_dir(&self) -> PathBuf {
match (&self.run_mode, &self.simulated_merge_path) {
(RunMode::SimulatedMerge, Some(p)) => p.clone(),
_ => self.worktree_path.to_path_buf(),
}
}
}
/// Verify result. `Fail` exits non-zero in the hook binary.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum VerifyResult {
Pass,
Fail {
reason: String,
detail: Option<String>,
},
}
/// Verify execution mode. Orchestrator splits `Both` into two sequential
/// `Worktree` + `SimulatedMerge` calls.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RunMode {
Worktree,
SimulatedMerge,
Both,
}
/// Parsed task.toml. Subset used by gates + verifies; parser lives in
/// `spawn.rs`.
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct TaskSpec {
#[serde(default)]
pub task: TaskMeta,
#[serde(default)]
pub scope: TaskScope,
#[serde(default)]
pub verification: TaskVerification,
#[serde(default)]
pub output: TaskOutput,
#[serde(default)]
pub body: TaskBody,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct TaskMeta {
#[serde(default)]
pub role: String,
#[serde(default, rename = "agent-id")]
pub agent_id: String,
#[serde(default, rename = "parent-agent")]
pub parent_agent: Option<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct TaskScope {
#[serde(default, rename = "files-whitelist")]
pub files_whitelist: Vec<String>,
#[serde(default, rename = "files-denylist")]
pub files_denylist: Vec<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct TaskVerification {
#[serde(default, rename = "cargo-check-crates")]
pub cargo_check_crates: Vec<String>,
#[serde(default, rename = "cargo-test-crates")]
pub cargo_test_crates: Vec<String>,
#[serde(default, rename = "test-count-min")]
pub test_count_min: Option<u32>,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct TaskOutput {
#[serde(default, rename = "report-fields-required")]
pub report_fields_required: Vec<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct TaskBody {
#[serde(default)]
pub text: String,
}