story-kit: merge 297_story_improve_bot_status_command_formatting
This commit is contained in:
@@ -178,6 +178,28 @@ fn strip_prefix_ci<'a>(text: &'a str, prefix: &str) -> Option<&'a str> {
|
|||||||
// Pipeline status helpers (moved from bot.rs)
|
// Pipeline status helpers (moved from bot.rs)
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// Format a short display label for a work item.
|
||||||
|
///
|
||||||
|
/// Extracts the leading numeric ID from the file stem (e.g. `"293"` from
|
||||||
|
/// `"293_story_register_all_bot_commands"`) and combines it with the human-
|
||||||
|
/// readable name from the front matter when available.
|
||||||
|
///
|
||||||
|
/// Examples:
|
||||||
|
/// - `("293_story_foo", Some("Register all bot commands"))` → `"293 — Register all bot commands"`
|
||||||
|
/// - `("293_story_foo", None)` → `"293"`
|
||||||
|
/// - `("no_number_here", None)` → `"no_number_here"`
|
||||||
|
fn story_short_label(stem: &str, name: Option<&str>) -> String {
|
||||||
|
let number = stem
|
||||||
|
.split('_')
|
||||||
|
.next()
|
||||||
|
.filter(|s| !s.is_empty() && s.chars().all(|c| c.is_ascii_digit()))
|
||||||
|
.unwrap_or(stem);
|
||||||
|
match name {
|
||||||
|
Some(n) => format!("{number} — {n}"),
|
||||||
|
None => number.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Read all story IDs and names from a pipeline stage directory.
|
/// Read all story IDs and names from a pipeline stage directory.
|
||||||
fn read_stage_items(
|
fn read_stage_items(
|
||||||
project_root: &std::path::Path,
|
project_root: &std::path::Path,
|
||||||
@@ -243,10 +265,7 @@ pub fn build_pipeline_status(project_root: &std::path::Path, agents: &AgentPool)
|
|||||||
out.push_str(" *(none)*\n");
|
out.push_str(" *(none)*\n");
|
||||||
} else {
|
} else {
|
||||||
for (story_id, name) in &items {
|
for (story_id, name) in &items {
|
||||||
let display = match name {
|
let display = story_short_label(story_id, name.as_deref());
|
||||||
Some(n) => format!("{story_id} — {n}"),
|
|
||||||
None => story_id.clone(),
|
|
||||||
};
|
|
||||||
if let Some(agent) = active_map.get(story_id) {
|
if let Some(agent) = active_map.get(story_id) {
|
||||||
let model_str = config
|
let model_str = config
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@@ -254,8 +273,8 @@ pub fn build_pipeline_status(project_root: &std::path::Path, agents: &AgentPool)
|
|||||||
.and_then(|ac| ac.model.as_deref())
|
.and_then(|ac| ac.model.as_deref())
|
||||||
.unwrap_or("?");
|
.unwrap_or("?");
|
||||||
out.push_str(&format!(
|
out.push_str(&format!(
|
||||||
" • {display} — {} ({}) [{}]\n",
|
" • {display} — {} ({model_str})\n",
|
||||||
agent.agent_name, model_str, agent.status
|
agent.agent_name
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
out.push_str(&format!(" • {display}\n"));
|
out.push_str(&format!(" • {display}\n"));
|
||||||
@@ -667,6 +686,64 @@ mod tests {
|
|||||||
assert_eq!(strip_prefix_ci("hello", "hello"), Some(""));
|
assert_eq!(strip_prefix_ci("hello", "hello"), Some(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -- story_short_label --------------------------------------------------
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn short_label_extracts_number_and_name() {
|
||||||
|
let label = story_short_label("293_story_register_all_bot_commands", Some("Register all bot commands"));
|
||||||
|
assert_eq!(label, "293 — Register all bot commands");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn short_label_number_only_when_no_name() {
|
||||||
|
let label = story_short_label("297_story_improve_bot_status_command_formatting", None);
|
||||||
|
assert_eq!(label, "297");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn short_label_falls_back_to_stem_when_no_numeric_prefix() {
|
||||||
|
let label = story_short_label("no_number_here", None);
|
||||||
|
assert_eq!(label, "no_number_here");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn short_label_does_not_include_underscore_slug() {
|
||||||
|
let label = story_short_label("293_story_register_all_bot_commands_in_the_command_registry", Some("Register all bot commands"));
|
||||||
|
assert!(
|
||||||
|
!label.contains("story_register"),
|
||||||
|
"label should not contain the slug portion: {label}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- build_pipeline_status formatting -----------------------------------
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn status_does_not_show_full_filename_stem() {
|
||||||
|
use std::io::Write;
|
||||||
|
use tempfile::TempDir;
|
||||||
|
|
||||||
|
let tmp = TempDir::new().unwrap();
|
||||||
|
let stage_dir = tmp.path().join(".story_kit/work/2_current");
|
||||||
|
std::fs::create_dir_all(&stage_dir).unwrap();
|
||||||
|
|
||||||
|
// Write a story file with a front-matter name
|
||||||
|
let story_path = stage_dir.join("293_story_register_all_bot_commands.md");
|
||||||
|
let mut f = std::fs::File::create(&story_path).unwrap();
|
||||||
|
writeln!(f, "---\nname: Register all bot commands\n---\n").unwrap();
|
||||||
|
|
||||||
|
let agents = AgentPool::new_test(3000);
|
||||||
|
let output = build_pipeline_status(tmp.path(), &agents);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
!output.contains("293_story_register_all_bot_commands"),
|
||||||
|
"output must not show full filename stem: {output}"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
output.contains("293 — Register all bot commands"),
|
||||||
|
"output must show number and title: {output}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// -- commands registry --------------------------------------------------
|
// -- commands registry --------------------------------------------------
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user