{"version":3,"sources":["../src/cli/commands/ingest/list.ts"],"sourcesContent":["import { setTimeout as wait } from \"node:timers/promises\";\nimport chalk from \"chalk\";\nimport { loadConfig, isLoggedIn } from \"@/cli/utils/governance/config\";\nimport {\n  listIngestionSources,\n  GovernanceCliError,\n} from \"@/cli/utils/governance/cli-api\";\n\n/**\n * `langwatch ingest list [--all] [--json]`\n *\n * Read-only enumeration of the org's IngestionSources, mirroring the\n * `/settings/governance/ingestion-sources` list page for ops folks\n * who live in terminal. Same multi-tenant guard as the web UI\n * (org-scoped via the device-flow Bearer token).\n */\nexport async function ingestListCommand(options: {\n  all?: boolean;\n  json?: boolean;\n}): Promise<void> {\n  const cfg = loadConfig();\n  if (!isLoggedIn(cfg)) {\n    process.stderr.write(\n      \"Not logged in. Run `langwatch login --device` first.\\n\",\n    );\n    process.exit(1);\n  }\n\n  let sources;\n  try {\n    sources = await listIngestionSources(cfg, { includeArchived: !!options.all });\n  } catch (err) {\n    if (err instanceof GovernanceCliError) {\n      process.stderr.write(`Error: ${err.message}\\n`);\n    } else {\n      process.stderr.write(`Error: ${String(err)}\\n`);\n    }\n    process.exit(1);\n  }\n\n  if (options.json) {\n    console.log(JSON.stringify(sources, null, 2));\n    return;\n  }\n\n  if (sources.length === 0) {\n    console.log(\n      chalk.gray(\n        \"No ingestion sources yet. Open the admin UI at \" +\n          `${cfg.control_plane_url.replace(/\\/+$/, \"\")}/settings/governance/ingestion-sources` +\n          \" to connect your first source.\",\n      ),\n    );\n    return;\n  }\n\n  // Stable formatted table. No external table dep — keep deps tight.\n  const cols: Array<keyof (typeof sources)[number]> = [\n    \"name\",\n    \"sourceType\",\n    \"status\",\n    \"lastEventAt\",\n  ];\n  const headerRow = [\"NAME\", \"TYPE\", \"STATUS\", \"LAST EVENT\"];\n  const rows: string[][] = [headerRow];\n  for (const s of sources) {\n    const lastEvent =\n      s.lastEventAt === null\n        ? chalk.gray(\"—\")\n        : humanRelative(new Date(s.lastEventAt));\n    const archivedTag = s.archivedAt ? chalk.gray(\" [archived]\") : \"\";\n    rows.push([\n      s.name + archivedTag,\n      s.sourceType,\n      colorStatus(s.status),\n      lastEvent,\n    ]);\n  }\n  printTable(rows);\n\n  // Tiny await to flush stdout cleanly when piping into less etc.\n  await wait(0);\n}\n\nfunction colorStatus(status: string): string {\n  switch (status) {\n    case \"active\":\n      return chalk.green(status);\n    case \"awaiting_first_event\":\n      return chalk.yellow(status);\n    case \"archived\":\n      return chalk.gray(status);\n    default:\n      return status;\n  }\n}\n\n/**\n * Render a relative timestamp like \"5m ago\" / \"2h ago\" / \"3d ago\"\n * for the table's LAST EVENT column. Falls back to the ISO string\n * for future timestamps (clock drift) since \"in 5 minutes\" would be\n * confusing in a \"last event\" context. Exported for unit testing.\n */\nexport function humanRelative(d: Date, now: number = Date.now()): string {\n  const ms = now - d.getTime();\n  if (ms < 0) return d.toISOString();\n  const s = Math.floor(ms / 1000);\n  if (s < 60) return `${s}s ago`;\n  const m = Math.floor(s / 60);\n  if (m < 60) return `${m}m ago`;\n  const h = Math.floor(m / 60);\n  if (h < 24) return `${h}h ago`;\n  const days = Math.floor(h / 24);\n  return `${days}d ago`;\n}\n\n/**\n * Build a fixed-width table from rows including a leading header row.\n * Returns the formatted string (one row per \\n-separated line) instead\n * of console.log-ing directly, so callers control output and tests can\n * assert column alignment without spying on stdout.\n *\n * Each cell's visible width is computed by stripping ANSI escape codes\n * (chalk wraps colors as `\\x1b[Nm...\\x1b[0m`); without this, coloured\n * cells appear longer than they actually are and break alignment.\n */\nexport function buildTable(rows: string[][]): string {\n  if (rows.length === 0) return \"\";\n  const widths = rows[0]!.map((_, i) =>\n    rows.reduce((max, r) => Math.max(max, stripAnsi(r[i] ?? \"\").length), 0),\n  );\n  const lines: string[] = [];\n  for (const row of rows) {\n    const padded = row.map((cell, i) => {\n      const visibleLen = stripAnsi(cell).length;\n      return cell + \" \".repeat(Math.max(0, widths[i]! - visibleLen));\n    });\n    lines.push(padded.join(\"  \"));\n  }\n  return lines.join(\"\\n\");\n}\n\nfunction printTable(rows: string[][]): void {\n  const out = buildTable(rows);\n  if (out) console.log(out);\n}\n\nfunction stripAnsi(s: string): string {\n  // eslint-disable-next-line no-control-regex -- intentional: stripping ANSI escape codes from chalk output for column-width math\n  return s.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n}\n"],"mappings":"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","names":[]}