import {
  estimateCost,
  isModelPriced
} from "./chunk-VI2UW6B6.js";
import {
  extractUsage
} from "./chunk-PXE2VKMX.js";

// src/contract/intake/code-agent-observation.ts
function observeCodeAgentSession(options) {
  const entries = options.entries.filter(isRecord);
  const projection = projectionFor(options.source, entries);
  const terminal = terminalWithExecution(projection, options.execution);
  return {
    source: options.source,
    sessionId: sessionIdFromEntries(options.source, entries) ?? fallbackSessionId(options.source, options.sourcePath),
    finalText: projection.finalText,
    terminal,
    actions: projection.actions
  };
}
function projectionFor(source, entries) {
  switch (source) {
    case "codex":
      return codexProjection(entries);
    case "claude-code":
      return claudeProjection(entries);
    case "opencode":
      return openCodeProjection(entries);
    case "kimi-code":
      return kimiProjection(entries);
    case "pi":
      return piProjection(entries);
  }
}
function codexProjection(entries) {
  const actions = [];
  const calls = /* @__PURE__ */ new Map();
  let finalText = null;
  let terminal = "unknown";
  let explicitTerminal = false;
  for (const entry of entries) {
    const entryType = stringField(entry, "type");
    const payload = record(entry.payload) ?? {};
    const payloadType = stringField(payload, "type");
    const timestampMs2 = timestamp(entry.timestamp);
    const item = record(entry.item);
    if (entryType === "item.started" && item) {
      const itemType = stringField(item, "type");
      if (isCodexActionItem(itemType)) {
        const id = stringField(item, "id") ?? `item-${actions.length}`;
        const action = actionFor({
          id,
          stepIndex: actions.length,
          kind: itemType === "file_change" ? "patch" : "tool",
          surface: codexItemSurface(itemType, item),
          name: codexItemName(itemType, item),
          status: "started",
          timestampMs: timestampMs2,
          metadata: compactMetadata({ sourceEventType: entryType, itemType })
        });
        calls.set(id, action);
        actions.push(action);
      }
    }
    if (entryType === "item.completed" && item) {
      const itemType = stringField(item, "type");
      if (itemType === "agent_message" || itemType === "message") {
        finalText = nonEmpty(stringField(item, "text")) ?? finalText;
      }
      if (isCodexActionItem(itemType)) {
        const id = stringField(item, "id") ?? `item-${actions.length}`;
        const status = codexItemStatus(itemType, item);
        const existing = calls.get(id);
        if (existing) {
          existing.status = status;
        } else {
          const action = actionFor({
            id,
            stepIndex: actions.length,
            kind: itemType === "file_change" ? "patch" : "tool",
            surface: codexItemSurface(itemType, item),
            name: codexItemName(itemType, item),
            status,
            timestampMs: timestampMs2,
            metadata: compactMetadata({ sourceEventType: entryType, itemType })
          });
          calls.set(id, action);
          actions.push(action);
        }
      }
    }
    if (entryType === "response_item") {
      if (payloadType === "message" || payloadType === "agent_message") {
        finalText = textFromMessagePayload(payload) ?? finalText;
      }
      if (payloadType === "function_call" || payloadType === "custom_tool_call") {
        const id = stringField(payload, "call_id") ?? stringField(payload, "id") ?? `call-${actions.length}`;
        const name = stringField(payload, "name") ?? payloadType;
        const action = actionFor({
          id,
          stepIndex: actions.length,
          kind: "tool",
          surface: surfaceForTool(name),
          name,
          status: "started",
          timestampMs: timestampMs2,
          metadata: compactMetadata({ sourceEventType: entryType, payloadType })
        });
        calls.set(id, action);
        actions.push(action);
      }
      if (payloadType === "function_call_output" || payloadType === "custom_tool_call_output") {
        const id = stringField(payload, "call_id") ?? stringField(payload, "id");
        const existing = id ? calls.get(id) : void 0;
        if (existing) existing.status = looksLikeError(payload.output) ? "failed" : "completed";
      }
    }
    if (entryType === "event_msg") {
      if (payloadType === "agent_message") {
        finalText = nonEmpty(stringField(payload, "message")) ?? nonEmpty(stringField(payload, "text")) ?? finalText;
      }
      if (payloadType === "patch_apply_end") {
        const patchStatus = typeof payload.success === "boolean" ? payload.success ? "completed" : "failed" : "unknown";
        actions.push(
          actionFor({
            id: stringField(payload, "call_id") ?? `patch-${actions.length}`,
            stepIndex: actions.length,
            kind: "patch",
            surface: "code",
            name: "patch",
            status: patchStatus,
            timestampMs: timestampMs2,
            metadata: compactMetadata({ sourceEventType: entryType, payloadType })
          })
        );
      }
      if (payloadType === "sub_agent_activity") {
        const name = stringField(payload, "kind") ?? "subagent";
        actions.push(
          actionFor({
            id: stringField(payload, "event_id") ?? `subagent-${actions.length}`,
            stepIndex: actions.length,
            kind: "tool",
            surface: "subagent",
            name,
            status: statusFrom(payload),
            timestampMs: timestampMs2,
            metadata: compactMetadata({ sourceEventType: entryType, payloadType })
          })
        );
      }
      if (payloadType === "task_complete" || payloadType === "turn_aborted") {
        const completed = payloadType === "task_complete";
        terminal = completed ? "completed" : "failed";
        explicitTerminal = true;
        actions.push(terminalAction(actions.length, payloadType, completed, timestampMs2));
      }
    }
    if (entryType === "turn.completed" || entryType === "exec_done") {
      const completed = entry.success !== false;
      terminal = completed ? "completed" : "failed";
      explicitTerminal = true;
      finalText = nonEmpty(stringField(entry, "message")) ?? finalText;
      actions.push(terminalAction(actions.length, entryType, completed, timestampMs2));
    }
    if (entryType === "turn.failed" || entryType === "error") {
      terminal = "failed";
      explicitTerminal = true;
      actions.push(terminalAction(actions.length, entryType, false, timestampMs2));
    }
  }
  return { finalText, terminal, explicitTerminal, actions };
}
function claudeProjection(entries) {
  const actions = [];
  const calls = /* @__PURE__ */ new Map();
  let finalText = null;
  let resultText = null;
  let terminal = "unknown";
  let explicitTerminal = false;
  for (const entry of entries) {
    const entryType = stringField(entry, "type");
    const timestampMs2 = timestamp(entry.timestamp);
    const message = record(entry.message);
    const content = Array.isArray(message?.content) ? message.content : [];
    if (entryType === "assistant") {
      const text = textBlocks(content);
      if (text !== null) finalText = text;
      for (const value of content) {
        const part = record(value);
        if (!part) continue;
        const partType = stringField(part, "type");
        if (partType === "tool_use") {
          const id = stringField(part, "id") ?? `tool-${actions.length}`;
          const name = stringField(part, "name") ?? "tool";
          const action = actionFor({
            id,
            stepIndex: actions.length,
            kind: "tool",
            surface: surfaceForTool(name),
            name,
            status: "started",
            timestampMs: timestampMs2,
            metadata: compactMetadata({ sourceEventType: entryType, partType })
          });
          calls.set(id, action);
          actions.push(action);
        }
      }
      completeClaudeTools(content, calls);
      const stopReason = stringField(message ?? {}, "stop_reason");
      if (stopReason === "end_turn") {
        terminal = "completed";
        explicitTerminal = true;
        actions.push(terminalAction(actions.length, stopReason, true, timestampMs2));
      }
    }
    if (entryType === "user") {
      completeClaudeTools(content, calls);
    }
    if (entryType === "tool_use") {
      const id = stringField(entry, "id") ?? `tool-${actions.length}`;
      const name = stringField(entry, "name") ?? "tool";
      const action = actionFor({
        id,
        stepIndex: actions.length,
        kind: "tool",
        surface: surfaceForTool(name),
        name,
        status: "started",
        timestampMs: timestampMs2,
        metadata: { sourceEventType: entryType }
      });
      calls.set(id, action);
      actions.push(action);
    }
    if (entryType === "tool_result") {
      const id = stringField(entry, "tool_use_id");
      const action = id ? calls.get(id) : void 0;
      if (action) action.status = entry.is_error === true ? "failed" : "completed";
    }
    if (entryType === "system") {
      const subtype = stringField(entry, "subtype");
      const hookName = stringField(entry, "hook_name") ?? stringField(entry, "hookName");
      if (subtype?.toLowerCase().includes("hook") || hookName) {
        actions.push(
          actionFor({
            id: stringField(entry, "uuid") ?? `hook-${actions.length}`,
            stepIndex: actions.length,
            kind: "tool",
            surface: "hook",
            name: hookName ?? subtype ?? "hook",
            status: statusFrom(entry),
            timestampMs: timestampMs2,
            metadata: compactMetadata({ sourceEventType: entryType, subtype })
          })
        );
      }
    }
    if (entryType === "pr-link") {
      actions.push(terminalAction(actions.length, entryType, true, timestampMs2));
    }
    if (entryType === "result") {
      resultText = nonEmpty(stringField(entry, "result")) ?? resultText;
      const subtype = stringField(entry, "subtype");
      const completed = entry.is_error !== true && !subtype?.toLowerCase().includes("error");
      terminal = completed ? "completed" : "failed";
      explicitTerminal = true;
      actions.push(terminalAction(actions.length, subtype ?? entryType, completed, timestampMs2));
    }
    if (entryType === "error") {
      terminal = "failed";
      explicitTerminal = true;
      actions.push(terminalAction(actions.length, entryType, false, timestampMs2));
    }
  }
  return {
    finalText: resultText ?? finalText,
    terminal,
    explicitTerminal,
    actions
  };
}
function openCodeProjection(entries) {
  const actions = [];
  const assistantMessageIds = new Set(
    entries.filter((entry) => stringField(entry, "role") === "assistant").map((entry) => stringField(entry, "id")).filter((id) => id !== void 0)
  );
  let finalText = null;
  let terminal = "unknown";
  let explicitTerminal = false;
  for (const entry of entries) {
    const entryType = stringField(entry, "type");
    const part = record(entry.part) ?? entry;
    const partType = stringField(part, "type");
    const timestampMs2 = timestamp(entry.timestamp) ?? timestamp(record(entry.time)?.created);
    if (entryType === "text" && record(entry.part)) {
      finalText = nonEmpty(stringField(part, "text")) ?? finalText;
    } else if (partType === "text" && (assistantMessageIds.size === 0 || assistantMessageIds.has(stringField(part, "messageID") ?? ""))) {
      finalText = nonEmpty(stringField(part, "text")) ?? finalText;
    }
    if (entryType === "tool_use" || partType === "tool") {
      const state = record(part.state) ?? {};
      const name = stringField(part, "tool") ?? "tool";
      actions.push(
        actionFor({
          id: stringField(part, "callID") ?? stringField(part, "id") ?? `tool-${actions.length}`,
          stepIndex: actions.length,
          kind: "tool",
          surface: surfaceForTool(name),
          name,
          status: statusFrom(state),
          timestampMs: timestampMs2,
          metadata: compactMetadata({ sourceEventType: entryType, partType })
        })
      );
    }
    if (partType === "patch") {
      actions.push(
        actionFor({
          id: stringField(part, "id") ?? `patch-${actions.length}`,
          stepIndex: actions.length,
          kind: "patch",
          surface: "code",
          name: "patch",
          status: "completed",
          timestampMs: timestampMs2,
          metadata: compactMetadata({ sourceEventType: entryType, partType })
        })
      );
    }
    if (stringField(entry, "role") === "assistant") {
      const finish = stringField(entry, "finish");
      if (finish === "stop" || finish === "error") {
        const completed = finish === "stop";
        terminal = completed ? "completed" : "failed";
        explicitTerminal = true;
        actions.push(terminalAction(actions.length, finish, completed, timestampMs2));
      }
    }
    if (entryType === "error") {
      terminal = "failed";
      explicitTerminal = true;
      actions.push(terminalAction(actions.length, entryType, false, timestampMs2));
    }
  }
  return { finalText, terminal, explicitTerminal, actions };
}
function kimiProjection(entries) {
  const actions = [];
  const calls = /* @__PURE__ */ new Map();
  let finalText = null;
  let terminal = "unknown";
  let explicitTerminal = false;
  for (const entry of entries) {
    const timestampMs2 = timestamp(entry.timestamp);
    const message = record(entry.message);
    const messageType = stringField(message ?? {}, "type");
    const payload = record(message?.payload) ?? {};
    if (messageType === "ContentPart" && stringField(payload, "type") === "text") {
      finalText = nonEmpty(stringField(payload, "text")) ?? nonEmpty(stringField(payload, "content")) ?? finalText;
    }
    if (messageType === "ToolCall") {
      const fn = record(payload.function) ?? {};
      const id = stringField(payload, "id") ?? `tool-${actions.length}`;
      const name = stringField(fn, "name") ?? "tool";
      const action = actionFor({
        id,
        stepIndex: actions.length,
        kind: "tool",
        surface: surfaceForTool(name),
        name,
        status: "started",
        timestampMs: timestampMs2,
        metadata: { sourceEventType: messageType }
      });
      calls.set(id, action);
      actions.push(action);
    }
    if (messageType === "ToolResult") {
      const id = stringField(payload, "tool_call_id");
      const action = id ? calls.get(id) : void 0;
      if (action)
        action.status = record(payload.return_value)?.is_error === true ? "failed" : "completed";
    }
    if (messageType === "TurnEnd" || messageType === "StepInterrupted") {
      const completed = messageType === "TurnEnd";
      terminal = completed ? "completed" : "failed";
      explicitTerminal = true;
      actions.push(terminalAction(actions.length, messageType, completed, timestampMs2));
    }
  }
  return { finalText, terminal, explicitTerminal, actions };
}
function piProjection(entries) {
  const actions = [];
  let terminal = "unknown";
  let explicitTerminal = false;
  for (const entry of entries) {
    const nodes = Array.isArray(entry.nodes) ? entry.nodes : [];
    for (const value of nodes) {
      const node = record(value);
      const ir = record(node?.ir) ?? node;
      const kind = stringField(ir ?? {}, "kind");
      if (kind === "ToolInvocation") {
        actions.push(
          actionFor({
            id: stringField(ir ?? {}, "id") ?? stringField(node ?? {}, "id") ?? `tool-${actions.length}`,
            stepIndex: actions.length,
            kind: "tool",
            surface: "tool",
            name: stringField(ir ?? {}, "name") ?? "graph-tool",
            status: "started",
            timestampMs: timestamp(ir?.createdAt),
            metadata: { sourceEventType: "graph-node", graphKind: kind }
          })
        );
      }
      if (kind === "ToolResult") {
        const prior = [...actions].reverse().find((action) => action.kind === "tool");
        if (prior) prior.status = "completed";
      }
      if (kind === "CompletionDecision") {
        terminal = "completed";
        explicitTerminal = true;
        actions.push(
          actionFor({
            id: stringField(ir ?? {}, "id") ?? stringField(node ?? {}, "id") ?? `completion-${actions.length}`,
            stepIndex: actions.length,
            kind: "graph-completion",
            surface: "tool",
            name: "complete",
            status: "completed",
            timestampMs: timestamp(ir?.createdAt),
            metadata: { sourceEventType: "graph-node", graphKind: kind }
          })
        );
      }
    }
  }
  return { finalText: null, terminal, explicitTerminal, actions };
}
function completeClaudeTools(content, calls) {
  for (const value of content) {
    const part = record(value);
    if (!part || stringField(part, "type") !== "tool_result") continue;
    const id = stringField(part, "tool_use_id");
    const action = id ? calls.get(id) : void 0;
    if (action) action.status = part.is_error === true ? "failed" : "completed";
  }
}
function isCodexActionItem(itemType) {
  return itemType === "command_execution" || itemType === "mcp_tool_call" || itemType === "collab_tool_call" || itemType === "web_search" || itemType === "file_change";
}
function codexItemSurface(itemType, item) {
  if (itemType === "mcp_tool_call") return "mcp";
  if (itemType === "collab_tool_call") return "subagent";
  if (itemType === "web_search") return "web";
  if (itemType === "file_change") return "code";
  return surfaceForTool(stringField(item, "name") ?? itemType ?? "tool");
}
function codexItemName(itemType, item) {
  if (itemType === "mcp_tool_call") {
    const server = stringField(item, "server");
    const tool = stringField(item, "tool");
    return [server, tool].filter(Boolean).join("/") || "mcp";
  }
  if (itemType === "collab_tool_call") return stringField(item, "tool") ?? "subagent";
  if (itemType === "web_search") return "web_search";
  if (itemType === "file_change") return "file_change";
  return stringField(item, "name") ?? itemType ?? "tool";
}
function codexItemStatus(itemType, item) {
  const status = statusFrom(item);
  if (status === "failed") return status;
  if (itemType === "command_execution") {
    const exitCode = numberField(item, "exit_code");
    if (exitCode !== void 0) return exitCode === 0 ? "completed" : "failed";
  }
  if (itemType === "mcp_tool_call" && record(item.error)) return "failed";
  return status === "unknown" || status === "started" ? "completed" : status;
}
function textFromMessagePayload(payload) {
  const direct = nonEmpty(stringField(payload, "text"));
  if (direct) return direct;
  const content = payload.content;
  if (typeof content === "string") return nonEmpty(content);
  if (Array.isArray(content)) return textBlocks(content);
  return null;
}
function textBlocks(values) {
  const text = values.map((value) => record(value)).filter((value) => value !== null).filter((value) => stringField(value, "type") === "text").map((value) => stringField(value, "text")).filter((value) => value !== void 0).join("\n");
  return nonEmpty(text);
}
function terminalWithExecution(projection, execution) {
  if (!execution) {
    return { status: projection.terminal, explicit: projection.explicitTerminal };
  }
  assertExecutionReceipt(execution);
  return {
    status: execution.exitCode !== 0 || projection.terminal === "failed" ? "failed" : "completed",
    explicit: true
  };
}
function assertExecutionReceipt(receipt) {
  if (!Number.isSafeInteger(receipt.exitCode)) {
    throw new Error("code-agent execution exitCode must be a safe integer");
  }
  for (const [name, value] of [
    ["startedAtMs", receipt.startedAtMs],
    ["completedAtMs", receipt.completedAtMs]
  ]) {
    if (value !== void 0 && (!Number.isFinite(value) || value < 0)) {
      throw new Error(`code-agent execution ${name} must be a non-negative finite number`);
    }
  }
  if (receipt.startedAtMs !== void 0 && receipt.completedAtMs !== void 0 && receipt.completedAtMs < receipt.startedAtMs) {
    throw new Error("code-agent execution completedAtMs precedes startedAtMs");
  }
}
function terminalAction(stepIndex, name, completed, timestampMs2) {
  return actionFor({
    id: `terminal-${stepIndex}`,
    stepIndex,
    kind: "terminal",
    surface: "tool",
    name,
    status: completed ? "completed" : "failed",
    timestampMs: timestampMs2,
    metadata: { sourceEventType: name }
  });
}
function actionFor(input) {
  return input;
}
function surfaceForTool(name) {
  const normalized = name.toLowerCase();
  if (normalized.startsWith("mcp__") || normalized.includes("mcp_tool")) return "mcp";
  if (normalized === "task" || normalized === "agent" || normalized.includes("subagent") || normalized.includes("spawn_agent") || normalized.includes("collab") || normalized.startsWith("multi_agent")) {
    return "subagent";
  }
  if (normalized === "skill" || normalized.includes("skill")) return "skill";
  if (normalized.includes("hook")) return "hook";
  if (normalized.includes("web_search") || normalized.includes("webfetch") || normalized === "web") {
    return "web";
  }
  if (normalized === "edit" || normalized === "write" || normalized.includes("patch") || normalized.includes("file_change")) {
    return "code";
  }
  return "tool";
}
function statusFrom(value) {
  const status = (stringField(value, "status") ?? "").toLowerCase();
  if (status === "completed" || status === "success" || status === "succeeded") return "completed";
  if (status === "error" || status === "failed" || status === "declined") return "failed";
  if (status === "running" || status === "started" || status === "in_progress") return "started";
  return "unknown";
}
function compactMetadata(input) {
  return Object.fromEntries(Object.entries(input).filter((entry) => entry[1] !== void 0));
}
function sessionIdFromEntries(source, entries) {
  for (const entry of entries) {
    if (source === "codex") {
      const threadId = stringField(entry, "thread_id");
      if (threadId) return threadId;
      const payload2 = record(entry.payload);
      const id = payload2 ? stringField(payload2, "id") : void 0;
      if (id) return id;
    }
    const message = record(entry.message);
    const payload = record(message?.payload);
    const sessionId = stringField(entry, "sessionID") ?? stringField(entry, "sessionId") ?? stringField(entry, "session_id") ?? stringField(payload ?? {}, "session_id");
    if (sessionId) return sessionId;
  }
  return void 0;
}
function fallbackSessionId(source, sourcePath) {
  return `${source}:${sourcePath ?? "unknown-session"}`;
}
function looksLikeError(value) {
  if (isRecord(value)) {
    if (value.success === false || value.is_error === true) return true;
    const exitCode = numberField(value, "exit_code");
    if (exitCode !== void 0 && exitCode !== 0) return true;
  }
  const text = typeof value === "string" ? value : JSON.stringify(value ?? "");
  return /\b(?:error|failed|failure)\b|exit(?:_| )code["\s:]+[1-9]/i.test(text);
}
function nonEmpty(value) {
  return value !== void 0 && value.length > 0 ? value : null;
}
function isRecord(value) {
  return value !== null && typeof value === "object" && !Array.isArray(value);
}
function record(value) {
  return isRecord(value) ? value : null;
}
function stringField(value, key) {
  const field = value[key];
  return typeof field === "string" && field.length > 0 ? field : void 0;
}
function numberField(value, key) {
  const field = value[key];
  return typeof field === "number" && Number.isFinite(field) ? field : void 0;
}
function timestamp(value) {
  if (typeof value === "number" && Number.isFinite(value)) {
    return value > 1e12 ? value : value * 1e3;
  }
  if (typeof value === "string" && value.length > 0) {
    const parsed = Date.parse(value);
    return Number.isFinite(parsed) ? parsed : void 0;
  }
  return void 0;
}

// src/contract/intake/code-agent-session.ts
import { createHash } from "crypto";
function parseCodeAgentJsonl(jsonl) {
  const entries = [];
  let malformedLines = 0;
  for (const line of jsonl.split("\n")) {
    const trimmed = line.trim();
    if (!trimmed) continue;
    try {
      entries.push(JSON.parse(trimmed));
    } catch {
      malformedLines += 1;
    }
  }
  return { entries, malformedLines };
}
function fromCodexSession(options) {
  return fromCodeAgentSession("codex", options);
}
function fromClaudeCodeSession(options) {
  return fromCodeAgentSession("claude-code", options);
}
function fromOpenCodeSession(options) {
  return fromCodeAgentSession("opencode", options);
}
function fromKimiCodeSession(options) {
  return fromCodeAgentSession("kimi-code", options);
}
function fromPiSession(options) {
  return fromCodeAgentSession("pi", options);
}
var fromPigraphSession = fromPiSession;
function fromCodeAgentSession(source, options) {
  const entries = options.entries.filter(isRecord2);
  if (entries.length === 0) {
    return {
      runs: [],
      diagnostics: [
        {
          source,
          sessionId: fallbackSessionId2(source, options.sourcePath),
          sourcePath: options.sourcePath,
          entries: 0,
          malformedLines: options.malformedLines ?? 0,
          inferredScore: true,
          hasExplicitTerminalSignal: false,
          hasFinalOutput: false,
          hasQualityLabel: false,
          hasTokenUsage: false,
          hasCost: false,
          costKind: "uncaptured",
          warnings: ["no parseable session entries"]
        }
      ],
      metrics: [],
      observations: []
    };
  }
  const metrics = metricsFor(source, entries);
  const sessionId = sessionIdFromEntries2(source, entries) ?? fallbackSessionId2(source, options.sourcePath);
  const observation = observeCodeAgentSession({
    source,
    entries,
    sourcePath: options.sourcePath,
    execution: options.execution
  });
  applyObservedSurfaceMetrics(metrics, observation);
  const model = withSnapshot(options.model ?? modelFromEntries(source, entries) ?? source);
  const tokenUsage = {
    input: metrics.inputTokens,
    output: metrics.outputTokens,
    ...metrics.reasoningTokens > 0 ? { reasoning: metrics.reasoningTokens } : {},
    ...metrics.cachedTokens > 0 ? { cached: metrics.cachedTokens } : {},
    ...metrics.cacheWriteTokens > 0 ? { cacheWrite: metrics.cacheWriteTokens } : {}
  };
  const { costUsd, costProvenance } = resolveSessionCost(options.costProvenance, metrics, model);
  const score = clamp01(options.score ?? metrics.processScore);
  const promptHash = options.promptHash ?? hashString(`prompt:${source}:${firstUserText(entries) ?? ""}`);
  const configHash = options.configHash ?? hashJson({
    source,
    model,
    sourcePath: options.sourcePath,
    cwd: cwdFromEntries(entries),
    entryCount: entries.length
  });
  const explicitTerminal = observation.terminal.explicit;
  const warnings = diagnosticsFor(metrics, {
    model,
    explicitTerminal,
    malformedLines: options.malformedLines ?? 0,
    scoreOverridden: options.score !== void 0,
    costKind: costProvenance.kind
  });
  const run = {
    runId: `${source}:${sessionId}`,
    experimentId: options.experimentId ?? `${source}-local-sessions`,
    candidateId: options.candidateId ?? model,
    seed: options.seed ?? stableSeed(sessionId),
    model,
    promptHash,
    configHash,
    commitSha: options.commitSha ?? "local-session",
    wallMs: metrics.wallMs,
    costUsd,
    costProvenance,
    tokenUsage,
    outcome: {
      holdoutScore: score,
      raw: {
        entries: metrics.entries,
        user_messages: metrics.userMessages,
        assistant_messages: metrics.assistantMessages,
        reasoning_items: metrics.reasoningItems,
        tool_calls: metrics.toolCalls,
        tool_outputs: metrics.toolOutputs,
        tool_errors: metrics.toolErrors,
        patch_attempts: metrics.patchAttempts,
        patch_successes: metrics.patchSuccesses,
        patch_failures: metrics.patchFailures,
        turns_started: metrics.turnsStarted,
        turns_completed: metrics.turnsCompleted,
        turns_aborted: metrics.turnsAborted,
        context_compactions: metrics.contextCompactions,
        mcp_calls: metrics.mcpCalls,
        subagent_calls: metrics.subagentCalls,
        skill_calls: metrics.skillCalls,
        hook_calls: metrics.hookCalls,
        web_calls: metrics.webCalls,
        code_actions: metrics.codeActions,
        pr_links: metrics.prLinks,
        file_snapshots: metrics.fileSnapshots,
        graph_nodes: metrics.graphNodes,
        graph_edges: metrics.graphEdges,
        action_candidates: metrics.actionCandidates,
        verification_reports: metrics.verificationReports,
        completion_decisions: metrics.completionDecisions,
        reliability_rows: metrics.reliabilityRows,
        reliability_lift: metrics.reliabilityLift,
        input_tokens: metrics.inputTokens,
        output_tokens: metrics.outputTokens,
        reasoning_tokens: metrics.reasoningTokens,
        cached_tokens: metrics.cachedTokens,
        cache_write_tokens: metrics.cacheWriteTokens,
        observed_cost_usd: metrics.observedCostUsd,
        observed_cost_captured: metrics.observedCostCaptured ? 1 : 0,
        estimated_cost_usd: costProvenance.kind === "estimated" ? costUsd : 0,
        process_score: score,
        inferred_score: options.score === void 0 ? 1 : 0,
        explicit_terminal_signal: explicitTerminal ? 1 : 0,
        quality_label_present: options.score !== void 0 ? 1 : 0,
        cost_observed: costProvenance.kind === "observed" ? 1 : 0,
        cost_estimated: costProvenance.kind === "estimated" ? 1 : 0,
        cost_uncaptured: costProvenance.kind === "uncaptured" ? 1 : 0,
        cost_unknown: costProvenance.kind === "uncaptured" ? 1 : 0
      }
    },
    splitTag: options.splitTag ?? "holdout",
    ...options.scenarioId ? { scenarioId: options.scenarioId } : {},
    ...metrics.toolErrors > 0 || metrics.turnsAborted > 0 ? { failureMode: metrics.turnsAborted > 0 ? "turn_aborted" : "tool_error" } : {}
  };
  return {
    runs: [run],
    diagnostics: [
      {
        source,
        sessionId,
        sourcePath: options.sourcePath,
        entries: entries.length,
        malformedLines: options.malformedLines ?? 0,
        inferredScore: options.score === void 0,
        hasExplicitTerminalSignal: explicitTerminal,
        hasFinalOutput: observation.finalText !== null,
        hasQualityLabel: options.score !== void 0,
        hasTokenUsage: metrics.inputTokens > 0 || metrics.outputTokens > 0 || metrics.reasoningTokens > 0 || metrics.cachedTokens > 0 || metrics.cacheWriteTokens > 0,
        hasCost: costProvenance.kind !== "uncaptured",
        costKind: costProvenance.kind,
        warnings
      }
    ],
    metrics: [metrics],
    observations: [{ ...observation, sessionId }]
  };
}
function metricsFor(source, entries) {
  switch (source) {
    case "codex":
      return codexMetrics(entries);
    case "claude-code":
      return claudeCodeMetrics(entries);
    case "opencode":
      return openCodeMetrics(entries);
    case "kimi-code":
      return kimiCodeMetrics(entries);
    case "pi":
      return piMetrics(entries);
  }
}
function codexMetrics(entries) {
  const metrics = emptyMetrics(entries.length);
  const startedToolIds = /* @__PURE__ */ new Set();
  let startedAt;
  let completedAt;
  for (const entry of entries) {
    const payload = record2(entry.payload) ?? {};
    const entryType = stringField2(entry, "type");
    const payloadType = stringField2(payload, "type");
    const timestamp2 = timestampMs(entry.timestamp);
    if (timestamp2 !== void 0) {
      startedAt = startedAt === void 0 ? timestamp2 : Math.min(startedAt, timestamp2);
      completedAt = completedAt === void 0 ? timestamp2 : Math.max(completedAt, timestamp2);
    }
    if (entryType === "turn.started") metrics.turnsStarted += 1;
    if (entryType === "turn.completed") {
      metrics.turnsCompleted += 1;
      addCodexExecUsage(metrics, record2(entry.usage));
    }
    if (entryType === "turn.failed") metrics.turnsAborted += 1;
    if (entryType === "error") metrics.toolErrors += 1;
    const item = record2(entry.item);
    if (item && (entryType === "item.started" || entryType === "item.completed")) {
      addCodexExecItem(metrics, startedToolIds, entryType, item);
    }
    if (entryType === "response_item") {
      if (payloadType === "function_call" || payloadType === "custom_tool_call")
        metrics.toolCalls += 1;
      if (payloadType === "function_call_output" || payloadType === "custom_tool_call_output")
        metrics.toolOutputs += 1;
      if (payloadType === "reasoning") metrics.reasoningItems += 1;
      if (payloadType === "message" && stringField2(payload, "role") === "assistant")
        metrics.assistantMessages += 1;
    }
    if (entryType === "event_msg") {
      if (payloadType === "user_message") metrics.userMessages += 1;
      if (payloadType === "agent_message") metrics.assistantMessages += 1;
      if (payloadType === "task_started") {
        metrics.turnsStarted += 1;
        const started = timestampMs(payload.started_at);
        if (started !== void 0) {
          startedAt = startedAt === void 0 ? started : Math.min(startedAt, started);
        }
      }
      if (payloadType === "task_complete") {
        metrics.turnsCompleted += 1;
        const completed = timestampMs(payload.completed_at);
        if (completed !== void 0) {
          completedAt = completedAt === void 0 ? completed : Math.max(completedAt, completed);
        }
        const duration = numberField2(payload, "duration_ms");
        if (duration !== void 0) metrics.wallMs = Math.max(metrics.wallMs, duration);
      }
      if (payloadType === "turn_aborted") {
        metrics.turnsAborted += 1;
        const completed = timestampMs(payload.completed_at);
        if (completed !== void 0) {
          completedAt = completedAt === void 0 ? completed : Math.max(completedAt, completed);
        }
      }
      if (payloadType === "context_compacted") metrics.contextCompactions += 1;
      if (payloadType === "patch_apply_end") {
        metrics.patchAttempts += 1;
        if (payload.success === true) metrics.patchSuccesses += 1;
        else {
          metrics.patchFailures += 1;
          metrics.toolErrors += 1;
        }
      }
      if (payloadType === "token_count")
        setCodexCumulativeUsage(metrics, record2(record2(payload.info)?.total_token_usage));
      const result = record2(payload.result);
      if (result && "Err" in result) metrics.toolErrors += 1;
    }
  }
  if (metrics.wallMs === 0 && startedAt !== void 0 && completedAt !== void 0) {
    metrics.wallMs = Math.max(0, completedAt - startedAt);
  }
  metrics.processScore = codexProcessScore(metrics);
  return metrics;
}
function addCodexExecItem(metrics, startedToolIds, eventType, item) {
  const itemType = stringField2(item, "type");
  const itemId = stringField2(item, "id");
  const isTool = itemType === "command_execution" || itemType === "mcp_tool_call" || itemType === "collab_tool_call" || itemType === "web_search";
  if (eventType === "item.started" && isTool) {
    metrics.toolCalls += 1;
    if (itemId) startedToolIds.add(itemId);
  }
  if (eventType === "item.completed" && isTool) {
    if (!itemId || !startedToolIds.has(itemId)) metrics.toolCalls += 1;
    metrics.toolOutputs += 1;
  }
  if (eventType !== "item.completed") return;
  if (itemType === "agent_message" || itemType === "message") metrics.assistantMessages += 1;
  if (itemType === "reasoning") metrics.reasoningItems += 1;
  if (itemType === "file_change") {
    metrics.patchAttempts += 1;
    const status = stringField2(item, "status");
    if (status === "completed") metrics.patchSuccesses += 1;
    if (status === "failed") {
      metrics.patchFailures += 1;
      metrics.toolErrors += 1;
    }
  }
  if (itemType === "error" || codexExecToolFailed(itemType, item)) metrics.toolErrors += 1;
}
function codexExecToolFailed(itemType, item) {
  const status = stringField2(item, "status");
  if (itemType === "command_execution") {
    const exitCode = numberField2(item, "exit_code");
    return status === "failed" || status === "declined" || exitCode !== void 0 && exitCode !== 0;
  }
  if (itemType === "mcp_tool_call") return status === "failed" || record2(item.error) !== null;
  return itemType === "collab_tool_call" && status === "failed";
}
function addCodexExecUsage(metrics, usage) {
  const parsed = readUsage(usage);
  metrics.inputTokens += parsed.input;
  metrics.outputTokens += parsed.output;
  metrics.reasoningTokens += parsed.reasoning;
  metrics.cachedTokens += parsed.cached;
  metrics.cacheWriteTokens += parsed.cacheWrite;
}
function setCodexCumulativeUsage(metrics, usage) {
  const parsed = readUsage(usage);
  metrics.inputTokens = Math.max(metrics.inputTokens, parsed.input);
  metrics.outputTokens = Math.max(metrics.outputTokens, parsed.output);
  metrics.reasoningTokens = Math.max(metrics.reasoningTokens, parsed.reasoning);
  metrics.cachedTokens = Math.max(metrics.cachedTokens, parsed.cached);
  metrics.cacheWriteTokens = Math.max(metrics.cacheWriteTokens, parsed.cacheWrite);
}
function claudeCodeMetrics(entries) {
  const metrics = emptyMetrics(entries.length);
  let startedAt;
  let completedAt;
  for (const entry of entries) {
    const type = stringField2(entry, "type");
    const timestamp2 = timestampMs(entry.timestamp);
    if (timestamp2 !== void 0) {
      startedAt = startedAt === void 0 ? timestamp2 : Math.min(startedAt, timestamp2);
      completedAt = completedAt === void 0 ? timestamp2 : Math.max(completedAt, timestamp2);
    }
    if (type === "user") metrics.userMessages += 1;
    if (type === "assistant") metrics.assistantMessages += 1;
    if (type === "pr-link") metrics.prLinks += 1;
    if (type === "file-history-snapshot") metrics.fileSnapshots += 1;
    const message = record2(entry.message);
    if (message) addUsage(metrics, record2(message.usage));
    const content = Array.isArray(message?.content) ? message.content : [];
    for (const item of content) {
      const part = record2(item);
      if (!part) continue;
      const partType = stringField2(part, "type");
      if (partType === "thinking") metrics.reasoningItems += 1;
      if (partType === "tool_use") metrics.toolCalls += 1;
      if (partType === "tool_result") {
        metrics.toolOutputs += 1;
        if (part.is_error === true) metrics.toolErrors += 1;
      }
    }
  }
  if (startedAt !== void 0 && completedAt !== void 0)
    metrics.wallMs = Math.max(0, completedAt - startedAt);
  metrics.processScore = claudeProcessScore(metrics);
  return metrics;
}
function openCodeMetrics(entries) {
  const metrics = emptyMetrics(entries.length);
  const messageUsage = emptyTokenTotals();
  const partUsage = emptyTokenTotals();
  let messageCost = 0;
  let partCost = 0;
  let messageCostCaptured = false;
  let partCostCaptured = false;
  let startedAt;
  let completedAt;
  for (const entry of entries) {
    const time = record2(entry.time);
    const created = timestampMs(time?.created);
    const completed = timestampMs(time?.completed);
    if (created !== void 0)
      startedAt = startedAt === void 0 ? created : Math.min(startedAt, created);
    if (completed !== void 0)
      completedAt = completedAt === void 0 ? completed : Math.max(completedAt, completed);
    const role = stringField2(entry, "role");
    if (role === "user") metrics.userMessages += 1;
    if (role === "assistant") {
      metrics.assistantMessages += 1;
      const finish = stringField2(entry, "finish");
      if (finish === "stop") metrics.turnsCompleted += 1;
      if (finish === "error") metrics.turnsAborted += 1;
    }
    const type = stringField2(entry, "type");
    if (type === "reasoning") metrics.reasoningItems += 1;
    if (type === "tool") {
      metrics.toolCalls += 1;
      const status = stringField2(record2(entry.state) ?? {}, "status");
      if (status === "completed") metrics.toolOutputs += 1;
      if (status === "error") {
        metrics.toolOutputs += 1;
        metrics.toolErrors += 1;
      }
    }
    if (type === "patch") {
      metrics.patchAttempts += 1;
      metrics.patchSuccesses += 1;
    }
    const cost = numberField2(entry, "cost");
    if (record2(entry.tokens) && role) {
      addUsageTo(messageUsage, record2(entry.tokens));
      if (cost !== void 0) {
        messageCost += cost;
        messageCostCaptured = true;
      }
    } else if (record2(entry.tokens)) {
      addUsageTo(partUsage, record2(entry.tokens));
      if (cost !== void 0) {
        partCost += cost;
        partCostCaptured = true;
      }
    }
  }
  const usage = hasTokenTotals(messageUsage) ? messageUsage : partUsage;
  metrics.inputTokens = usage.input;
  metrics.outputTokens = usage.output;
  metrics.reasoningTokens = usage.reasoning;
  metrics.cachedTokens = usage.cached;
  metrics.cacheWriteTokens = usage.cacheWrite;
  metrics.observedCostUsd = messageCostCaptured ? messageCost : partCost;
  metrics.observedCostCaptured = messageCostCaptured || partCostCaptured;
  if (metrics.wallMs === 0 && startedAt !== void 0 && completedAt !== void 0)
    metrics.wallMs = Math.max(0, completedAt - startedAt);
  metrics.processScore = terminalProcessScore(metrics);
  return metrics;
}
function kimiCodeMetrics(entries) {
  const metrics = emptyMetrics(entries.length);
  let startedAt;
  let completedAt;
  for (const entry of entries) {
    const timestamp2 = timestampMs(entry.timestamp);
    if (timestamp2 !== void 0) {
      startedAt = startedAt === void 0 ? timestamp2 : Math.min(startedAt, timestamp2);
      completedAt = completedAt === void 0 ? timestamp2 : Math.max(completedAt, timestamp2);
    }
    const role = stringField2(entry, "role");
    if (role === "user") metrics.userMessages += 1;
    if (role === "assistant") metrics.assistantMessages += 1;
    if (role === "_usage") addUsage(metrics, entry);
    const message = record2(entry.message);
    const messageType = message ? stringField2(message, "type") : void 0;
    const payload = record2(message?.payload) ?? {};
    if (messageType === "TurnBegin") {
      metrics.userMessages += 1;
      metrics.turnsStarted += 1;
    }
    if (messageType === "TurnEnd") metrics.turnsCompleted += 1;
    if (messageType === "StepInterrupted") metrics.turnsAborted += 1;
    if (messageType === "StepBegin") metrics.reasoningItems += 1;
    if (messageType === "ContentPart") {
      const payloadType = stringField2(payload, "type");
      if (payloadType === "think") metrics.reasoningItems += 1;
      if (payloadType === "text") metrics.assistantMessages += 1;
    }
    if (messageType === "ToolCall") metrics.toolCalls += 1;
    if (messageType === "ToolResult") {
      metrics.toolOutputs += 1;
      if (record2(payload.return_value)?.is_error === true) metrics.toolErrors += 1;
    }
    if (messageType === "StatusUpdate") addUsage(metrics, record2(payload.token_usage));
    if (messageType === "Notification") {
      const notification = record2(payload.payload);
      const exitCode = numberField2(notification ?? {}, "exit_code");
      if (notification?.timed_out === true || exitCode !== void 0 && exitCode !== 0) {
        metrics.toolErrors += 1;
      }
    }
  }
  if (startedAt !== void 0 && completedAt !== void 0)
    metrics.wallMs = Math.max(0, completedAt - startedAt);
  metrics.processScore = terminalProcessScore(metrics);
  return metrics;
}
function piMetrics(entries) {
  const metrics = emptyMetrics(entries.length);
  let bestReliabilityScore;
  for (const entry of entries) {
    const nodes = Array.isArray(entry.nodes) ? entry.nodes : [];
    const edges = Array.isArray(entry.edges) ? entry.edges : [];
    metrics.graphNodes += nodes.length;
    metrics.graphEdges += edges.length;
    for (const node of nodes) {
      const obj = record2(node);
      const ir = record2(obj?.ir) ?? obj;
      const kind = stringField2(ir ?? {}, "kind");
      if (kind === "ActionCandidate") metrics.actionCandidates += 1;
      if (kind === "ToolInvocation") metrics.toolCalls += 1;
      if (kind === "ToolResult") metrics.toolOutputs += 1;
      if (kind === "VerificationReport") metrics.verificationReports += 1;
      if (kind === "CompletionDecision") {
        metrics.completionDecisions += 1;
        metrics.turnsCompleted += 1;
      }
    }
    const averageReliability = numberField2(entry, "averageNodeReliability");
    if (averageReliability !== void 0)
      bestReliabilityScore = maxOptional(bestReliabilityScore, averageReliability);
    const pessimisticPath = numberField2(entry, "pessimisticPathEstimate");
    if (pessimisticPath !== void 0)
      bestReliabilityScore = maxOptional(bestReliabilityScore, pessimisticPath);
    const rows = Array.isArray(entry.rows) ? entry.rows : [];
    metrics.reliabilityRows += rows.length;
    for (const row of rows) {
      const obj = record2(row);
      if (!obj) continue;
      const lift = numberField2(obj, "lift");
      if (lift !== void 0) metrics.reliabilityLift = Math.max(metrics.reliabilityLift, lift);
      const validated = numberField2(obj, "validatedSuccessEstimate");
      if (validated !== void 0)
        bestReliabilityScore = maxOptional(bestReliabilityScore, validated);
    }
  }
  metrics.processScore = bestReliabilityScore !== void 0 ? clamp01(bestReliabilityScore) : metrics.completionDecisions > 0 ? 1 : 0;
  return metrics;
}
function emptyMetrics(entries) {
  return {
    entries,
    userMessages: 0,
    assistantMessages: 0,
    reasoningItems: 0,
    toolCalls: 0,
    toolOutputs: 0,
    toolErrors: 0,
    patchAttempts: 0,
    patchSuccesses: 0,
    patchFailures: 0,
    turnsStarted: 0,
    turnsCompleted: 0,
    turnsAborted: 0,
    contextCompactions: 0,
    mcpCalls: 0,
    subagentCalls: 0,
    skillCalls: 0,
    hookCalls: 0,
    webCalls: 0,
    codeActions: 0,
    prLinks: 0,
    fileSnapshots: 0,
    graphNodes: 0,
    graphEdges: 0,
    actionCandidates: 0,
    verificationReports: 0,
    completionDecisions: 0,
    reliabilityRows: 0,
    reliabilityLift: 0,
    inputTokens: 0,
    outputTokens: 0,
    reasoningTokens: 0,
    cachedTokens: 0,
    cacheWriteTokens: 0,
    observedCostUsd: 0,
    observedCostCaptured: false,
    wallMs: 0,
    processScore: 0
  };
}
function codexProcessScore(metrics) {
  const terminalTurns = metrics.turnsCompleted + metrics.turnsAborted;
  const base = terminalTurns > 0 ? metrics.turnsCompleted / terminalTurns : metrics.assistantMessages > 0 ? 0.5 : 0;
  return penalizeErrors(base, metrics);
}
function claudeProcessScore(metrics) {
  const base = metrics.prLinks > 0 ? 1 : metrics.assistantMessages > 0 ? 0.75 : 0;
  return penalizeErrors(base, metrics);
}
function terminalProcessScore(metrics) {
  const terminalTurns = metrics.turnsCompleted + metrics.turnsAborted;
  const base = terminalTurns > 0 ? metrics.turnsCompleted / terminalTurns : metrics.assistantMessages > 0 ? 0.75 : metrics.toolCalls > 0 ? 0.5 : 0;
  return penalizeErrors(base, metrics);
}
function penalizeErrors(base, metrics) {
  const operations = Math.max(1, metrics.toolCalls + metrics.patchAttempts);
  const errorRate = Math.min(1, (metrics.toolErrors + metrics.patchFailures) / operations);
  return clamp01(base * (1 - 0.5 * errorRate));
}
function emptyTokenTotals() {
  return { input: 0, output: 0, reasoning: 0, cached: 0, cacheWrite: 0 };
}
function hasTokenTotals(usage) {
  return usage.input > 0 || usage.output > 0 || usage.reasoning > 0 || usage.cached > 0 || usage.cacheWrite > 0;
}
function addUsage(metrics, usage) {
  const parsed = readUsage(usage);
  metrics.inputTokens += parsed.input;
  metrics.outputTokens += parsed.output;
  metrics.reasoningTokens += parsed.reasoning;
  metrics.cachedTokens += parsed.cached;
  metrics.cacheWriteTokens += parsed.cacheWrite;
}
function addUsageTo(totals, usage) {
  const parsed = readUsage(usage);
  totals.input += parsed.input;
  totals.output += parsed.output;
  totals.reasoning += parsed.reasoning;
  totals.cached += parsed.cached;
  totals.cacheWrite += parsed.cacheWrite;
}
function readUsage(usage) {
  const parsed = extractUsage(usage);
  return {
    input: parsed?.input ?? 0,
    output: parsed?.output ?? 0,
    reasoning: parsed?.reasoning ?? 0,
    cached: parsed?.cached ?? 0,
    cacheWrite: parsed?.cacheWrite ?? 0
  };
}
function resolveSessionCost(explicit, metrics, model) {
  if (explicit) {
    if (explicit.kind === "uncaptured") {
      if (explicit.usd !== null) throw new Error("uncaptured cost must have usd: null");
      return { costUsd: 0, costProvenance: explicit };
    }
    if (!Number.isFinite(explicit.usd) || explicit.usd < 0) {
      throw new Error(`${explicit.kind} cost must be a finite, non-negative USD amount`);
    }
    return { costUsd: explicit.usd, costProvenance: explicit };
  }
  if (metrics.observedCostCaptured) {
    const costProvenance = { kind: "observed", usd: metrics.observedCostUsd };
    return { costUsd: metrics.observedCostUsd, costProvenance };
  }
  const hasUsage = metrics.inputTokens > 0 || metrics.outputTokens > 0;
  if (hasUsage && isModelPriced(model)) {
    const costUsd = estimateCost(metrics.inputTokens, metrics.outputTokens, model);
    return { costUsd, costProvenance: { kind: "estimated", usd: costUsd } };
  }
  return { costUsd: 0, costProvenance: { kind: "uncaptured", usd: null } };
}
function diagnosticsFor(metrics, options) {
  const warnings = [];
  if (!options.scoreOverridden) warnings.push("outcome score is inferred from process telemetry");
  if (!options.explicitTerminal) warnings.push("no explicit terminal success/failure signal");
  if (metrics.inputTokens === 0 && metrics.outputTokens === 0 && metrics.reasoningTokens === 0 && metrics.cachedTokens === 0 && metrics.cacheWriteTokens === 0) {
    warnings.push("missing token usage");
  }
  if (options.costKind === "estimated")
    warnings.push("USD cost estimated from token usage and model pricing");
  if (options.costKind === "uncaptured") warnings.push("USD cost uncaptured");
  if (options.costKind === "uncaptured" && !isModelPriced(options.model))
    warnings.push("model pricing unknown");
  if (options.malformedLines > 0)
    warnings.push(`${options.malformedLines} malformed JSONL lines skipped`);
  return warnings;
}
function applyObservedSurfaceMetrics(metrics, observation) {
  const actions = observation.actions.filter(
    (action) => action.kind === "tool" || action.kind === "patch"
  );
  metrics.mcpCalls = actions.filter((action) => action.surface === "mcp").length;
  metrics.subagentCalls = actions.filter((action) => action.surface === "subagent").length;
  metrics.skillCalls = actions.filter((action) => action.surface === "skill").length;
  metrics.hookCalls = actions.filter((action) => action.surface === "hook").length;
  metrics.webCalls = actions.filter((action) => action.surface === "web").length;
  metrics.codeActions = actions.filter((action) => action.surface === "code").length;
}
function sessionIdFromEntries2(source, entries) {
  for (const entry of entries) {
    if (source === "codex") {
      const threadId = stringField2(entry, "thread_id");
      if (threadId) return threadId;
      const payload2 = record2(entry.payload);
      const id = payload2 ? stringField2(payload2, "id") : void 0;
      if (id) return id;
    }
    const message = record2(entry.message);
    const payload = record2(message?.payload);
    const sessionId = stringField2(entry, "sessionID") ?? stringField2(entry, "sessionId") ?? stringField2(entry, "session_id") ?? stringField2(payload ?? {}, "session_id");
    if (sessionId) return sessionId;
  }
  return void 0;
}
function modelFromEntries(source, entries) {
  let providerModel;
  for (const entry of entries) {
    if (source === "codex") {
      const payload = record2(entry.payload);
      const model2 = payload ? stringField2(payload, "model") : void 0;
      if (model2) return model2;
      providerModel = providerModel ?? (payload ? stringField2(payload, "model_provider") : void 0);
    }
    const openCodeModel = stringField2(entry, "modelID");
    if (openCodeModel) {
      const provider = stringField2(entry, "providerID");
      return provider ? `${provider}/${openCodeModel}` : openCodeModel;
    }
    const modelObject = record2(entry.model);
    const nestedModel = stringField2(modelObject ?? {}, "modelID");
    if (nestedModel) {
      const provider = stringField2(modelObject ?? {}, "providerID");
      return provider ? `${provider}/${nestedModel}` : nestedModel;
    }
    const message = record2(entry.message);
    const model = message ? stringField2(message, "model") : void 0;
    if (model) return model;
  }
  return providerModel;
}
function cwdFromEntries(entries) {
  for (const entry of entries) {
    const path = record2(entry.path);
    const cwd = stringField2(entry, "cwd") ?? stringField2(path ?? {}, "cwd") ?? stringField2(path ?? {}, "root") ?? (record2(entry.payload) ? stringField2(record2(entry.payload), "cwd") : void 0);
    if (cwd) return cwd;
  }
  return void 0;
}
function firstUserText(entries) {
  for (const entry of entries) {
    const payload = record2(entry.payload);
    const payloadType = payload ? stringField2(payload, "type") : void 0;
    if (payloadType === "user_message") return stringField2(payload, "message");
    if (stringField2(entry, "role") === "user") {
      const content = entry.content;
      if (typeof content === "string") return content;
    }
    const wirePayload = record2(record2(entry.message)?.payload);
    const userInput = wirePayload ? stringField2(wirePayload, "user_input") : void 0;
    if (userInput) return userInput;
    const message = record2(entry.message);
    if (message && stringField2(message, "role") === "user") {
      const content = message.content;
      if (typeof content === "string") return content;
      if (Array.isArray(content)) {
        const text = content.map((part) => {
          const obj = record2(part);
          return obj ? stringField2(obj, "text") : void 0;
        }).filter((part) => part !== void 0).join("\n");
        if (text) return text;
      }
    }
  }
  return void 0;
}
function fallbackSessionId2(source, sourcePath) {
  return hashString(`${source}:${sourcePath ?? "unknown-session"}`).slice(
    "sha256:".length,
    "sha256:".length + 20
  );
}
function withSnapshot(model) {
  const trimmed = model.trim() || "unknown";
  if (trimmed.includes("@") || /-\d{8}$/.test(trimmed) || /-\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
    return trimmed;
  }
  return `${trimmed}@observed-local`;
}
function hashJson(value) {
  return hashString(JSON.stringify(value));
}
function hashString(value) {
  return `sha256:${createHash("sha256").update(value).digest("hex")}`;
}
function stableSeed(value) {
  return createHash("sha256").update(value).digest().readUInt32BE(0);
}
function maxOptional(current, next) {
  return current === void 0 ? next : Math.max(current, next);
}
function clamp01(value) {
  if (!Number.isFinite(value)) return 0;
  return Math.max(0, Math.min(1, value));
}
function isRecord2(value) {
  return value !== null && typeof value === "object" && !Array.isArray(value);
}
function record2(value) {
  return isRecord2(value) ? value : null;
}
function stringField2(obj, key) {
  const value = obj[key];
  return typeof value === "string" && value.length > 0 ? value : void 0;
}
function numberField2(obj, key) {
  const value = obj[key];
  return typeof value === "number" && Number.isFinite(value) ? value : void 0;
}
function timestampMs(value) {
  if (typeof value === "number" && Number.isFinite(value)) {
    return value > 1e12 ? value : value * 1e3;
  }
  if (typeof value === "string" && value.length > 0) {
    const parsed = Date.parse(value);
    return Number.isFinite(parsed) ? parsed : void 0;
  }
  return void 0;
}

export {
  observeCodeAgentSession,
  parseCodeAgentJsonl,
  fromCodexSession,
  fromClaudeCodeSession,
  fromOpenCodeSession,
  fromKimiCodeSession,
  fromPiSession,
  fromPigraphSession
};
//# sourceMappingURL=chunk-7VYEGHWF.js.map