{"version":3,"sources":["../src/cli/commands/experiment/status.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport ora from \"ora\";\nimport { ExperimentsApiService } from \"@/client-sdk/services/experiments/experiments-api.service\";\nimport { deriveRunStatus } from \"@/client-sdk/services/experiments/run-status\";\nimport { checkApiKey } from \"../../utils/apiKey\";\nimport { failSpinner } from \"../../utils/spinnerError\";\nimport { resolveRunId } from \"./resolve-run\";\n\nconst statusColor = (status: string) =>\n  status === \"completed\"\n    ? chalk.green\n    : status === \"failed\" || status === \"interrupted\"\n      ? chalk.red\n      : status === \"running\"\n        ? chalk.yellow\n        : chalk.gray;\n\n// SDK-logged runs (langwatch.experiment + evaluation.log) never populate the\n// Redis run-state that GET /runs/:runId reads, so that endpoint 404s for them.\n// Their data lives only in ClickHouse, reachable through the results endpoint,\n// so we derive the status from there. experimentSlug is required because runId\n// is not unique across experiments once the Redis run-state expires.\nconst statusFromResults = async ({\n  service,\n  runId,\n  experimentSlug,\n}: {\n  service: ExperimentsApiService;\n  runId: string;\n  experimentSlug: string;\n}): Promise<{\n  runId: string;\n  status: string;\n  progress: number;\n  total: number;\n  startedAt?: number;\n  finishedAt?: number;\n  stoppedAt?: number;\n} | null> => {\n  try {\n    const results = await service.getRunResults({ runId, experimentSlug });\n    return {\n      runId,\n      status: deriveRunStatus(results.timestamps),\n      progress: results.progress ?? results.dataset.length,\n      total: results.total ?? results.dataset.length,\n      startedAt: results.timestamps.createdAt,\n      finishedAt: results.timestamps.finishedAt ?? undefined,\n      stoppedAt: results.timestamps.stoppedAt ?? undefined,\n    };\n  } catch (error) {\n    // Only a genuine \"no such run\" is a fallback miss. Real 5xx / auth /\n    // network errors must propagate so they aren't masked as not-found.\n    const message = error instanceof Error ? error.message : String(error);\n    if (/404|not found/i.test(message)) {\n      return null;\n    }\n    throw error;\n  }\n};\n\nexport const experimentStatusCommand = async (\n  experimentSlug: string,\n  options?: { format?: string; runId?: string },\n): Promise<void> => {\n  checkApiKey();\n\n  const service = new ExperimentsApiService();\n  const spinner = ora(`Checking status for \"${experimentSlug}\"...`).start();\n\n  try {\n    const runId = await resolveRunId({\n      service,\n      experimentSlug,\n      runId: options?.runId,\n    });\n\n    let status: {\n      runId?: string;\n      status: string;\n      progress: number;\n      total: number;\n      startedAt?: number;\n      finishedAt?: number;\n      stoppedAt?: number;\n      summary?: {\n        completedCells?: number;\n        failedCells?: number;\n        duration?: number;\n        runUrl?: string;\n      };\n    };\n\n    try {\n      status = await service.getRunStatus(runId);\n    } catch (error) {\n      // Only a missing Redis run-state warrants the ClickHouse fallback. Real\n      // 5xx / auth / network failures must propagate, otherwise a working\n      // results call would mask them as a healthy derived status.\n      const message = error instanceof Error ? error.message : String(error);\n      if (!/404|not found/i.test(message)) {\n        throw error;\n      }\n\n      const fallback = await statusFromResults({\n        service,\n        runId,\n        experimentSlug,\n      });\n      if (!fallback) throw error;\n      status = fallback;\n    }\n\n    const color = statusColor(status.status);\n    spinner.succeed(`Run ${chalk.cyan(runId)}: ${color(status.status)}`);\n\n    if (options?.format === \"json\") {\n      console.log(JSON.stringify(status, null, 2));\n      return;\n    }\n\n    console.log();\n    console.log(`  ${chalk.gray(\"Status:\")}   ${color(status.status)}`);\n    console.log(`  ${chalk.gray(\"Progress:\")} ${status.progress}/${status.total} cells`);\n\n    if (status.startedAt) {\n      console.log(`  ${chalk.gray(\"Started:\")}  ${new Date(status.startedAt).toLocaleString()}`);\n    }\n    if (status.finishedAt) {\n      console.log(`  ${chalk.gray(\"Finished:\")} ${new Date(status.finishedAt).toLocaleString()}`);\n    }\n    if (status.stoppedAt) {\n      console.log(`  ${chalk.gray(\"Stopped:\")}  ${new Date(status.stoppedAt).toLocaleString()}`);\n    }\n\n    if (status.summary) {\n      console.log();\n      console.log(chalk.bold(\"  Summary:\"));\n      if (status.summary.completedCells !== undefined) {\n        console.log(`    ${chalk.gray(\"Completed:\")} ${chalk.green(String(status.summary.completedCells))}`);\n      }\n      if (status.summary.failedCells) {\n        console.log(`    ${chalk.gray(\"Failed:\")}    ${chalk.red(String(status.summary.failedCells))}`);\n      }\n      if (status.summary.duration) {\n        console.log(`    ${chalk.gray(\"Duration:\")}  ${(status.summary.duration / 1000).toFixed(1)}s`);\n      }\n      if (status.summary.runUrl) {\n        console.log(`    ${chalk.gray(\"View:\")}      ${status.summary.runUrl}`);\n      }\n    }\n\n    console.log();\n  } catch (error) {\n    failSpinner({ spinner, error, action: \"check experiment status\" });\n    process.exit(1);\n  }\n};\n"],"mappings":"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","names":[]}