{"version":3,"file":"index.cjs","names":["resolve"],"sources":["../../../../src/services/workflowRuns/index.ts"],"sourcesContent":["import { resolve } from 'node:path';\n\nimport type {\n  WorkflowJobPhase,\n  WorkflowJobView,\n  WorkflowOutcome,\n  WorkflowPosition,\n  WorkflowProgressState,\n  WorkflowRunView,\n  WorkflowStage,\n  WorkflowStepView,\n} from '../../types/webWorkflows';\n\n/**\n * MIRRORS @agimon-ai/workflow-mcp's on-disk registry\n * (src/services/WorkflowRegistryService.ts and WorkflowProgressService.ts in\n * that package). The engine keeps one directory per run under\n * `<home>/workspaces/<workspace>/<stage>/<runKey>/` holding a `run.json`\n * record and an append-only `progress.ndjson` job/step log; the hub only ever\n * reads them. The derivation is duplicated rather than imported because\n * doompi-web must not depend on the engine at runtime; the unit suite pins\n * this mirror against the package's published types.\n */\nconst DEFAULT_WORKFLOW_HOME_DIR_NAME = '.workflow-mcp';\nexport const WORKFLOW_HOME_ENV = 'WORKFLOW_MCP_HOME';\nexport const WORKSPACES_DIR_NAME = 'workspaces';\nexport const RUN_RECORD_FILE_NAME = 'run.json';\nexport const PROGRESS_FILE_NAME = 'progress.ndjson';\nexport const WORKFLOW_STAGES: readonly WorkflowStage[] = ['running', 'completed', 'error'];\n\n/**\n * Errored runs stay a day, which is how long recovery has to act on them.\n *\n * Finished runs have no retention of their own: a session keeps every run it\n * launched, grouped by outcome, for as long as the session lives. A run leaves\n * the view when the engine prunes its registry directory, not on a timer here,\n * because \"what did this session run today\" is a question asked long after the\n * run settled.\n */\nexport const WORKFLOW_ERROR_RETENTION_MS = 24 * 60 * 60 * 1000;\n/**\n * Upper bound per outcome group rather than over the whole list.\n *\n * One cap across every run let a long stream of green runs push a failure out\n * of the list, which is the one thing that must never fall off the end.\n */\nexport const MAX_PRESENTED_WORKFLOW_RUNS_PER_GROUP = 24;\n\n/** The env key doompi-workflow stamps on runs it launches; ties a run to a Pi session. */\nexport const PI_SESSION_ENV = 'PI_SESSION_ID';\n\nconst PROGRESS_STATES: ReadonlySet<string> = new Set([\n  'running',\n  'completed',\n  'skipped',\n  'failed',\n  'pause_requested',\n  'paused',\n  'resumed',\n]);\nconst OUTCOMES: ReadonlySet<string> = new Set(['success', 'skipped', 'failed', 'interrupted']);\nconst EXECUTION_STATES: ReadonlySet<string> = new Set(['running', 'pause_requested', 'paused', 'resume_requested']);\nconst STEP_TERMINAL_STATES: ReadonlySet<WorkflowProgressState> = new Set(['completed', 'skipped', 'failed']);\n/** The engine records its pre:/post: blocks under these reserved pseudo-job names. */\nconst PHASE_JOB_PRE = 'pre';\nconst PHASE_JOB_POST = 'post';\n\n// oxlint-disable-next-line no-control-regex -- stripping terminal color codes from errorMessage is the point\nconst ANSI_ESCAPE_PATTERN = /\\u001b\\[[0-9;]*[A-Za-z]/g;\n\nexport interface WorkflowHomeInput {\n  /** process.env.WORKFLOW_MCP_HOME, supplied by the caller. */\n  envValue: string | undefined;\n  /** os.homedir(), supplied by the caller. */\n  homeDir: string;\n}\n\n/** Where workflow-mcp keeps its registry, mirroring the engine's own resolution. */\nexport function resolveWorkflowHome(input: WorkflowHomeInput): string {\n  return resolve(\n    input.envValue !== undefined && input.envValue !== ''\n      ? input.envValue\n      : resolve(input.homeDir, DEFAULT_WORKFLOW_HOME_DIR_NAME),\n  );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction asOptionalString(value: unknown): string | undefined {\n  return typeof value === 'string' && value !== '' ? value : undefined;\n}\n\nfunction asOptionalNumber(value: unknown): number | undefined {\n  return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction stripAnsi(text: string): string {\n  return text.replace(ANSI_ESCAPE_PATTERN, '').trim();\n}\n\n/**\n * One run record plus the facts the hub needs for session scoping but the\n * page never sees.\n */\nexport interface ParsedWorkflowRun {\n  /** The wire view, before the progress log is folded in (jobs empty). */\n  view: WorkflowRunView;\n  /** env.PI_SESSION_ID from the record, when the launcher stamped one. */\n  piSessionId?: string;\n}\n\n/**\n * Validates one run.json into the wire shape plus scoping facts.\n *\n * Returns undefined for anything unreadable or a foreign format. The record\n * is trusted for its own stage: the registry rewrites it when a run moves\n * between stage directories.\n */\nexport function parseWorkflowRunRecord(raw: string): ParsedWorkflowRun | undefined {\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(raw);\n  } catch {\n    return undefined;\n  }\n  if (!isRecord(parsed)) return undefined;\n  const runKey = asOptionalString(parsed.runKey);\n  const workspace = asOptionalString(parsed.workspace);\n  const workflowPath = asOptionalString(parsed.workflowPath);\n  const startedAt = asOptionalString(parsed.startedAt);\n  const stage = asOptionalString(parsed.stage);\n  if (!runKey || !workspace || !workflowPath || !startedAt) return undefined;\n  if (stage === undefined || !WORKFLOW_STAGES.includes(stage as WorkflowStage)) return undefined;\n\n  const outcome = asOptionalString(parsed.outcome);\n  const executionState = asOptionalString(parsed.executionState);\n  const rawError = asOptionalString(parsed.errorMessage);\n  const env = isRecord(parsed.env) ? parsed.env : undefined;\n  const view: WorkflowRunView = {\n    runKey,\n    workspace,\n    displayName: asOptionalString(parsed.displayName) ?? runKey,\n    ...(asOptionalString(parsed.workflowName) === undefined\n      ? {}\n      : { workflowName: asOptionalString(parsed.workflowName) }),\n    workflowPath,\n    stage: stage as WorkflowStage,\n    ...(outcome !== undefined && OUTCOMES.has(outcome) ? { outcome: outcome as WorkflowOutcome } : {}),\n    ...(executionState !== undefined && EXECUTION_STATES.has(executionState)\n      ? { executionState: executionState as WorkflowRunView['executionState'] }\n      : {}),\n    ...(asOptionalString(parsed.prompt) === undefined ? {} : { prompt: asOptionalString(parsed.prompt) }),\n    startedAt,\n    ...(asOptionalString(parsed.finishedAt) === undefined ? {} : { finishedAt: asOptionalString(parsed.finishedAt) }),\n    ...(rawError === undefined ? {} : { errorMessage: stripAnsi(rawError) }),\n    ...(asOptionalString(parsed.failedJob) === undefined ? {} : { failedJob: asOptionalString(parsed.failedJob) }),\n    ...(parsed.stale === true ? { stale: true } : {}),\n    ...(asOptionalString(parsed.staleReason) === undefined\n      ? {}\n      : { staleReason: asOptionalString(parsed.staleReason) }),\n    ...(asOptionalString(parsed.worktreeBranch) === undefined\n      ? {}\n      : { worktreeBranch: asOptionalString(parsed.worktreeBranch) }),\n    jobs: [],\n  };\n  const piSessionId = env === undefined ? undefined : asOptionalString(env[PI_SESSION_ENV]);\n  return { view, ...(piSessionId === undefined ? {} : { piSessionId }) };\n}\n\ninterface WorkflowProgressEvent {\n  type: 'job' | 'step';\n  status: WorkflowProgressState;\n  job: string;\n  step?: string;\n  index?: number;\n  total?: number;\n  reason?: string;\n  at: string;\n}\n\n/**\n * Parses the append-only progress log. Malformed lines are skipped rather\n * than failing the file: a reader routinely catches a torn final line\n * mid-append.\n */\nexport function parseWorkflowProgress(raw: string): WorkflowProgressEvent[] {\n  const events: WorkflowProgressEvent[] = [];\n  for (const line of raw.split('\\n')) {\n    const trimmed = line.trim();\n    if (trimmed === '') continue;\n    let parsed: unknown;\n    try {\n      parsed = JSON.parse(trimmed);\n    } catch {\n      continue;\n    }\n    if (!isRecord(parsed)) continue;\n    const type = parsed.type;\n    const status = asOptionalString(parsed.status);\n    const job = asOptionalString(parsed.job);\n    const at = asOptionalString(parsed.at);\n    if ((type !== 'job' && type !== 'step') || !job || !at) continue;\n    if (status === undefined || !PROGRESS_STATES.has(status)) continue;\n    const step = asOptionalString(parsed.step);\n    const index = asOptionalNumber(parsed.index);\n    const total = asOptionalNumber(parsed.total);\n    const reason = asOptionalString(parsed.reason);\n    events.push({\n      type,\n      status: status as WorkflowProgressState,\n      job,\n      ...(step === undefined ? {} : { step }),\n      ...(index === undefined ? {} : { index }),\n      ...(total === undefined ? {} : { total }),\n      ...(reason === undefined ? {} : { reason }),\n      at,\n    });\n  }\n  return events;\n}\n\nfunction jobPhase(name: string): WorkflowJobPhase {\n  if (name === PHASE_JOB_PRE) return PHASE_JOB_PRE;\n  if (name === PHASE_JOB_POST) return PHASE_JOB_POST;\n  return 'job';\n}\n\n/**\n * Folds the event log into the current job tree; later events win, so a job\n * that started and later failed reads as failed. Jobs and steps keep the\n * order of their first appearance.\n */\nexport function foldWorkflowProgress(events: readonly WorkflowProgressEvent[]): WorkflowJobView[] {\n  const jobs: WorkflowJobView[] = [];\n  const jobByName = new Map<string, WorkflowJobView>();\n  for (const event of events) {\n    let job = jobByName.get(event.job);\n    if (job === undefined) {\n      job = { name: event.job, phase: jobPhase(event.job), status: event.status, steps: [] };\n      jobByName.set(event.job, job);\n      jobs.push(job);\n    }\n    if (event.type === 'job') {\n      job.status = event.status;\n      if (event.reason !== undefined) job.reason = event.reason;\n      if (event.index !== undefined) job.index = event.index;\n      if (event.total !== undefined) job.total = event.total;\n      if (event.status === 'running' && job.startedAt === undefined) job.startedAt = event.at;\n      if (STEP_TERMINAL_STATES.has(event.status)) job.endedAt = event.at;\n      continue;\n    }\n    if (event.step === undefined) continue;\n    let step: WorkflowStepView | undefined = job.steps.find((candidate) => candidate.name === event.step);\n    if (step === undefined) {\n      step = { name: event.step, status: event.status };\n      job.steps.push(step);\n    }\n    step.status = event.status;\n    if (event.reason !== undefined) step.reason = event.reason;\n    if (event.status === 'running' && step.startedAt === undefined) step.startedAt = event.at;\n    if (STEP_TERMINAL_STATES.has(event.status)) step.endedAt = event.at;\n  }\n  return jobs;\n}\n\nconst ACTIVE_PROGRESS_STATES: ReadonlySet<WorkflowProgressState> = new Set([\n  'running',\n  'pause_requested',\n  'paused',\n  'resumed',\n]);\n\n/** The job and step a run is on right now, for the NOW breadcrumb. */\nexport function workflowPosition(jobs: readonly WorkflowJobView[]): WorkflowPosition | undefined {\n  for (let jobIndex = jobs.length - 1; jobIndex >= 0; jobIndex -= 1) {\n    const job = jobs[jobIndex]!;\n    if (!ACTIVE_PROGRESS_STATES.has(job.status)) continue;\n    for (let stepIndex = job.steps.length - 1; stepIndex >= 0; stepIndex -= 1) {\n      const step = job.steps[stepIndex]!;\n      if (ACTIVE_PROGRESS_STATES.has(step.status)) {\n        return {\n          job: job.name,\n          step: step.name,\n          ...(job.index === undefined ? {} : { index: job.index }),\n          ...(job.total === undefined ? {} : { total: job.total }),\n        };\n      }\n    }\n    return {\n      job: job.name,\n      ...(job.index === undefined ? {} : { index: job.index }),\n      ...(job.total === undefined ? {} : { total: job.total }),\n    };\n  }\n  return undefined;\n}\n\n/** The finished view: record fields plus the folded job tree and position. */\nexport function completeWorkflowRunView(view: WorkflowRunView, jobs: WorkflowJobView[]): WorkflowRunView {\n  const position = view.stage === 'running' ? workflowPosition(jobs) : undefined;\n  return { ...view, jobs, ...(position === undefined ? {} : { position }) };\n}\n\n/**\n * Whether a run belongs on a session's workflow tab: launched by that Pi\n * session, which is the same env test doompi-workflow's isSessionRun applies.\n *\n * The registry is one directory under $HOME shared by every repository and\n * every Pi session on the machine, so repository proximity is not ownership.\n * Scoping on it as well let two sessions open in one repo read each other's\n * history, and kept a dead session's runs on the board of every session that\n * replaced it. Fails closed on an unstamped record, which is what a launch\n * from the CLI rather than from a session leaves behind.\n */\nexport function runBelongsToSession(run: ParsedWorkflowRun, sessionId: string): boolean {\n  return run.piSessionId !== undefined && run.piSessionId === sessionId;\n}\n\nfunction parseTime(value: string | undefined): number {\n  if (value === undefined) return 0;\n  const time = Date.parse(value);\n  return Number.isFinite(time) ? time : 0;\n}\n\nconst STAGE_ORDER: Readonly<Record<WorkflowStage, number>> = { running: 0, error: 1, completed: 2 };\n\n/**\n * Whether a run still belongs in the view.\n *\n * Only errored runs age out here, and slowly: everything else a session\n * started stays until the engine forgets the run itself.\n */\nfunction withinRetention(run: WorkflowRunView, now: number): boolean {\n  if (run.stage !== 'error') return true;\n  const settledAt = parseTime(run.finishedAt) || parseTime(run.startedAt);\n  return now - settledAt < WORKFLOW_ERROR_RETENTION_MS;\n}\n\n/**\n * When a run last moved, which is what orders it within its group.\n *\n * A running run has only its start; a settled one is ordered by when it\n * settled, because a list kept for the whole session is read as a history and\n * two runs started together can finish an hour apart.\n */\nfunction lastMovedAt(run: WorkflowRunView): number {\n  return run.stage === 'running' ? parseTime(run.startedAt) : parseTime(run.finishedAt) || parseTime(run.startedAt);\n}\n\n/**\n * Running runs first, then errored (recovery acts on them), then finished;\n * newest first within a group, and each group capped on its own.\n */\nexport function presentWorkflowRuns(runs: readonly WorkflowRunView[], now: number): WorkflowRunView[] {\n  const groups = new Map<WorkflowStage, WorkflowRunView[]>();\n  for (const run of runs) {\n    if (!withinRetention(run, now)) continue;\n    const group = groups.get(run.stage);\n    if (group) group.push(run);\n    else groups.set(run.stage, [run]);\n  }\n  return [...groups.entries()]\n    .sort(([left], [right]) => STAGE_ORDER[left] - STAGE_ORDER[right])\n    .flatMap(([, group]) =>\n      group\n        .sort((left, right) => lastMovedAt(right) - lastMovedAt(left))\n        .slice(0, MAX_PRESENTED_WORKFLOW_RUNS_PER_GROUP),\n    );\n}\n"],"mappings":"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"}