huskies: merge 512_story_migrate_chat_commands_from_filesystem_lookup_to_crdt_db
This commit is contained in:
@@ -8,16 +8,6 @@ use super::CommandContext;
|
||||
use crate::io::story_metadata::{clear_front_matter_field, clear_front_matter_field_in_content, parse_front_matter, set_front_matter_field};
|
||||
use std::path::Path;
|
||||
|
||||
/// All pipeline stage directories to search when finding a work item by number.
|
||||
const SEARCH_DIRS: &[&str] = &[
|
||||
"1_backlog",
|
||||
"2_current",
|
||||
"3_qa",
|
||||
"4_merge",
|
||||
"5_done",
|
||||
"6_archived",
|
||||
];
|
||||
|
||||
/// Handle the `unblock` command.
|
||||
///
|
||||
/// Parses `<number>` from `ctx.args`, locates the work item, checks that it is
|
||||
@@ -40,61 +30,28 @@ pub(super) fn handle_unblock(ctx: &CommandContext) -> Option<String> {
|
||||
///
|
||||
/// Returns a Markdown-formatted response string suitable for all transports.
|
||||
/// Also used by the MCP `unblock` tool.
|
||||
///
|
||||
/// Lookup priority: CRDT → content store → filesystem (Story 512).
|
||||
pub(crate) fn unblock_by_number(project_root: &Path, story_number: &str) -> String {
|
||||
// Try content store / CRDT first to find story by numeric prefix.
|
||||
let mut found_id: Option<String> = None;
|
||||
|
||||
// Check content store IDs.
|
||||
for id in crate::db::all_content_ids() {
|
||||
let num = id.split('_').next().unwrap_or("");
|
||||
if num == story_number {
|
||||
found_id = Some(id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If found in content store, use DB-backed unblock.
|
||||
if let Some(story_id) = found_id {
|
||||
return unblock_by_story_id(&story_id);
|
||||
}
|
||||
|
||||
// Fallback: find the story file across all pipeline stages on filesystem.
|
||||
let mut found: Option<(std::path::PathBuf, String)> = None;
|
||||
|
||||
'outer: for stage_dir in SEARCH_DIRS {
|
||||
let dir = project_root.join(".huskies").join("work").join(stage_dir);
|
||||
if !dir.exists() {
|
||||
continue;
|
||||
}
|
||||
if let Ok(entries) = std::fs::read_dir(&dir) {
|
||||
for entry in entries.flatten() {
|
||||
let path = entry.path();
|
||||
if path.extension().and_then(|e| e.to_str()) != Some("md") {
|
||||
continue;
|
||||
}
|
||||
if let Some(stem) = path.file_stem().and_then(|s| s.to_str()) {
|
||||
let file_num = stem
|
||||
.split('_')
|
||||
.next()
|
||||
.filter(|s| !s.is_empty() && s.chars().all(|c| c.is_ascii_digit()))
|
||||
.unwrap_or("");
|
||||
if file_num == story_number {
|
||||
found = Some((path.to_path_buf(), stem.to_string()));
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
let (story_id, _stage_dir, path, _content) =
|
||||
match crate::chat::lookup::find_story_by_number(project_root, story_number) {
|
||||
Some(found) => found,
|
||||
None => {
|
||||
return format!(
|
||||
"No story, bug, or spike with number **{story_number}** found."
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Prefer DB-backed unblock when the story is in the content store.
|
||||
// Note: `content` may have come from the filesystem fallback in
|
||||
// `find_story_by_number`, so we must re-check the DB rather than
|
||||
// relying on `content.is_some()` alone.
|
||||
if crate::db::read_content(&story_id).is_some() {
|
||||
unblock_by_story_id(&story_id)
|
||||
} else {
|
||||
unblock_by_path(&path, &story_id)
|
||||
}
|
||||
|
||||
let (path, story_id) = match found {
|
||||
Some(f) => f,
|
||||
None => {
|
||||
return format!("No story, bug, or spike with number **{story_number}** found.");
|
||||
}
|
||||
};
|
||||
|
||||
unblock_by_path(&path, &story_id)
|
||||
}
|
||||
|
||||
/// Unblock a story using the content store (DB-backed).
|
||||
|
||||
Reference in New Issue
Block a user