use super::{Error, Fx, Outcome};
use crate::config::Workflow;
use crate::config::version::Version;
use crate::template::{GitRunner, RealGit};
use crate::workspace::{self, DEFAULT_CONFIG_NAME, workflow_mark};
use std::path::{Path, PathBuf};
const REASON: &str =
"a workflow switch marks a running agent to resolve another workflow (ARCH §6)";
const VERSION_FILE: &str = "version";
#[derive(clap::Args, Debug)]
pub struct Args {
pub workspace: PathBuf,
pub agent: String,
#[arg(long, conflicts_with = "clear")]
pub config: Option<String>,
#[arg(long)]
pub clear: bool,
}
pub fn run(args: Args, _fx: &mut Fx) -> Result<Outcome, Error> {
let e = |source: &dyn std::fmt::Display| Error::new("workflow", source);
crate::name::require_agent_id(&args.agent).map_err(|s| e(&s))?;
let git = RealGit::new();
workspace::require(&args.workspace).map_err(|s| e(&s))?;
workspace::require_agent(&args.workspace, &args.agent, REASON, &git).map_err(|s| e(&s))?;
if args.clear {
workflow_mark::clear(&args.workspace, &args.agent, &git).map_err(|s| e(&s))?;
eprintln!(
"litany: workflow mark cleared for [{}] — its followed config's workflow \
governs from its next step (ARCH §6)",
args.agent,
);
return Ok(Outcome::Quiet);
}
let name = args.config.as_deref().unwrap_or(DEFAULT_CONFIG_NAME);
let target = preflight(&args.workspace, name, &git).map_err(|s| e(&s))?;
workflow_mark::write(&args.workspace, &args.agent, &target, &git).map_err(|s| e(&s))?;
eprintln!(
"litany: [{}] marked to run {}'s workflow ({}) — it governs from the agent's next \
step boundary on, and stands until re-marked or cleared (ARCH §6)",
args.agent,
workspace::config_ref(name),
&target[..target.len().min(12)],
);
Ok(Outcome::Quiet)
}
fn preflight(ws: &Path, name: &str, git: &dyn GitRunner) -> Result<String, String> {
workspace::require_lineage(ws, name, git).map_err(|s| s.to_string())?;
let spec = format!("{}^{{commit}}", workspace::config_ref(name));
let target = git
.run_capture(&workspace::repo_git(ws), &["rev-parse", &spec])
.map_err(|s| s.to_string())?
.trim()
.to_string();
let origin = |path: &str| PathBuf::from(format!("{target}:{path}"));
let version = control(ws, &target, VERSION_FILE, git)?;
Version::parse(&version, &origin(VERSION_FILE)).map_err(|s| s.to_string())?;
let workflow = control(ws, &target, crate::prompt::WORKFLOW_FILE, git)?;
Workflow::parse(&workflow, &origin(crate::prompt::WORKFLOW_FILE)).map_err(|s| s.to_string())?;
Ok(target)
}
fn control(ws: &Path, commit: &str, path: &str, git: &dyn GitRunner) -> Result<String, String> {
workspace::show_control(ws, commit, path, git).map_err(|s| format!("{commit}:{path}: {s}"))
}