Accept story 45: Deterministic Story Lifecycle Management

- accept_story MCP tool moves current/ to archived/
- move_story_to_archived helper with idempotent behavior
- start_agent auto-moves upcoming/ to current/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dave
2026-02-20 15:09:39 +00:00
parent 42640fba6a
commit 5c164f4855
3 changed files with 61 additions and 1 deletions

View File

@@ -652,6 +652,36 @@ impl AgentPool {
}
}
/// Move a story file from current/ to archived/ (human accept action).
///
/// * If the story is in current/, it is renamed to archived/.
/// * If the story is already in archived/, this is a no-op (idempotent).
/// * If the story is not found in current/ or archived/, an error is returned.
pub fn move_story_to_archived(project_root: &Path, story_id: &str) -> Result<(), String> {
let stories_dir = project_root.join(".story_kit").join("stories");
let current_path = stories_dir.join("current").join(format!("{story_id}.md"));
let archived_path = stories_dir.join("archived").join(format!("{story_id}.md"));
if archived_path.exists() {
// Already archived — idempotent, nothing to do.
return Ok(());
}
if current_path.exists() {
let archived_dir = stories_dir.join("archived");
std::fs::create_dir_all(&archived_dir)
.map_err(|e| format!("Failed to create archived stories directory: {e}"))?;
std::fs::rename(&current_path, &archived_path)
.map_err(|e| format!("Failed to move story '{story_id}' to archived/: {e}"))?;
eprintln!("[lifecycle] Moved story '{story_id}' from current/ to archived/");
return Ok(());
}
Err(format!(
"Story '{story_id}' not found in current/. Cannot accept story."
))
}
// ── Acceptance-gate helpers ───────────────────────────────────────────────────
/// Check whether the given directory has any uncommitted git changes.