{"version":3,"file":"workflowFinishedMessage.mjs","names":[],"sources":["../../../../src/tui/workflow/workflowFinishedMessage.ts"],"sourcesContent":["/**\n * Renders the `workflow-run-finished` custom message: one line per run that\n * reached a terminal state, rather than the host's default block of the\n * `[workflow-run-finished]` label above raw markdown.\n *\n * The same shape `@agimon-ai/doompi-team` gives a slash launch: a status glyph,\n * the run's identity, its outcome, and anything that went wrong indented under\n * it. A finished run is read at a glance in a transcript that is mostly about\n * something else, so it earns a line, not a card.\n *\n * DESIGN PATTERNS:\n * - A message with no `details` renders its content verbatim. That is a\n *   transcript entry written before the field existed, and re-deriving it by\n *   parsing the summary back out of markdown is exactly the liability\n *   `completionNotice.ts` in the team package refused to port\n * - The full summary is still the message's `content`, which is what the model\n *   reads and what `deliverAs: 'steer'` carries. This changes what a person\n *   sees, never what the agent is told\n */\n\nimport type { ExtensionAPI, Theme } from '@earendil-works/pi-coding-agent';\nimport { type Component, Text } from '@earendil-works/pi-tui';\n\nexport const WORKFLOW_FINISHED_MESSAGE = 'workflow-run-finished';\n\n/** One finished run, as the extension records it on the message. */\nexport interface WorkflowFinishedRun {\n  runKey: string;\n  workspace: string;\n  stage: string;\n  workflowId?: string;\n  failedJob?: string;\n  error?: string;\n}\n\nexport interface WorkflowFinishedDetails {\n  /** Kept for readers that already index runs by id; the lines come from `runs`. */\n  runIds?: string[];\n  runs?: WorkflowFinishedRun[];\n}\n\nconst COMPLETED_STAGE = 'completed';\nconst HELD_STAGES = new Set(['stopped', 'paused', 'cancelled']);\n\nfunction statusIcon(stage: string, theme: Theme): string {\n  if (stage === COMPLETED_STAGE) return theme.fg('success', '✔');\n  // Held is not failed: the run went nowhere wrong, it just stopped short.\n  if (HELD_STAGES.has(stage)) return theme.fg('warning', '■');\n  return theme.fg('error', '✖');\n}\n\nfunction runLine(run: WorkflowFinishedRun, theme: Theme): string {\n  const separator = ` ${theme.fg('dim', '·')} `;\n  const identity = [run.runKey, run.workspace].filter(Boolean).join('/');\n  const parts = [theme.fg('dim', identity), theme.fg('dim', run.stage)];\n  if (run.workflowId) parts.unshift(theme.bold(run.workflowId));\n  let text = `${statusIcon(run.stage, theme)} ${parts.join(separator)}`;\n  if (run.failedJob) text += `\\n  ${theme.fg('dim', `⎿  failed job: ${run.failedJob}`)}`;\n  if (run.error) text += `\\n  ${theme.fg('dim', `⎿  ${run.error}`)}`;\n  return text;\n}\n\n/**\n * Exported for tests: the rendered string before it is wrapped in a `Text`\n * component, so the formatting is assertable without a terminal.\n */\nexport function renderWorkflowFinished(runs: readonly WorkflowFinishedRun[], theme: Theme): string {\n  return runs.map((run) => runLine(run, theme)).join('\\n');\n}\n\nexport function isWorkflowFinishedRuns(value: unknown): value is WorkflowFinishedRun[] {\n  if (!Array.isArray(value) || value.length === 0) return false;\n  return value.every(\n    (entry) =>\n      typeof entry === 'object' &&\n      entry !== null &&\n      typeof (entry as WorkflowFinishedRun).runKey === 'string' &&\n      typeof (entry as WorkflowFinishedRun).stage === 'string',\n  );\n}\n\nexport function createWorkflowFinishedRenderer(): readonly [...Parameters<ExtensionAPI['registerMessageRenderer']>] {\n  return [\n    WORKFLOW_FINISHED_MESSAGE,\n    (message, _options, theme: Theme): Component => {\n      const content = typeof message.content === 'string' ? message.content : JSON.stringify(message.content);\n      const runs = (message.details as WorkflowFinishedDetails | undefined)?.runs;\n      if (!isWorkflowFinishedRuns(runs)) return new Text(content, 0, 0);\n      return new Text(renderWorkflowFinished(runs, theme), 0, 0);\n    },\n  ];\n}\n"],"mappings":";;AAuBA,MAAa,4BAA4B;AAkBzC,MAAM,kBAAkB;AACxB,MAAM,8BAAc,IAAI,IAAI;CAAC;CAAW;CAAU;AAAW,CAAC;AAE9D,SAAS,WAAW,OAAe,OAAsB;CACvD,IAAI,UAAU,iBAAiB,OAAO,MAAM,GAAG,WAAW,GAAG;CAE7D,IAAI,YAAY,IAAI,KAAK,GAAG,OAAO,MAAM,GAAG,WAAW,GAAG;CAC1D,OAAO,MAAM,GAAG,SAAS,GAAG;AAC9B;AAEA,SAAS,QAAQ,KAA0B,OAAsB;CAC/D,MAAM,YAAY,IAAI,MAAM,GAAG,OAAO,GAAG,EAAE;CAC3C,MAAM,WAAW,CAAC,IAAI,QAAQ,IAAI,SAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CACrE,MAAM,QAAQ,CAAC,MAAM,GAAG,OAAO,QAAQ,GAAG,MAAM,GAAG,OAAO,IAAI,KAAK,CAAC;CACpE,IAAI,IAAI,YAAY,MAAM,QAAQ,MAAM,KAAK,IAAI,UAAU,CAAC;CAC5D,IAAI,OAAO,GAAG,WAAW,IAAI,OAAO,KAAK,EAAE,GAAG,MAAM,KAAK,SAAS;CAClE,IAAI,IAAI,WAAW,QAAQ,OAAO,MAAM,GAAG,OAAO,kBAAkB,IAAI,WAAW;CACnF,IAAI,IAAI,OAAO,QAAQ,OAAO,MAAM,GAAG,OAAO,MAAM,IAAI,OAAO;CAC/D,OAAO;AACT;;;;;AAMA,SAAgB,uBAAuB,MAAsC,OAAsB;CACjG,OAAO,KAAK,KAAK,QAAQ,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;AACzD;AAEA,SAAgB,uBAAuB,OAAgD;CACrF,IAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,GAAG,OAAO;CACxD,OAAO,MAAM,OACV,UACC,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAA8B,WAAW,YACjD,OAAQ,MAA8B,UAAU,QACpD;AACF;AAEA,SAAgB,iCAAoG;CAClH,OAAO,CACL,4BACC,SAAS,UAAU,UAA4B;EAC9C,MAAM,UAAU,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU,KAAK,UAAU,QAAQ,OAAO;EACtG,MAAM,OAAQ,QAAQ,SAAiD;EACvE,IAAI,CAAC,uBAAuB,IAAI,GAAG,OAAO,IAAI,KAAK,SAAS,GAAG,CAAC;EAChE,OAAO,IAAI,KAAK,uBAAuB,MAAM,KAAK,GAAG,GAAG,CAAC;CAC3D,CACF;AACF"}