import path from "node:path";
import { appendFile, readFile } from "node:fs/promises";
import { countRedactions } from "../safe-transcript/index.js";
import { ensureDir, readJsonFile, readJsonl, sanitizeText, writeJsonFile, writeTextFile } from "../../shared/index.js";
import { LAB_REPRESENTATIVE_AGENT } from "../../agents/identity.js";
import { evaluateRunBudget, refreshRunBudgetEvaluation } from "../run-budget/index.js";
import { listSubplans } from "../subplan/index.js";
export function activityJournalStatus(store, runId, timestamp = new Date().toISOString()) {
    const interval = normalizeIntervalMinutes(store.config.activity_journal.interval_minutes);
    const bucket = bucketFor(timestamp, interval);
    const root = path.resolve(store.directory, store.config.trace.artifact_root, runId, "activity");
    return {
        enabled: store.config.trace.enabled && store.config.activity_journal.enabled,
        interval_minutes: interval,
        root_path: root,
        index_path: path.join(root, "README.md"),
        latest_path: path.join(root, "latest.md"),
        latest_json_path: path.join(root, "latest.json"),
        current_window_path: path.join(root, `${bucket.fileLabel}.md`),
        current_window_json_path: path.join(root, `${bucket.fileLabel}.json`),
        current_raw_window_path: path.join(root, "raw", `${bucket.fileLabel}.md`),
        current_window_label: bucket.displayLabel,
        current_window_start: bucket.start,
        current_window_end: bucket.end,
    };
}
export async function appendActivityJournalEntry(store, runId, entry) {
    const timestamp = entryTimestamp(entry);
    const status = activityJournalStatus(store, runId, timestamp);
    if (!status.enabled)
        return undefined;
    await ensureDir(status.root_path);
    await ensureRawWindowHeader(status);
    await appendFile(status.current_raw_window_path, renderEntry(entry, store.config.activity_journal), "utf8");
    await writeRepresentativeBriefing(store, runId, status);
    await writeIndex(status, runId);
    return status;
}
async function ensureRawWindowHeader(status) {
    try {
        await readFile(status.current_raw_window_path, "utf8");
    }
    catch {
        await writeTextFile(status.current_raw_window_path, `# SEED Raw Activity Window\n\nWindow: ${status.current_window_label}\nInterval: ${status.interval_minutes} minutes\n\n`);
    }
}
async function writeRepresentativeBriefing(store, runId, status) {
    const briefing = await buildRepresentativeBriefing(store, runId, status);
    const markdown = renderRepresentativeBriefing(briefing);
    await writeJsonFile(status.current_window_json_path, briefing);
    await writeJsonFile(status.latest_json_path, briefing);
    await writeTextFile(status.current_window_path, markdown);
    await writeTextFile(status.latest_path, markdown);
}
async function writeIndex(status, runId) {
    const lines = [
        "# SEED Activity Journal",
        "",
        `Run: ${runId}`,
        `Window size: ${status.interval_minutes} minutes`,
        `Current briefing: ${path.basename(status.current_window_path)}`,
        `Current briefing JSON: ${path.basename(status.current_window_json_path)}`,
        "Latest window: latest.md",
        "Latest briefing: latest.md",
        "Latest briefing JSON: latest.json",
        `Raw current window: ${path.relative(status.root_path, status.current_raw_window_path).split(path.sep).join("/")}`,
        `Updated: ${new Date().toISOString()}`,
        "",
        "This directory is the human-readable activity layer for the SEED run.",
        "The Markdown briefing is synthesized for the professor; raw chronological entries live under raw/.",
        "JSON/JSONL files one directory up remain the source of truth.",
        "",
        "Raw trace:",
        "- ../events.jsonl",
        "- ../agent_calls.jsonl",
        "- ../model_calls.jsonl",
        "- ../tool_calls.jsonl",
    ];
    await writeTextFile(status.index_path, `${lines.join("\n")}\n`);
}
async function buildRepresentativeBriefing(store, runId, status) {
    const root = runRoot(store, runId);
    const [run, tasks, events, agentCalls, modelCalls, toolCalls, teamRuntime, teamTasks, backgroundTasks, workspaceLeases, workspaceConflicts, artifactIndex, subplans, budgetState,] = await Promise.all([
        readJsonFile(path.join(root, "run.json")),
        readJsonFile(path.join(root, "tasks.json")),
        readJsonl(path.join(root, "events.jsonl")),
        readJsonl(path.join(root, "agent_calls.jsonl")),
        readJsonl(path.join(root, "model_calls.jsonl")),
        readJsonl(path.join(root, "tool_calls.jsonl")),
        readJsonFile(path.join(root, "team", "runtime.json")),
        readJsonFile(path.join(root, "team", "tasks.json")),
        readJsonFile(path.join(root, "background_tasks.json")),
        readJsonFile(path.join(root, "workspace", "leases.json")),
        readJsonFile(path.join(root, "workspace", "conflicts.json")),
        readJsonFile(path.join(root, "artifacts", "index.json")),
        listSubplans(store, runId),
        refreshRunBudgetEvaluation(store, runId),
    ]);
    const budgetEvaluation = await evaluateRunBudget(store, budgetState);
    const windowEvents = events.filter((event) => isWithinWindow(event.timestamp, status));
    const windowAgentCalls = agentCalls.filter((call) => isWithinWindow(call.timestamp_end ?? call.timestamp_start, status));
    const windowModelCalls = modelCalls.filter((call) => isWithinWindow(call.timestamp, status));
    const windowToolCalls = toolCalls.filter((call) => isWithinWindow(call.timestamp_end ?? call.timestamp_start, status));
    const observations = latestObservations(windowEvents, windowAgentCalls, windowModelCalls, windowToolCalls);
    const artifacts = artifactIndex?.artifacts ?? [];
    const documentArtifactRefs = artifacts
        .map((artifact) => artifact.path)
        .filter((artifactPath) => Boolean(artifactPath?.startsWith("artifacts/documents/")))
        .slice(-12);
    const rawWindowPath = status.current_raw_window_path;
    const promptRefs = unique(windowAgentCalls.map((call) => call.full_prompt_ref).filter(isString)).slice(-12);
    const runStatus = run?.status ?? "unknown";
    const completedRun = runStatus === "completed" || runStatus === "stopped";
    const activeRoles = activeRoleLines(run, teamRuntime);
    const staleBackgrounds = (backgroundTasks ?? []).filter((task) => task.status === "running" && task.stale_at);
    const blockers = blockerLines(tasks ?? [], teamTasks ?? [], backgroundTasks ?? [], workspaceConflicts ?? [], windowAgentCalls, windowToolCalls);
    const currentPhase = inferCurrentPhase(run, tasks ?? [], teamRuntime, backgroundTasks ?? [], workspaceConflicts ?? [], documentArtifactRefs, windowEvents, subplans);
    const latestSafeObservation = observations.at(-1)?.line ?? "No activity has been recorded in this window yet.";
    const observationLines = observations.slice(-12).map((observation) => observation.line);
    const traceStreams = ["../events.jsonl", "../agent_calls.jsonl", "../model_calls.jsonl", "../tool_calls.jsonl"];
    const workspaceRefs = ["../workspace/leases.json", "../workspace/conflicts.json"];
    const safetySource = JSON.stringify({ observations: observationLines, windowEvents, windowAgentCalls, windowModelCalls, windowToolCalls });
    const runRelative = (file) => relativeToRunRoot(root, file);
    return {
        version: 1,
        run_id: runId,
        generated_at: new Date().toISOString(),
        window: {
            label: status.current_window_label,
            start: status.current_window_start,
            end: status.current_window_end,
            interval_minutes: status.interval_minutes,
        },
        status: runStatus,
        current_phase: currentPhase,
        professor_goal: run?.professor_goal ?? "Unknown professor goal",
        latest_safe_observation: latestSafeObservation,
        active_roles: activeRoles,
        blockers,
        next_action: nextAction(run?.status ?? "unknown", blockers, tasks ?? [], backgroundTasks ?? [], workspaceConflicts ?? [], budgetEvaluation.status, staleBackgrounds),
        counts: {
            events: windowEvents.length,
            agent_calls: windowAgentCalls.length,
            model_calls: windowModelCalls.length,
            tool_calls: windowToolCalls.length,
            tasks_by_status: countBy((tasks ?? []).map((task) => task.status)),
            team_members_by_status: countBy((teamRuntime?.members ?? []).map((member) => presentationStatus(member.status, completedRun))),
            team_tasks_by_status: countBy((teamTasks ?? []).map((task) => task.status)),
            background_tasks_by_status: countBy((backgroundTasks ?? []).map((task) => presentationStatus(task.status ?? "unknown", completedRun))),
            subplans_by_status: countBy(subplans.map((subplan) => subplan.status)),
            active_workspace_leases: (workspaceLeases ?? []).filter((lease) => lease.status === "active").length,
            open_workspace_conflicts: (workspaceConflicts ?? []).filter((conflict) => conflict.status === "open").length,
            document_artifacts: documentArtifactRefs.length,
        },
        budget: {
            status: budgetEvaluation.status,
            warnings: budgetEvaluation.warnings,
            blocking_reason: budgetEvaluation.blocking_reason,
            model_calls: `${budgetState.usage.model_calls}/${budgetState.limits.max_model_calls}`,
            child_sessions: `${budgetState.usage.child_sessions}/${budgetState.limits.max_child_sessions}`,
        },
        stale_backgrounds: staleBackgrounds.map((task) => `${task.target_agent ?? task.kind ?? "background"} ${task.stale_reason ?? task.last_message ?? "stale"}`).slice(0, 8),
        verifier_verdicts: subplans
            .filter((subplan) => subplan.latest_verdict)
            .slice(-8)
            .map((subplan) => `${subplan.subplan_id} ${subplan.latest_verdict?.verdict}: ${subplan.latest_verdict?.summary}`),
        observations: observationLines,
        artifacts: {
            progress_path: "progress.md",
            evidence_path: "evidence.md",
            final_report_path: "final_report.md",
            raw_window_path: runRelative(rawWindowPath),
            prompt_refs: promptRefs.map(runRelative),
            document_artifact_refs: documentArtifactRefs,
            workspace_refs: workspaceRefs,
            trace_streams: traceStreams,
        },
        safety: {
            redaction_count: countRedactions(safetySource),
            reasoning_parts_recorded: false,
            note: "SEED records sanitized prompt/tool summaries and visible transcript text only; hidden model reasoning is not recorded.",
        },
    };
}
function renderRepresentativeBriefing(briefing) {
    return `${[
        "# SEED Lab-Representative Briefing",
        "",
        `Run: ${briefing.run_id}`,
        `Window: ${briefing.window.label}`,
        `Generated: ${briefing.generated_at}`,
        `Status: ${briefing.status}`,
        `Current phase: ${briefing.current_phase}`,
        `Professor goal: ${sanitizeText(briefing.professor_goal)}`,
        "",
        "## Reassurance",
        "",
        `Latest safe observation: ${briefing.latest_safe_observation}`,
        `Blocker: ${briefing.blockers.length ? briefing.blockers.join("; ") : "no blocker"}`,
        `Next action: ${briefing.next_action}`,
        `Latest briefing file: activity/latest.md`,
        "",
        briefing.status === "completed" || briefing.status === "stopped" ? "## Roles" : "## Active Roles",
        "",
        renderBulletList(briefing.active_roles),
        "",
        "## What Happened In This Window",
        "",
        renderBulletList(briefing.observations),
        "",
        "## Counts",
        "",
        `- events: ${briefing.counts.events}`,
        `- agent calls: ${briefing.counts.agent_calls}`,
        `- model calls: ${briefing.counts.model_calls}`,
        `- tool calls: ${briefing.counts.tool_calls}`,
        `- tasks: ${formatCounts(briefing.counts.tasks_by_status)}`,
        `- team members: ${formatCounts(briefing.counts.team_members_by_status)}`,
        `- team tasks: ${formatCounts(briefing.counts.team_tasks_by_status)}`,
        `- background tasks: ${formatCounts(briefing.counts.background_tasks_by_status)}`,
        `- sub-plans: ${formatCounts(briefing.counts.subplans_by_status)}`,
        `- active workspace leases: ${briefing.counts.active_workspace_leases}`,
        `- open workspace conflicts: ${briefing.counts.open_workspace_conflicts}`,
        `- document artifacts: ${briefing.counts.document_artifacts}`,
        "",
        "## Plan And Verification",
        "",
        renderBulletList(briefing.verifier_verdicts),
        "",
        "## Budget And Stale Workers",
        "",
        `- budget: ${briefing.budget.status} model_calls:${briefing.budget.model_calls} child_sessions:${briefing.budget.child_sessions}`,
        ...(briefing.budget.blocking_reason ? [`- budget blocker: ${briefing.budget.blocking_reason}`] : []),
        ...(briefing.budget.warnings.length ? briefing.budget.warnings.map((warning) => `- budget warning: ${warning}`) : ["- budget warning: none"]),
        ...briefing.stale_backgrounds.map((line) => `- stale worker: ${sanitizeText(line)}`),
        "",
        "## Artifacts",
        "",
        `- progress: ${briefing.artifacts.progress_path}`,
        `- evidence: ${briefing.artifacts.evidence_path}`,
        `- final report: ${briefing.artifacts.final_report_path}`,
        `- raw chronological window: ${briefing.artifacts.raw_window_path}`,
        ...briefing.artifacts.prompt_refs.map((ref) => `- prompt: ${ref}`),
        ...briefing.artifacts.document_artifact_refs.map((ref) => `- document: ${ref}`),
        ...briefing.artifacts.workspace_refs.map((ref) => `- workspace: ${ref}`),
        ...briefing.artifacts.trace_streams.map((ref) => `- trace: ${ref}`),
        "",
        "## Safety",
        "",
        `- redaction count: ${briefing.safety.redaction_count}`,
        `- hidden reasoning recorded: ${briefing.safety.reasoning_parts_recorded ? "yes" : "no"}`,
        `- note: ${briefing.safety.note}`,
    ].join("\n")}\n`;
}
function renderEntry(entry, config) {
    if (entry.kind === "event")
        return renderEventEntry(entry.event, config);
    if (entry.kind === "agent_call")
        return renderAgentCallEntry(entry.agent_call, config);
    return renderToolCallEntry(entry.tool_call, config);
}
function renderEventEntry(event, config) {
    return renderLines([
        `### ${timeOnly(event.timestamp)} event: ${safeInline(event.type)}`,
        "",
        field("Actor", event.actor, config),
        field("Summary", event.summary, config),
        field("Session", event.session_id, config),
        field("Task", event.related_task_id, config),
        field("Agent call", event.related_agent_call_id, config),
        field("Tool call", event.related_tool_call_id, config),
    ]);
}
function renderAgentCallEntry(call, config) {
    return renderLines([
        `### ${timeOnly(call.timestamp_end ?? call.timestamp_start)} agent: ${safeInline(call.target_agent)} ${safeInline(call.status)}`,
        "",
        field("Caller", call.caller_agent, config),
        field("Mode", call.mode, config),
        field("Parent session", call.parent_session_id, config),
        field("Child session", call.child_session_id, config),
        field("Task", call.task_id, config),
        config.include_prompt_summaries ? field("Prompt", call.prompt_summary, config) : undefined,
        field("Prompt artifact", call.full_prompt_ref, config),
        field("Model", call.resolved_model ?? call.requested_model ?? call.model_profile, config),
        field("Result", call.result_summary, config),
        field("Evidence", call.evidence_refs.join(", "), config),
        field("Error", call.error, config),
    ]);
}
function renderToolCallEntry(call, config) {
    return renderLines([
        `### ${timeOnly(call.timestamp_end ?? call.timestamp_start)} tool: ${safeInline(call.tool_name)} ${safeInline(call.status)}`,
        "",
        field("Session", call.session_id, config),
        field("Agent", call.agent, config),
        field("Task", call.task_id, config),
        config.include_tool_args ? field("Args", call.args_summary, config) : undefined,
        field("Output", call.output_summary, config),
        field("Evidence", call.evidence_refs.join(", "), config),
        field("Error", call.error, config),
    ]);
}
function latestObservations(events, agentCalls, modelCalls, toolCalls) {
    const observations = [
        ...events.map((event) => ({
            timestamp: event.timestamp,
            line: compactLine(`event: ${event.type}`, event.summary),
        })),
        ...agentCalls.map((call) => ({
            timestamp: call.timestamp_end ?? call.timestamp_start,
            line: compactLine(`agent: ${call.target_agent} ${call.status}`, [
                call.prompt_summary ? `Prompt: ${call.prompt_summary}` : "",
                call.result_summary ? `Result: ${call.result_summary}` : "",
                call.evidence_refs.length ? `Evidence: ${call.evidence_refs.join(", ")}` : "",
            ].filter(Boolean).join(" | ")),
        })),
        ...modelCalls.map((call) => ({
            timestamp: call.timestamp,
            line: compactLine(`model: ${call.target_agent} attempt ${call.attempt} ${call.status}`, call.resolved_model ?? call.model ?? call.model_profile ?? ""),
        })),
        ...toolCalls.map((call) => ({
            timestamp: call.timestamp_end ?? call.timestamp_start,
            line: compactLine(`tool: ${call.tool_name} ${call.status}`, [
                call.args_summary ? `Args: ${call.args_summary}` : "",
                call.output_summary ? `Output: ${call.output_summary}` : "",
                call.evidence_refs.length ? `Evidence: ${call.evidence_refs.join(", ")}` : "",
                call.error ? `Error: ${call.error}` : "",
            ].filter(Boolean).join(" | ")),
        })),
    ];
    return observations.sort((left, right) => safeDate(left.timestamp).getTime() - safeDate(right.timestamp).getTime());
}
function activeRoleLines(run, runtime) {
    const activeStatuses = new Set(["queued", "launching", "running", "active", "waiting_on_mailbox", "blocked"]);
    const activeMembers = (runtime?.members ?? []).filter((member) => activeStatuses.has(member.status));
    const completedRun = run?.status === "completed" || run?.status === "stopped";
    if (activeMembers.length) {
        return activeMembers.map((member) => {
            const status = completedRun ? `last observed ${member.status}; run ${run?.status}` : member.status;
            return `${member.name} (${member.role_label ?? member.role}, ${status})`;
        });
    }
    return [`${run?.active_agent ?? LAB_REPRESENTATIVE_AGENT} (Lab-Representative, ${run?.status ?? "running"})`];
}
function blockerLines(tasks, teamTasks, backgroundTasks, workspaceConflicts, agentCalls, toolCalls) {
    return [
        ...tasks.filter((task) => task.status === "blocked").map((task) => `${task.title}: ${task.blocker ?? "blocked"}`),
        ...teamTasks.filter((task) => task.status === "blocked").map((task) => `${task.title}: ${task.blocker ?? "blocked"}`),
        ...backgroundTasks.filter((task) => task.status === "failed").map((task) => `${task.target_agent ?? task.kind ?? "background"} failed: ${task.last_message ?? "review background output"}`),
        ...backgroundTasks.filter((task) => task.status === "running" && task.stale_at).map((task) => `${task.target_agent ?? task.kind ?? "background"} stale: ${task.stale_reason ?? task.last_message ?? "review stale worker"}`),
        ...workspaceConflicts.filter((conflict) => conflict.status === "open").map((conflict) => `workspace ${conflict.path}: ${conflict.summary}`),
        ...agentCalls.filter((call) => call.status === "failed").map((call) => `${call.target_agent} failed: ${call.error ?? call.result_summary ?? "review agent call"}`),
        ...toolCalls.filter((call) => call.status === "failed").map((call) => `${call.tool_name} failed: ${call.error ?? call.output_summary ?? "review tool call"}`),
    ].map((line) => sanitizeText(line).slice(0, 240)).slice(0, 8);
}
function inferCurrentPhase(run, tasks, runtime, backgroundTasks, workspaceConflicts, documentArtifactRefs, events, subplans) {
    if (!run)
        return "initializing";
    if (run.status === "blocked")
        return "blocked";
    if (run.status === "failed")
        return "failed";
    if (run.status === "completed")
        return "completed";
    if (run.status === "stopped")
        return "stopped";
    if (run.status === "awaiting_feedback")
        return "awaiting-feedback lab meeting";
    if (workspaceConflicts.some((conflict) => conflict.status === "open"))
        return "conflict resolution";
    if (subplans.some((subplan) => subplan.status === "verifying"))
        return "sub-plan verification";
    if (subplans.some((subplan) => subplan.status === "rework"))
        return "sub-plan rework";
    if (subplans.some((subplan) => subplan.status === "executing"))
        return "sub-plan execution";
    if (subplans.some((subplan) => subplan.status === "ready" || subplan.status === "planned"))
        return "sub-plan planning";
    if (tasks.some((task) => task.status === "review"))
        return "verification and review";
    if ((runtime?.members.length ?? 0) > 1)
        return "team orchestration";
    if (backgroundTasks.some((task) => task.status === "running"))
        return "background execution";
    if (documentArtifactRefs.length || events.some((event) => event.type.includes("document")))
        return "document analysis";
    return "running";
}
function nextAction(runStatus, blockers, tasks, backgroundTasks, workspaceConflicts, budgetStatus, staleBackgrounds) {
    if (runStatus === "completed")
        return "Review the final report and cited artifacts.";
    if (runStatus === "stopped")
        return "Run is stopped; start a new /seed run when ready.";
    if (runStatus === "awaiting_feedback")
        return "Wait for normal professor feedback in the Lab-Representative chat, then resume from that feedback.";
    if (blockers.length || workspaceConflicts.some((conflict) => conflict.status === "open")) {
        return "Resolve the listed blocker before marking the run complete.";
    }
    if (budgetStatus === "blocked")
        return "Resolve the run budget blocker before launching more delegated work.";
    if (staleBackgrounds.length)
        return "Review stale background workers, then checkpoint, follow up, cancel, or relaunch.";
    if (budgetStatus === "warning")
        return "Review budget usage before launching more workers.";
    if (backgroundTasks.some((task) => task.status === "running")) {
        return "Continue monitoring active background work and checkpoint if it runs long.";
    }
    if (tasks.some((task) => task.status === "pending"))
        return "Claim the next pending task or delegate it to a suitable lab member.";
    if (tasks.some((task) => task.status === "in_progress"))
        return "Continue the active task and attach evidence for claims.";
    return "Continue the Lab-Representative plan and keep progress/final report artifacts current.";
}
function renderLines(lines) {
    return `${lines.filter((line) => Boolean(line)).join("\n")}\n\n`;
}
function renderBulletList(items) {
    return items.length ? items.map((item) => `- ${sanitizeText(item)}`).join("\n") : "- none";
}
function field(label, value, config) {
    if (!value)
        return undefined;
    return `- ${label}: ${truncate(sanitizeText(value), config.max_inline_chars)}`;
}
function safeInline(value) {
    return sanitizeText(value).replace(/\s+/g, " ").slice(0, 120);
}
function compactLine(prefix, detail) {
    const cleanPrefix = sanitizeText(prefix).replace(/\s+/g, " ").trim();
    const cleanDetail = sanitizeText(detail).replace(/\s+/g, " ").trim();
    return cleanDetail ? `${cleanPrefix} - ${cleanDetail.slice(0, 700)}` : cleanPrefix;
}
function truncate(value, maxChars) {
    const limit = Math.max(80, maxChars);
    const compact = value.replace(/\s+/g, " ").trim();
    return compact.length > limit ? `${compact.slice(0, limit - 1)}...` : compact;
}
function entryTimestamp(entry) {
    if (entry.kind === "event")
        return entry.event.timestamp;
    if (entry.kind === "agent_call")
        return entry.agent_call.timestamp_end ?? entry.agent_call.timestamp_start;
    return entry.tool_call.timestamp_end ?? entry.tool_call.timestamp_start;
}
function timeOnly(timestamp) {
    return safeDate(timestamp).toISOString().slice(11, 19);
}
function bucketFor(timestamp, intervalMinutes) {
    const date = safeDate(timestamp);
    const intervalMs = intervalMinutes * 60 * 1000;
    const start = new Date(Math.floor(date.getTime() / intervalMs) * intervalMs);
    const end = new Date(start.getTime() + intervalMs);
    return {
        fileLabel: start.toISOString().replace(/:/g, "-").replace(/\.\d{3}Z$/, "Z"),
        displayLabel: `${start.toISOString()} to ${end.toISOString()}`,
        start: start.toISOString(),
        end: end.toISOString(),
    };
}
function normalizeIntervalMinutes(value) {
    return Number.isFinite(value) && value >= 1 ? Math.floor(value) : 10;
}
function isWithinWindow(timestamp, status) {
    const time = safeDate(timestamp).getTime();
    return time >= safeDate(status.current_window_start).getTime() && time < safeDate(status.current_window_end).getTime();
}
function safeDate(timestamp) {
    const date = new Date(timestamp);
    return Number.isFinite(date.getTime()) ? date : new Date();
}
function countBy(values) {
    const counts = {};
    for (const value of values)
        counts[value] = (counts[value] ?? 0) + 1;
    return counts;
}
function formatCounts(counts) {
    return Object.entries(counts).map(([status, count]) => `${status}:${count}`).join(", ") || "none";
}
function presentationStatus(status, completedRun) {
    if (!completedRun)
        return status;
    if (status === "running" || status === "active" || status === "queued" || status === "launching" || status === "waiting_on_mailbox") {
        return `last_observed_${status}`;
    }
    return status;
}
function relativeToRunRoot(root, file) {
    const relative = path.relative(root, file).split(path.sep).join("/");
    if (!relative || relative.startsWith("..") || path.isAbsolute(relative))
        return file.split(path.sep).join("/");
    return relative;
}
function unique(values) {
    return [...new Set(values.filter(Boolean))];
}
function isString(value) {
    return typeof value === "string" && value.length > 0;
}
function runRoot(store, runId) {
    return path.join(path.resolve(store.directory, store.config.trace.artifact_root), runId);
}
//# sourceMappingURL=index.js.map