huskies: merge 492_story_remove_filesystem_pipeline_state_and_store_story_content_in_database

This commit is contained in:
dave
2026-04-08 03:03:59 +00:00
parent f43d30bdae
commit 8fd49d563e
27 changed files with 1663 additions and 1295 deletions
+29 -22
View File
@@ -134,15 +134,10 @@ pub(super) fn tool_get_story_todos(args: &Value, ctx: &AppContext) -> Result<Str
.ok_or("Missing required argument: story_id")?;
let root = ctx.state.get_project_root()?;
let current_dir = root.join(".huskies").join("work").join("2_current");
let filepath = current_dir.join(format!("{story_id}.md"));
if !filepath.exists() {
return Err(format!("Story file not found: {story_id}.md"));
}
let contents =
fs::read_to_string(&filepath).map_err(|e| format!("Failed to read story file: {e}"))?;
// Read from DB content store, falling back to filesystem.
let contents = crate::http::workflow::read_story_content(&root, story_id)
.map_err(|_| format!("Story file not found: {story_id}.md"))?;
let story_name = parse_front_matter(&contents).ok().and_then(|m| m.name);
let todos = parse_unchecked_todos(&contents);
@@ -451,7 +446,13 @@ pub(super) async fn tool_delete_story(args: &Value, ctx: &AppContext) -> Result<
crate::worktree::remove_worktree_by_story_id(&project_root, story_id, &config).await;
}
// 4. Find and delete the story file from any pipeline stage
// 4. Delete from database content store and CRDT.
let found_in_db = crate::db::read_content(story_id).is_some()
|| crate::crdt_state::read_item(story_id).is_some();
crate::db::delete_item(story_id);
// Also delete filesystem file if it exists (backwards compat).
let sk = project_root.join(".huskies").join("work");
let stage_dirs = [
"1_backlog",
@@ -461,18 +462,18 @@ pub(super) async fn tool_delete_story(args: &Value, ctx: &AppContext) -> Result<
"5_done",
"6_archived",
];
let mut deleted = false;
let mut deleted_from_fs = false;
for stage in &stage_dirs {
let path = sk.join(stage).join(format!("{story_id}.md"));
if path.exists() {
fs::remove_file(&path).map_err(|e| format!("Failed to delete story file: {e}"))?;
let _ = fs::remove_file(&path);
slog_warn!("[delete_story] Deleted '{story_id}' from work/{stage}/");
deleted = true;
deleted_from_fs = true;
break;
}
}
if !deleted {
if !found_in_db && !deleted_from_fs {
return Err(format!(
"Story '{story_id}' not found in any pipeline stage."
));
@@ -948,11 +949,13 @@ mod tests {
)
.unwrap();
assert!(result.contains("1_bug_login_crash"));
assert!(result.contains("_bug_login_crash"), "result should contain bug ID: {result}");
// Extract the actual bug ID from the result message (format: "Created bug: <id>").
let bug_id = result.trim_start_matches("Created bug: ").trim();
let bug_file = tmp
.path()
.join(".huskies/work/1_backlog/1_bug_login_crash.md");
assert!(bug_file.exists());
.join(format!(".huskies/work/1_backlog/{bug_id}.md"));
assert!(bug_file.exists(), "expected bug file at {}", bug_file.display());
}
#[test]
@@ -1071,11 +1074,13 @@ mod tests {
)
.unwrap();
assert!(result.contains("1_spike_compare_encoders"));
assert!(result.contains("_spike_compare_encoders"), "result should contain spike ID: {result}");
// Extract the actual spike ID from the result message (format: "Created spike: <id>").
let spike_id = result.trim_start_matches("Created spike: ").trim();
let spike_file = tmp
.path()
.join(".huskies/work/1_backlog/1_spike_compare_encoders.md");
assert!(spike_file.exists());
.join(format!(".huskies/work/1_backlog/{spike_id}.md"));
assert!(spike_file.exists(), "expected spike file at {}", spike_file.display());
let contents = std::fs::read_to_string(&spike_file).unwrap();
assert!(contents.starts_with("---\nname: \"Compare Encoders\"\n---"));
assert!(contents.contains("Which encoder is fastest?"));
@@ -1087,12 +1092,14 @@ mod tests {
let ctx = test_ctx(tmp.path());
let result = tool_create_spike(&json!({"name": "My Spike"}), &ctx).unwrap();
assert!(result.contains("1_spike_my_spike"));
assert!(result.contains("_spike_my_spike"), "result should contain spike ID: {result}");
// Extract the actual spike ID from the result message (format: "Created spike: <id>").
let spike_id = result.trim_start_matches("Created spike: ").trim();
let spike_file = tmp
.path()
.join(".huskies/work/1_backlog/1_spike_my_spike.md");
assert!(spike_file.exists());
.join(format!(".huskies/work/1_backlog/{spike_id}.md"));
assert!(spike_file.exists(), "expected spike file at {}", spike_file.display());
let contents = std::fs::read_to_string(&spike_file).unwrap();
assert!(contents.starts_with("---\nname: \"My Spike\"\n---"));
assert!(contents.contains("## Question\n\n- TBD\n"));