import { basename } from "node:path"; export type InputKind = "prompt" | "md-file" | "prd" | "jira"; export interface ClassifiedInput { kind: InputKind; value: string; } /** * Classify a raw sf_flow_auto input string into one of the four input kinds. * - `jira ` → jira (value = the issue key) * - `*.md` / `path/to.md` → md-file (value = the path) * - `prd:` / `*.prd` → prd (value = the path) * - anything else → prompt (value = the verbatim text) */ export function classifyInput(raw: string): ClassifiedInput { const s = raw.trim(); if (/^jira\s+/i.test(s)) return { kind: "jira", value: resolveJiraRef(s) }; if (/\.md$/i.test(s) || /^\.?\/.+\.md$/i.test(s)) return { kind: "md-file", value: s }; if (/\.prd$/i.test(s) || /^prd:/i.test(s)) return { kind: "prd", value: s.replace(/^prd:\s*/i, "") }; return { kind: "prompt", value: s }; } /** Extract a Jira issue key (e.g. PROJ-123) from a `jira ...` string. */ export function resolveJiraRef(raw: string): string { const m = raw.match(/([A-Z][A-Z0-9_]+-\d+)/); return m ? m[1] : raw.replace(/^jira\s+/i, ""); } /** * Map a classified input to the SHORT source the run slug is derived from (the * same slug feeds the ai_plan// folder and the flow/ worktree * branch). File inputs use the basename (path discarded), jira uses the key, * prompt uses the text verbatim (deriveSlug kebabs + truncates). */ export function slugSourceFor(c: ClassifiedInput): string { switch (c.kind) { case "md-file": case "prd": return basename(c.value).replace(/\.(md|prd)$/i, ""); case "jira": return c.value; case "prompt": default: return c.value; } }