/** Shared utility functions and constants for WorkItemDetailPanel sub-components. */ import type { AgentStatusValue } from "../api/agents"; export const STAGE_LABELS: Record = { backlog: "Backlog", current: "Current", qa: "QA", merge: "To Merge", done: "Done", archived: "Archived", }; export const STATUS_COLORS: Record = { running: "#3fb950", pending: "#e3b341", completed: "#aaa", failed: "#f85149", }; /** * Strip YAML front matter and the first H1 heading from story content before * rendering. The panel header already shows the story ID/title, so rendering * them again inside the markdown body creates duplicate information. */ export function stripDisplayContent(content: string): string { // Guard: content may be undefined/null at runtime if the server response is // missing the field (e.g. a tombstoned story returns an error object). if (!content) return ""; let text = content; // Strip YAML front matter (--- ... ---) if (text.startsWith("---")) { const eol = text.indexOf("\n"); if (eol !== -1) { const closeIdx = text.indexOf("\n---", eol); if (closeIdx !== -1) { text = text.slice(closeIdx + 4); } } } // Trim leading blank lines left by the front matter text = text.trimStart(); // Strip the first H1 heading — it duplicates the panel header title if (text.startsWith("# ")) { const eol = text.indexOf("\n"); text = eol !== -1 ? text.slice(eol + 1).trimStart() : ""; } return text; } /** * Format the story ID/title line shown in the panel header. * Produces e.g. "Story 454: My Story Name" or "Bug 12: Crash on startup". * Falls back to name or storyId when the pattern doesn't match. */ export function formatStoryTitle(storyId: string, name: string | null): string { const match = storyId.match(/^(\d+)_([a-z]+)_/); if (!match || !name) return name ?? storyId; const [, number, type] = match; const typeLabel = type.charAt(0).toUpperCase() + type.slice(1); return `${typeLabel} ${number}: ${name}`; }