{"version":3,"file":"workflowStatusRow.cjs","names":[],"sources":["../../../../src/tui/workflow/workflowStatusRow.ts"],"sourcesContent":["/**\n * Session reporting for a run's progress log.\n *\n * DESIGN PATTERNS:\n * - Pure derivation. Takes a run's raw progress events and returns report lines,\n *   so the behaviour is unit-testable without a registry or a live run.\n *\n * CODING STANDARDS:\n * - Named exports only\n * - Explicit return types on exported members\n *\n * Live progress now renders through `workflowProgressOverlay.ts`. This module\n * remains the compatibility derivation used by terminal summaries and legacy\n * workflow-step cards already persisted in older sessions.\n */\n\nimport type { WorkflowProgressEvent } from '@agimon-ai/workflow-mcp';\n\n/** Step names come from workflow YAML and can be sentences. */\nconst MAX_STEP_LABEL = 48;\n\n/** One session line, plus the key that stops it being reported twice. */\nexport interface StepReport {\n  duration?: string;\n  job: string;\n  key: string;\n  status: 'FAILED' | 'FINISHED' | 'STARTED';\n  step: string;\n}\n\nfunction truncateStep(step: string): string {\n  return step.length <= MAX_STEP_LABEL ? step : `${step.slice(0, MAX_STEP_LABEL - 1)}…`;\n}\n\n/**\n * Human-scale duration.\n *\n * Rounded hard on purpose: this is read at a glance next to a step name, where\n * milliseconds are noise and \"4m12s\" answers the only question being asked.\n */\nexport function humanizeDuration(ms: number): string {\n  if (!Number.isFinite(ms) || ms < 0) return '?';\n  if (ms < 1000) return `${ms}ms`;\n  const seconds = Math.round(ms / 1000);\n  if (seconds < 60) return `${seconds}s`;\n  const minutes = Math.floor(seconds / 60);\n  if (minutes < 60) return `${minutes}m${String(seconds % 60).padStart(2, '0')}s`;\n  return `${Math.floor(minutes / 60)}h${String(minutes % 60).padStart(2, '0')}m`;\n}\n\n/**\n * Turn a run's raw progress log into session report lines.\n *\n * Derives durations by pairing each step's start with its end rather than\n * recording a duration in the log, so nothing about the log format has to\n * change and old runs read back the same way.\n *\n * Keyed by the event's own timestamp so a caller polling the same append-only\n * file repeatedly reports each transition exactly once, however often it polls.\n */\nexport function stepReportLines(runKey: string, events: WorkflowProgressEvent[]): StepReport[] {\n  const startedAt = new Map<string, string>();\n  const reports: StepReport[] = [];\n\n  for (const event of events) {\n    if (event.type !== 'step' || !event.step) continue;\n    const id = `${runKey}/${event.job}`;\n    const stepKey = `${id}/${event.step}`;\n    const label = truncateStep(event.step);\n\n    if (event.status === 'running') {\n      startedAt.set(stepKey, event.at);\n      reports.push({ job: event.job, key: `started:${stepKey}:${event.at}`, status: 'STARTED', step: label });\n      continue;\n    }\n\n    const began = startedAt.get(stepKey);\n    const duration = began ? humanizeDuration(Date.parse(event.at) - Date.parse(began)) : '?';\n    // A failed step did finish, but calling it FINISHED buries the one outcome\n    // the reader needs to see. Same shape, honest verb.\n    const status = event.status === 'failed' ? 'FAILED' : 'FINISHED';\n    reports.push({ duration, job: event.job, key: `${status}:${stepKey}:${event.at}`, status, step: label });\n  }\n\n  return reports;\n}\n"],"mappings":";;;;;;;AAwCA,SAAgB,iBAAiB,IAAoB;CACnD,IAAI,CAAC,OAAO,SAAS,EAAE,KAAK,KAAK,GAAG,OAAO;CAC3C,IAAI,KAAK,KAAM,OAAO,GAAG,GAAG;CAC5B,MAAM,UAAU,KAAK,MAAM,KAAK,GAAI;CACpC,IAAI,UAAU,IAAI,OAAO,GAAG,QAAQ;CACpC,MAAM,UAAU,KAAK,MAAM,UAAU,EAAE;CACvC,IAAI,UAAU,IAAI,OAAO,GAAG,QAAQ,GAAG,OAAO,UAAU,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE;CAC7E,OAAO,GAAG,KAAK,MAAM,UAAU,EAAE,EAAE,GAAG,OAAO,UAAU,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE;AAC9E"}