List vault intents. Optionally filtered by status. Pass `Some("all")` or `None` for all intents.
(
&self,
status_filter: Option<&str>,
)
| 250 | /// |
| 251 | /// Optionally filtered by status. Pass `Some("all")` or `None` for all intents. |
| 252 | pub fn vault_intent_list( |
| 253 | &self, |
| 254 | status_filter: Option<&str>, |
| 255 | ) -> Result<Vec<IntentInfo>, RepositoryError> { |
| 256 | let manifest = self.vault_manifest()?; |
| 257 | let mut intents: Vec<IntentInfo> = Vec::new(); |
| 258 | |
| 259 | for (id, summary) in &manifest.intents { |
| 260 | if let Some(filter) = status_filter { |
| 261 | if filter != "all" && summary.status != filter { |
| 262 | continue; |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | // Use the title stored in the manifest summary. |
| 267 | // Fall back to path-based lookup only for legacy entries without a title. |
| 268 | let title = if !summary.title.is_empty() { |
| 269 | summary.title.clone() |
| 270 | } else if !summary.vault_path.is_empty() { |
| 271 | self.vault_retrieve(&summary.vault_path)? |
| 272 | .and_then(|entry| { |
| 273 | let fm: serde_json::Map<String, serde_json::Value> = |
| 274 | serde_json::from_str(&entry.frontmatter_json).ok()?; |
| 275 | fm.get("title")?.as_str().map(String::from) |
| 276 | }) |
| 277 | .unwrap_or_else(|| id.clone()) |
| 278 | } else { |
| 279 | // Legacy entry with neither title nor vault_path — try scanning |
| 280 | self.find_intent_path(id)? |
| 281 | .and_then(|path| self.vault_retrieve(&path).ok().flatten()) |
| 282 | .and_then(|entry| { |
| 283 | let fm: serde_json::Map<String, serde_json::Value> = |
| 284 | serde_json::from_str(&entry.frontmatter_json).ok()?; |
| 285 | fm.get("title")?.as_str().map(String::from) |
| 286 | }) |
| 287 | .unwrap_or_else(|| id.clone()) |
| 288 | }; |
| 289 | |
| 290 | intents.push(IntentInfo { |
| 291 | id: id.clone(), |
| 292 | title, |
| 293 | status: summary.status.clone(), |
| 294 | priority: summary.priority.clone(), |
| 295 | assignee: summary.assignee.clone(), |
| 296 | goals: summary.goals, |
| 297 | blocked_by: summary.blocked_by.clone(), |
| 298 | }); |
| 299 | } |
| 300 | |
| 301 | // Sort by ID (which sorts by number within same prefix) |
| 302 | intents.sort_by(|a, b| a.id.cmp(&b.id)); |
| 303 | |
| 304 | Ok(intents) |
| 305 | } |
| 306 | |
| 307 | /// Show an intent's full content. |
| 308 | pub fn vault_intent_show(&self, intent_id: &str) -> Result<VaultEntry, RepositoryError> { |