merge e0ced047-de9d-48cf-b0f8-20040e532f88

81eba9fgl0w

all commits

Message

merge e0ced047-de9d-48cf-b0f8-20040e532f88

Diff

crates/cli/src/cmd/label.rs+3 −2
diff --git a/crates/cli/src/cmd/label.rs b/crates/cli/src/cmd/label.rsindex 05916b3..3a3f0a1 100644--- a/crates/cli/src/cmd/label.rs+++ b/crates/cli/src/cmd/label.rs@@ -6,7 +6,7 @@ use crate::CliError;66 use f0rge_core::{Forge, Label};77 88 pub fn help() -> &'static str {9-    "f0rge label: definitions\nusage: f0rge label <list|create|edit> [--json]\nfile: .forge/labels.md\ndocs: spec/schema.md §Label\ncontract: f0rge --skill\n"9+    "f0rge label: definitions\nusage: f0rge label <list|create|edit> [--json]\ncreate: label create <name>\nfile: .forge/labels.md\ndocs: spec/schema.md §Label\ncontract: f0rge --skill\n"1010 }1111 1212 const VALS: &[&str] = &["name", "color", "description", "desc", "jq"];@@ -150,7 +150,8 @@ fn desc_of(fs: &FlagSet) -> Option<String> {150150 }151151 152152 fn list(fg: &Forge, json: bool, jq: Option<&str>) -> Result<(), CliError> {153-    let items = load(fg)?;153+    let mut items = load(fg)?;154+    items.sort_by(|a, b| a.name.cmp(&b.name));154155     if json {155156         if items.is_empty() {156157             output::emit_str("[]", jq);
crates/cli/src/cmd/milestone.rs+3 −2
diff --git a/crates/cli/src/cmd/milestone.rs b/crates/cli/src/cmd/milestone.rsindex f7baedc..4fd0997 100644--- a/crates/cli/src/cmd/milestone.rs+++ b/crates/cli/src/cmd/milestone.rs@@ -6,7 +6,7 @@ use crate::CliError;66 use f0rge_core::{Forge, Milestone};77 88 pub fn help() -> &'static str {9-    "f0rge milestone: spans\nusage: f0rge milestone <list|create|edit> [--json]\nfile: .forge/milestones.md\ndocs: spec/schema.md §Milestone\ncontract: f0rge --skill\n"9+    "f0rge milestone: spans\nusage: f0rge milestone <list|create|edit> [--json]\ncreate: milestone create <name> [--state S]\nfile: .forge/milestones.md\ndocs: spec/schema.md §Milestone\ncontract: f0rge --skill\n"1010 }1111 1212 const VALS: &[&str] = &["name", "state", "due", "description", "desc", "jq"];@@ -160,7 +160,8 @@ fn check_state(s: &str) -> Result<String, CliError> {160160 }161161 162162 fn list(fg: &Forge, json: bool, jq: Option<&str>) -> Result<(), CliError> {163-    let items = load(fg)?;163+    let mut items = load(fg)?;164+    items.sort_by(|a, b| a.name.cmp(&b.name));164165     if json {165166         if items.is_empty() {166167             output::emit_str("[]", jq);
crates/cli/src/cmd/task.rs+12 −10
diff --git a/crates/cli/src/cmd/task.rs b/crates/cli/src/cmd/task.rsindex 04c45e5..9f23482 100644--- a/crates/cli/src/cmd/task.rs+++ b/crates/cli/src/cmd/task.rs@@ -5,7 +5,7 @@ use f0rge_core::{Forge, Task};55 use serde::Serialize;66 77 pub fn help() -> &'static str {8-    "f0rge task: kanban cards\nusage: f0rge task <create|list|move|done> [--json]\ncreate: --title T [--body B] [--column C]\ncols: todo doing blocked done\ndocs: spec/schema.md §Task\ncontract: f0rge --skill\n"8+    "f0rge task: kanban cards\nusage: f0rge task <create|list|move|done> [--json]\ncreate: task create --title S [--body S --column C]\ncols: todo doing blocked done\ndocs: spec/schema.md §Task\ncontract: f0rge --skill\n"99 }1010 1111 const COLS: &[&str] = &["todo", "doing", "blocked", "done"];@@ -99,17 +99,19 @@ struct TaskJson {9999     id: String,100100     status: String,101101     title: String,102+    body: String,102103     #[serde(rename = "createdAt")]103104     created_at: String,104105     #[serde(skip_serializing_if = "Option::is_none")]105106     issue: Option<String>,106107 }107108 108-fn view_of(t: &Task, issue: Option<String>) -> TaskJson {109+fn view_of(t: &Task, body: &str, issue: Option<String>) -> TaskJson {109110     TaskJson {110111         id: t.id.clone(),111112         status: t.status.clone(),112113         title: t.title.clone(),114+        body: body.to_string(),113115         created_at: t.created.clone(),114116         issue,115117     }@@ -182,7 +184,7 @@ fn load(fg: &Forge, uuid: &str) -> Result<(Task, Option<String>, String), CliErr182184     Ok((p.value, issue, p.body))183185 }184186 185-fn load_all(fg: &Forge) -> Result<Vec<(Task, Option<String>)>, CliError> {187+fn load_all(fg: &Forge) -> Result<Vec<(Task, String, Option<String>)>, CliError> {186188     let dir = fg.root().join("tasks");187189     let rd = match std::fs::read_dir(&dir) {188190         Ok(r) => r,@@ -203,7 +205,7 @@ fn load_all(fg: &Forge) -> Result<Vec<(Task, Option<String>)>, CliError> {203205             continue;204206         }205207         match load(fg, stem) {206-            Ok((t, issue, _)) => out.push((t, issue)),208+            Ok((t, issue, body)) => out.push((t, body, issue)),207209             Err(CliError::Runtime(_)) => continue,208210             Err(e) => return Err(e),209211         }@@ -253,7 +255,7 @@ fn create(fs: &args::FlagSet, fg: &Forge) -> Result<(), CliError> {253255     };254256     fg.atomic_write(&fg.task_file(&id), render(&t, issue.as_deref(), &body).as_bytes())255257         .map_err(CliError::from)?;256-    output::emit_json(&view_of(&t, issue), fs.get("jq"));258+    output::emit_json(&view_of(&t, &body, issue), fs.get("jq"));257259     Ok(())258260 }259261 @@ -268,8 +270,8 @@ fn list(fs: &args::FlagSet, fg: &Forge) -> Result<(), CliError> {268270             output::emit_empty_array(fs.get("jq"));269271             return Ok(());270272         }271-        for (t, issue) in &all {272-            output::emit_str(&output::json_line(&view_of(t, issue.clone())), fs.get("jq"));273+        for (t, body, issue) in &all {274+            output::emit_str(&output::json_line(&view_of(t, body, issue.clone())), fs.get("jq"));273275         }274276         return Ok(());275277     }@@ -280,7 +282,7 @@ fn list(fs: &args::FlagSet, fg: &Forge) -> Result<(), CliError> {280282     for col in COLS {281283         human.push_str(col);282284         human.push_str(":\n");283-        for (t, _) in all.iter().filter(|(t, _)| &t.status == col) {285+        for (t, _, _) in all.iter().filter(|(t, _, _)| &t.status == col) {284286             human.push_str(&format!("  {}  {}\n", t.id, t.title));285287         }286288     }@@ -302,7 +304,7 @@ fn mv(fs: &args::FlagSet, fg: &Forge) -> Result<(), CliError> {302304     t.updated = Some(f0rge_core::now_rfc3339());303305     fg.atomic_write(&fg.task_file(&uuid), render(&t, issue.as_deref(), &body).as_bytes())304306         .map_err(CliError::from)?;305-    output::emit_json(&view_of(&t, issue), fs.get("jq"));307+    output::emit_json(&view_of(&t, &body, issue), fs.get("jq"));306308     Ok(())307309 }308310 @@ -318,7 +320,7 @@ fn done(fs: &args::FlagSet, fg: &Forge) -> Result<(), CliError> {318320     t.updated = Some(now);319321     fg.atomic_write(&fg.task_file(&uuid), render(&t, issue.as_deref(), &body).as_bytes())320322         .map_err(CliError::from)?;321-    output::emit_json(&view_of(&t, issue), fs.get("jq"));323+    output::emit_json(&view_of(&t, &body, issue), fs.get("jq"));322324     Ok(())323325 }324326