import { defineCommand } from '@kb-labs/sdk';
import { loadTrace, formatTraceLoadError } from '@kb-labs/agent-tracing';

// src/cli/commands/trace-diagnose.ts

// src/cli/commands/trace-event-normalizer.ts
function normalizeTraceEvents(events) {
  const out = [];
  let currentIteration = 0;
  for (const raw of events) {
    const type = String(raw.type ?? "");
    const data = getEventData(raw);
    const explicitIteration = asNumber(raw.iteration) ?? asNumber(data.iteration);
    if (type === "iteration:start") {
      currentIteration = explicitIteration ?? Math.max(1, currentIteration + 1);
    }
    const iteration = explicitIteration ?? currentIteration;
    out.push({ raw, type, data, iteration });
  }
  return out;
}
function getEventData(event) {
  const data = event.data;
  if (data && typeof data === "object") {
    return data;
  }
  return {};
}
function asNumber(value) {
  if (typeof value === "number" && Number.isFinite(value)) {
    return value;
  }
  if (typeof value === "string") {
    const n = Number(value);
    if (Number.isFinite(n)) {
      return n;
    }
  }
  return void 0;
}

// src/cli/commands/trace-diagnose.ts
var trace_diagnose_default = defineCommand({
  id: "trace:diagnose",
  description: 'Quick diagnostic analysis \u2014 answers "what went wrong?" in one command',
  handler: {
    async execute(ctx, input) {
      const flags = input.flags ?? input;
      const taskId = flags["task-id"] ?? flags.taskId;
      try {
        const loaded = await loadTrace(taskId);
        if (!loaded.ok) {
          ctx.ui.write(JSON.stringify(mkError("INVALID_TASK_ID", formatTraceLoadError(loaded.error)), null, 2) + "\n");
          return { exitCode: 1 };
        }
        const events = loaded.events;
        const report = analyzeDiagnostics(taskId ?? "", events);
        if (flags.json) {
          ctx.ui.write(JSON.stringify({ success: true, report }, null, 2) + "\n");
        } else {
          printReport(ctx, report);
        }
        return { exitCode: report.issues.some((i) => i.severity === "critical") ? 1 : 0 };
      } catch {
        ctx.ui.write(JSON.stringify(mkError("TRACE_NOT_FOUND", `Trace not found: ${taskId}`), null, 2) + "\n");
        return { exitCode: 1 };
      }
    }
  }
});
function analyzeDiagnostics(taskId, events) {
  const normalized = normalizeTraceEvents(events);
  const issues = [];
  const taskStart = events[0];
  const agentEnd = [...events].reverse().find((e) => e.type === "agent:end");
  const iterationStarts = normalized.filter((e) => e.type === "iteration:start");
  const iterations = iterationStarts.length || Math.max(0, ...normalized.map((e) => e.iteration));
  const llmEndTokens = normalized.filter((e) => e.type === "llm:end").reduce((sum, e) => sum + (Number(e.data.tokensUsed) || 0), 0);
  const totalTokens = Number(agentEnd?.data?.tokensUsed) || llmEndTokens;
  const durationMs = Number(agentEnd?.data?.durationMs) || (taskStart && events[events.length - 1] ? new Date(events[events.length - 1].timestamp).getTime() - new Date(taskStart.timestamp).getTime() : 0);
  const success = Boolean(agentEnd?.data?.success ?? true);
  let confidence = 0;
  const toolResults = normalized.filter(
    (e) => e.type === "tool:end" || e.type === "tool_result" || e.type === "tool:execution"
  );
  for (const tr of toolResults) {
    const data = tr.data || tr.raw.output || tr.raw;
    const output = typeof data?.output === "string" ? data.output : JSON.stringify(data?.result || "");
    if (output.includes('"confidence"')) {
      try {
        const match = output.match(/"confidence"\s*:\s*([\d.]+)/);
        if (match?.[1]) {
          confidence = parseFloat(match[1]);
        }
      } catch {
      }
    }
  }
  const contextSnapshots = events.filter((e) => e.type === "context:snapshot");
  const contextDiffs = events.filter((e) => e.type === "context:diff");
  const contextTrims = events.filter((e) => e.type === "context:trim");
  let maxContextChars = 0;
  let totalDroppedMessages = 0;
  let truncatedToolOutputs = 0;
  const contextGrowthHistory = [];
  for (const snap of contextSnapshots) {
    const data = snap.data || snap;
    const chars = data.totalChars || 0;
    const dropped = data.slidingWindow?.droppedMessages || 0;
    if (chars > maxContextChars) {
      maxContextChars = chars;
    }
    totalDroppedMessages += dropped;
    contextGrowthHistory.push({
      iteration: data.iteration || 0,
      messageCount: data.messageCount || 0,
      totalChars: chars,
      droppedMessages: dropped
    });
  }
  truncatedToolOutputs = contextTrims.length;
  const tokenGrowth = [];
  let cumulative = 0;
  for (const e of normalized.filter((e2) => e2.type === "llm:end")) {
    cumulative += Number(e.data.tokensUsed) || 0;
    tokenGrowth.push({ iteration: e.iteration, cumulativeTokens: cumulative });
  }
  const systemPromptChanges = [];
  for (const cd of contextDiffs) {
    const diff = (cd.data || cd).diff;
    if (diff?.systemPromptChanged) {
      systemPromptChanges.push({
        iteration: (cd.data || cd).iteration || 0,
        charsDelta: diff.systemPromptCharsDelta || 0
      });
      issues.push({
        severity: "warning",
        category: "context",
        message: `System prompt changed at iteration ${(cd.data || cd).iteration} (${diff.systemPromptCharsDelta > 0 ? "+" : ""}${diff.systemPromptCharsDelta} chars)`
      });
    }
  }
  if (totalDroppedMessages > 0) {
    issues.push({
      severity: "warning",
      category: "context",
      message: `${totalDroppedMessages} messages dropped by sliding window \u2014 agent lost earlier context`,
      details: contextDiffs.filter((d) => (d.data || d).diff?.droppedMessages > 0).map((d) => `Iteration ${(d.data || d).iteration}: ${(d.data || d).diff?.droppedMessages} dropped`).join(", ")
    });
  }
  if (truncatedToolOutputs > 0) {
    issues.push({
      severity: "info",
      category: "context",
      message: `${truncatedToolOutputs} tool outputs were truncated (>8KB) before sending to LLM`
    });
  }
  const toolStarts = normalized.filter((e) => e.type === "tool:start" || e.type === "tool_call");
  const toolEnds = normalized.filter((e) => e.type === "tool:end" || e.type === "tool:execution" || e.type === "tool_result");
  const toolErrors = normalized.filter(
    (e) => e.type === "tool:error" || e.type === "tool:end" && e.data?.success === false || e.type === "tool:execution" && e.raw.output?.success === false || e.type === "tool_result" && e.data?.success === false
  );
  const toolBreakdown = {};
  const slowCalls = [];
  const SLOW_THRESHOLD_MS = 5e3;
  for (const te of toolEnds) {
    const data = te.data || te.raw;
    const name = data.toolName || data.tool?.name || "unknown";
    const dur = Number(data.durationMs) || Number(data.timing?.durationMs) || 0;
    const success2 = data.success ?? data.output?.success ?? true;
    if (!toolBreakdown[name]) {
      toolBreakdown[name] = { calls: 0, failures: 0, totalDurationMs: 0 };
    }
    toolBreakdown[name].calls++;
    toolBreakdown[name].totalDurationMs += dur;
    if (!success2) {
      toolBreakdown[name].failures++;
    }
    if (dur > SLOW_THRESHOLD_MS) {
      const args = data.input ? JSON.stringify(data.input).slice(0, 100) : "";
      slowCalls.push({
        tool: name,
        durationMs: dur,
        iteration: te.iteration || Number(data.iteration) || 0,
        args
      });
    }
  }
  const toolBreakdownFinal = {};
  for (const [name, stats] of Object.entries(toolBreakdown)) {
    toolBreakdownFinal[name] = {
      calls: stats.calls,
      failures: stats.failures,
      avgDurationMs: stats.calls > 0 ? Math.round(stats.totalDurationMs / stats.calls) : 0
    };
  }
  for (const err of toolErrors) {
    const data = err.data || err.raw;
    const name = data.toolName || data.tool?.name || "unknown";
    const errMsg = data.error || data.output?.error?.message || "";
    issues.push({
      severity: "warning",
      category: "tool",
      message: `Tool "${name}" failed: ${typeof errMsg === "string" ? errMsg.slice(0, 200) : JSON.stringify(errMsg).slice(0, 200)}`,
      iteration: Number(data.iteration) || err.iteration
    });
  }
  const llmResponses = normalized.filter((e) => e.type === "llm:end" || e.type === "llm_response");
  const llmCalls = normalized.filter((e) => e.type === "llm:start" || e.type === "llm:call" || e.type === "llm_call");
  let emptyResponses = 0;
  const reasoningTexts = [];
  for (const lr of llmResponses) {
    const data = lr.data || lr.raw;
    const content = data.content || "";
    const hasToolCalls = data.hasToolCalls || false;
    if (!content && !hasToolCalls) {
      emptyResponses++;
      issues.push({
        severity: "warning",
        category: "llm",
        message: "LLM returned empty response (no text, no tool calls)",
        iteration: lr.iteration || Number(data.iteration) || 0
      });
    }
    if (content && content.length > 5 && content !== "[Executing tools...]") {
      reasoningTexts.push({
        iteration: lr.iteration || Number(data.iteration) || 0,
        preview: content.slice(0, 300)
      });
    }
  }
  const stoppingAnalyses = events.filter((e) => e.type === "stopping:analysis");
  const stoppingReasons = stoppingAnalyses.map((e) => (e.data || e).reasoning || "").filter(Boolean);
  const errors = normalized.filter((e) => e.type === "error:captured" || e.type === "agent:error");
  for (const err of errors) {
    const data = err.data || err.raw;
    const msg = data.error?.message || data.error || "";
    issues.push({
      severity: "critical",
      category: "error",
      message: typeof msg === "string" ? msg.slice(0, 300) : JSON.stringify(msg).slice(0, 300),
      iteration: Number(data.iteration) || err.iteration,
      details: data.error?.stack || data.agentStack ? JSON.stringify(data.agentStack || {}).slice(0, 200) : void 0
    });
  }
  let loopDetected = false;
  const repeatedPatterns = [];
  const toolCallSequence = toolStarts.map((e) => {
    const data = e.data || e.raw;
    return data.toolName || data.tool?.name || "unknown";
  });
  if (toolCallSequence.length >= 6) {
    for (let windowSize = 2; windowSize <= 3; windowSize++) {
      const lastN = toolCallSequence.slice(-windowSize * 2);
      const first = lastN.slice(0, windowSize).join(",");
      const second = lastN.slice(windowSize).join(",");
      if (first === second) {
        loopDetected = true;
        repeatedPatterns.push(first);
        issues.push({
          severity: "warning",
          category: "loop",
          message: `Repeated tool pattern detected: ${first} (called ${windowSize} times in a row)`
        });
      }
    }
  }
  if (!success) {
    issues.push({
      severity: "critical",
      category: "quality",
      message: "Task failed \u2014 agent did not produce a successful result"
    });
  }
  if (confidence > 0 && confidence < 0.5) {
    issues.push({
      severity: "warning",
      category: "quality",
      message: `Low confidence: ${confidence} \u2014 agent was not confident in its answer`
    });
  }
  if (iterations >= 20) {
    issues.push({
      severity: "warning",
      category: "quality",
      message: `Used ${iterations} iterations \u2014 may indicate difficulty finding answer`
    });
  }
  const severityOrder = { critical: 0, warning: 1, info: 2 };
  issues.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);
  return {
    taskId,
    summary: {
      totalEvents: events.length,
      iterations,
      totalTokens,
      durationMs,
      success,
      confidence
    },
    issues,
    contextHealth: {
      maxContextChars,
      maxContextTokens: Math.round(maxContextChars / 4),
      totalDroppedMessages,
      truncatedToolOutputs,
      contextGrowthHistory,
      tokenGrowth,
      systemPromptChanges
    },
    toolUsage: {
      totalCalls: Object.values(toolBreakdownFinal).reduce((sum, t) => sum + t.calls, 0),
      failures: Object.values(toolBreakdownFinal).reduce((sum, t) => sum + t.failures, 0),
      toolBreakdown: toolBreakdownFinal,
      slowCalls: slowCalls.sort((a, b) => b.durationMs - a.durationMs)
    },
    llmBehavior: {
      totalCalls: llmCalls.length,
      emptyResponses,
      reasoningTexts,
      stoppingReasons
    },
    loopDetection: {
      detected: loopDetected,
      repeatedPatterns
    }
  };
}
function printReport(ctx, report) {
  const { summary, issues, contextHealth, toolUsage, llmBehavior, loopDetection } = report;
  ctx.ui.write("\n");
  ctx.ui.write("=".repeat(60) + "\n");
  ctx.ui.write(`  DIAGNOSTIC REPORT: ${report.taskId}
`);
  ctx.ui.write("=".repeat(60) + "\n");
  const status = summary.success ? "  OK" : "  FAILED";
  ctx.ui.write(`
${status}
`);
  ctx.ui.write(`  Iterations: ${summary.iterations} | Tokens: ${summary.totalTokens} | Time: ${(summary.durationMs / 1e3).toFixed(1)}s`);
  if (summary.confidence > 0) {
    ctx.ui.write(` | Confidence: ${summary.confidence}`);
  }
  ctx.ui.write("\n");
  if (issues.length > 0) {
    ctx.ui.write("\n--- Issues (" + issues.length + ") ---\n");
    for (const issue of issues) {
      const icon = issue.severity === "critical" ? "X" : issue.severity === "warning" ? "!" : "i";
      const iter = issue.iteration ? ` [iter ${issue.iteration}]` : "";
      ctx.ui.write(`  [${icon}] ${issue.category}: ${issue.message}${iter}
`);
      if (issue.details) {
        ctx.ui.write(`      ${issue.details.slice(0, 150)}
`);
      }
    }
  } else {
    ctx.ui.write("\n  No issues detected.\n");
  }
  ctx.ui.write("\n--- Context Window ---\n");
  ctx.ui.write(`  Max context: ~${contextHealth.maxContextTokens} tokens (${contextHealth.maxContextChars} chars)
`);
  ctx.ui.write(`  Dropped messages: ${contextHealth.totalDroppedMessages}
`);
  ctx.ui.write(`  Truncated outputs: ${contextHealth.truncatedToolOutputs}
`);
  if (contextHealth.contextGrowthHistory.length > 0) {
    ctx.ui.write("  Growth: ");
    ctx.ui.write(contextHealth.contextGrowthHistory.map((g) => `iter${g.iteration}=${g.messageCount}msg/${Math.round(g.totalChars / 1e3)}K` + (g.droppedMessages > 0 ? `(-${g.droppedMessages})` : "")).join(" -> "));
    ctx.ui.write("\n");
  }
  if (contextHealth.tokenGrowth.length > 0) {
    ctx.ui.write("  Tokens: ");
    ctx.ui.write(contextHealth.tokenGrowth.map((t) => `iter${t.iteration}=${t.cumulativeTokens}`).join(" -> "));
    ctx.ui.write("\n");
  }
  if (contextHealth.systemPromptChanges.length > 0) {
    ctx.ui.write("  System prompt changes:\n");
    for (const sp of contextHealth.systemPromptChanges) {
      ctx.ui.write(`    iter${sp.iteration}: ${sp.charsDelta > 0 ? "+" : ""}${sp.charsDelta} chars
`);
    }
  }
  ctx.ui.write("\n--- Tools ---\n");
  ctx.ui.write(`  Total calls: ${toolUsage.totalCalls} | Failures: ${toolUsage.failures}
`);
  const entries = Object.entries(toolUsage.toolBreakdown).sort((a, b) => b[1].calls - a[1].calls);
  for (const [name, stats] of entries) {
    const fail = stats.failures > 0 ? ` (${stats.failures} failed)` : "";
    ctx.ui.write(`    ${name}: ${stats.calls}x avg ${stats.avgDurationMs}ms${fail}
`);
  }
  if (toolUsage.slowCalls.length > 0) {
    ctx.ui.write("  Slow calls (>5s):\n");
    for (const sc of toolUsage.slowCalls) {
      const durStr = sc.durationMs >= 6e4 ? `${(sc.durationMs / 6e4).toFixed(1)}min` : `${(sc.durationMs / 1e3).toFixed(1)}s`;
      ctx.ui.write(`    [iter ${sc.iteration}] ${sc.tool} ${durStr}${sc.args ? ` args=${sc.args}` : ""}
`);
    }
  }
  ctx.ui.write("\n--- LLM ---\n");
  ctx.ui.write(`  Calls: ${llmBehavior.totalCalls} | Empty responses: ${llmBehavior.emptyResponses}
`);
  if (llmBehavior.reasoningTexts.length > 0) {
    ctx.ui.write("  Reasoning:\n");
    for (const rt of llmBehavior.reasoningTexts.slice(0, 5)) {
      const preview = rt.preview.replace(/\n/g, " ").slice(0, 120);
      ctx.ui.write(`    [iter ${rt.iteration}] "${preview}"
`);
    }
  }
  if (llmBehavior.stoppingReasons.length > 0) {
    ctx.ui.write("  Stop reasons: " + [...new Set(llmBehavior.stoppingReasons)].join(", ") + "\n");
  }
  if (loopDetection.detected) {
    ctx.ui.write("\n--- Loop Detection ---\n");
    ctx.ui.write(`  LOOP DETECTED: ${loopDetection.repeatedPatterns.join("; ")}
`);
  }
  ctx.ui.write("\n" + "=".repeat(60) + "\n\n");
}
function mkError(code, message) {
  return {
    success: false,
    command: "trace:diagnose",
    taskId: "",
    error: { code, message },
    summary: { message, severity: "error", actionable: true }
  };
}

export { trace_diagnose_default as default };
//# sourceMappingURL=trace-diagnose.js.map
//# sourceMappingURL=trace-diagnose.js.map