Skip to main content

chant/operations/
reset.rs

1//! Spec reset operation.
2//!
3//! Canonical implementation for resetting specs to pending status.
4
5use anyhow::Result;
6use std::path::Path;
7
8use crate::spec::{Spec, SpecStatus};
9
10/// Options for spec reset
11#[derive(Debug, Clone, Default)]
12pub struct ResetOptions {
13    /// Whether to re-execute the spec after reset
14    pub re_execute: bool,
15    /// Optional prompt template for re-execution
16    pub prompt: Option<String>,
17    /// Optional branch to use for re-execution
18    pub branch: Option<String>,
19}
20
21/// Reset a spec to pending status.
22///
23/// This is the canonical reset logic used by both CLI and MCP.
24/// Only failed or in_progress specs can be reset.
25pub fn reset_spec(spec: &mut Spec, spec_path: &Path, _options: ResetOptions) -> Result<()> {
26    // Check if spec is in failed or in_progress state
27    if spec.frontmatter.status != SpecStatus::Failed
28        && spec.frontmatter.status != SpecStatus::InProgress
29    {
30        anyhow::bail!(
31            "Spec '{}' is not in failed or in_progress state (current: {:?}). \
32             Only failed or in_progress specs can be reset.",
33            spec.id,
34            spec.frontmatter.status
35        );
36    }
37
38    // Reset to pending using state machine
39    spec.set_status(SpecStatus::Pending)
40        .map_err(|e| anyhow::anyhow!("Failed to transition spec to Pending: {}", e))?;
41
42    // Save the spec
43    spec.save(spec_path)?;
44
45    Ok(())
46}