// 重构前 index.ts 只读参考：commit 6a04144d3f5103014f75b637d7e6bc2f45bf007f，blob 56e590c1a6b5ca7ad128bf2c992f60e46c355a58；可用 `git show 6a04144d3f5103014f75b637d7e6bc2f45bf007f:src/components/microservices/code-queue/src/index.ts` 查看。

import postgres from "postgres";
import { codeAgentPortForModel, codeAgentPortInfo, codeExecutionModeInfo, codeExecutionModes, codeModelProviderSourceContract, codeModelPorts as codeModelPortsFor, opencodeModels as opencodeModelsFor } from "./code-agent/common";
import { claudeQqNotificationOutboxStats, notificationTargetConfigured, notificationTargetLabel } from "./notifications";
import { executionModeOptions, executionProviderOptions } from "./provider-runtime";
import { taskFullOutput } from "./task-output";
import { sanitizeTaskOutputText } from "./output-redaction";
import { applyOaTraceStatsToTaskJson, taskScopeId, type OaTraceStats, type TraceStatsFallback } from "./oa-events";
import { buildExecutionDiagnostics, schedulerHeartbeatStaleMs } from "./execution-diagnostics";
import { buildCompactTaskTranscript, buildTaskTranscript, cachedPreviewTranscript, fullTranscript, prefixPreview, safePreview, statsDaysFromUrl, taskForCompactMetaResponse, taskForMetaResponse, taskListStepCount, taskStatisticsSummary, taskTiming, timestampMs } from "./task-view";
import { userPromptForDisplay } from "./prompts";
import type { ActiveRun, ActiveRunSlotWaiter } from "./code-agent/common";
import type { JsonValue, QueueRecord, QueuedStatusReason, QueueTask, RuntimeConfig, TaskStatus, TranscriptLine } from "./types";

export interface QueueApiContext {
  config: Pick<RuntimeConfig, "approvalPolicy" | "codeModels" | "codexModels" | "codexSqliteLogExportBatchSize" | "codexSqliteLogExportEnabled" | "codexSqliteLogExportIntervalMs" | "codexSqliteLogMaxBytes" | "deepseekApiBase" | "deepseekApiKey" | "deepseekModel" | "defaultModel" | "defaultReasoningEffort" | "defaultWorkdir" | "judgeMaxTokens" | "judgeRepairAttempts" | "mainProviderId" | "maxActiveQueues" | "maxInMemoryEventRecords" | "maxInMemoryOutputRecords" | "minimaxApiBase" | "minimaxApiKey" | "minimaxM3Model" | "minimaxModel" | "modelReasoningEfforts" | "notifyClaudeQqBaseUrl" | "notifyClaudeQqEnabled" | "notifyClaudeQqMaxResponseChars" | "notifyClaudeQqRetryIntervalMs" | "notifyClaudeQqSendAttempts" | "notifyClaudeQqTargetType" | "notifyClaudeQqTimeoutMs" | "outputArchiveDir" | "remoteDefaultWorkdir" | "sandbox" | "schedulerEnabled" | "schedulerPollIntervalMs" | "windowsNativeCodexDefaultWorkdir">;
  activeRunSlotQueueIds: () => string[];
  activeRunSlotWaiterSummaries: () => JsonValue[];
  activeRuns: Map<string, ActiveRun>;
  codexSqliteLogExporter: () => Record<string, JsonValue>;
  collectDevReady: () => JsonValue;
  compactJsonResponse: (body: unknown, status?: number) => Response;
  databaseLastError: () => string | null;
  databaseReady: () => boolean;
  defaultQueueId: string;
  dirtyDatabaseQueueCount: () => number;
  dirtyDatabaseTaskCount: () => number;
  databaseStorageHealth: () => JsonValue;
  jsonResponse: (body: unknown, status?: number) => Response;
  judgeFailRetryLimit: number;
  loadQueuesFromDatabase: () => Promise<QueueRecord[]>;
  loadTaskFromDatabase: (taskId: string) => Promise<QueueTask | null>;
  loadTasksFromDatabase: (where?: "all" | "hot") => Promise<QueueTask[]>;
  loadTasksFromDatabaseByIds: (taskIds: string[]) => Promise<QueueTask[]>;
  pageBySeq: <T extends { seq: number }>(items: T[], url: URL, limit: number) => { mode: "tail" | "after" | "before"; afterSeq: number; beforeSeq: number | null; nextAfterSeq: number; previousBeforeSeq: number | null; hasMore: boolean; hasBefore: boolean; chunk: T[] };
  parseLimit: (url: URL) => number;
  parseTextLimit: (url: URL) => number;
  processing: () => boolean;
  processingQueues: Set<string>;
  oaEventPublisherStatus: () => JsonValue;
  queueHeadTask: (queueId: string, tasks?: QueueTask[]) => QueueTask | null;
  queueIdOf: (task: QueueTask) => string;
  queues: () => QueueRecord[];
  queueTaskIsRunnable: (task: QueueTask) => boolean;
  queuedStatusReason: (task: QueueTask, tasks?: QueueTask[]) => QueuedStatusReason | null;
  queuedTaskPromptEditable: (task: QueueTask) => boolean;
  reconcileStatus: (tasks: QueueTask[]) => JsonValue;
  runGarbageCollection: () => void;
  safeQueueId: (value: unknown) => string;
  safeQueueName: (value: unknown, queueId: string) => string;
  sql: () => postgres.Sql;
  taskQueueEnteredAt: (task: QueueTask) => string;
  traceStatsForTasks: (taskIds: string[]) => Promise<Map<string, OaTraceStats>>;
  tasks: () => QueueTask[];
  truthyParam: (url: URL, name: string) => boolean;
}

let context: QueueApiContext | null = null;

export function configureQueueApi(runtimeContext: QueueApiContext): void {
  context = runtimeContext;
}

function ctx(): QueueApiContext {
  if (context === null) throw new Error("queue-api module is not configured");
  return context;
}

function terminalTask(task: QueueTask): boolean {
  return task.status === "succeeded" || task.status === "failed" || task.status === "canceled";
}

function terminalTaskUnread(task: QueueTask): boolean {
  return terminalTask(task) && task.readAt === null;
}

function taskUpdatedAtMs(task: QueueTask): number {
  return timestampMs(task.updatedAt) ?? timestampMs(task.createdAt) ?? 0;
}

function memoryTaskIsNewerThanDatabase(memoryTask: QueueTask, databaseTask: QueueTask): boolean {
  return preferHotTaskForRead(memoryTask, databaseTask);
}

function mergeReadTaskByFreshness(target: Map<string, QueueTask>, task: QueueTask): void {
  const existing = target.get(task.id);
  if (existing === undefined || memoryTaskIsNewerThanDatabase(task, existing)) target.set(task.id, task);
}

function rememberReadDatabaseError(error: unknown): void {
  const message = error instanceof Error ? error.message : String(error);
  console.warn(JSON.stringify({
    ts: new Date().toISOString(),
    service: "code-queue",
    level: "warn",
    message: "read_database_fallback",
    data: { error: message },
  }));
}

async function loadFreshMemoryTasksForRead(): Promise<QueueTask[]> {
  const memoryTasks = ctx().tasks();
  if (!ctx().databaseReady() || memoryTasks.length === 0) return memoryTasks;
  try {
    const databaseTasks = await ctx().loadTasksFromDatabaseByIds(memoryTasks.map((task) => task.id));
    const byId = new Map(databaseTasks.map((task) => [task.id, task]));
    for (const task of memoryTasks) mergeReadTaskByFreshness(byId, task);
    return Array.from(byId.values());
  } catch (error) {
    rememberReadDatabaseError(error);
    return memoryTasks;
  }
}

async function loadTaskForReadByFreshness(taskId: string): Promise<QueueTask | null> {
  const memoryTask = ctx().tasks().find((task) => task.id === taskId) ?? null;
  if (!ctx().databaseReady()) return memoryTask;
  try {
    const databaseTask = await ctx().loadTaskFromDatabase(taskId);
    if (databaseTask === null) return memoryTask;
    if (memoryTask !== null && memoryTaskIsNewerThanDatabase(memoryTask, databaseTask)) return memoryTask;
    return databaseTask;
  } catch (error) {
    rememberReadDatabaseError(error);
    return memoryTask;
  }
}

function queuedStatusPayload(task: QueueTask, tasks?: QueueTask[]): { queuedReason: QueuedStatusReason | null; queuedReasonLabel: string | null } {
  const reason = ctx().queuedStatusReason(task, tasks);
  return {
    queuedReason: reason,
    queuedReasonLabel: reason?.label ?? null,
  };
}

function transcriptChunkResponse(task: QueueTask, url: URL): Response {
  const limit = ctx().parseLimit(url);
  const fullText = ctx().truthyParam(url, "fullText") || ctx().truthyParam(url, "raw");
  const agentPort = codeAgentPortForModel(task.model);
  const transcript = fullText ? fullTranscript(task) : cachedPreviewTranscript(task);
  const page = ctx().pageBySeq(transcript, url, limit);
  return ctx().jsonResponse({
    ok: true,
    taskId: task.id,
    queueId: ctx().queueIdOf(task),
    status: task.status,
    updatedAt: task.updatedAt,
    agentPort,
    agentPortInfo: codeAgentPortInfo(agentPort),
    mode: page.mode,
    transcript: page.chunk,
    afterSeq: page.afterSeq,
    nextAfterSeq: page.nextAfterSeq,
    beforeSeq: page.beforeSeq,
    previousBeforeSeq: page.previousBeforeSeq,
    hasMore: page.hasMore,
    hasBefore: page.hasBefore,
    total: transcript.length,
    maxSeq: transcript.at(-1)?.seq ?? 0,
    fullText,
  });
}

function outputChunkResponse(task: QueueTask, url: URL): Response {
  const limit = ctx().parseLimit(url);
  const fullText = ctx().truthyParam(url, "fullText") || ctx().truthyParam(url, "raw");
  const maxTextChars = ctx().parseTextLimit(url);
  const fullOutput = taskFullOutput(task);
  const page = ctx().pageBySeq(fullOutput, url, limit);
  const output = page.chunk.map((item) => {
    const text = sanitizeTaskOutputText(item.text);
    const truncated = !fullText && text.length > maxTextChars;
    return {
      ...item,
      text: truncated ? text.slice(0, maxTextChars) : text,
      textChars: text.length,
      textTruncated: truncated,
      omittedChars: truncated ? text.length - maxTextChars : 0,
    };
  });
  return ctx().jsonResponse({
    ok: true,
    taskId: task.id,
    queueId: ctx().queueIdOf(task),
    status: task.status,
    updatedAt: task.updatedAt,
    mode: page.mode,
    output,
    afterSeq: page.afterSeq,
    nextAfterSeq: page.nextAfterSeq,
    beforeSeq: page.beforeSeq,
    previousBeforeSeq: page.previousBeforeSeq,
    hasMore: page.hasMore,
    hasBefore: page.hasBefore,
    total: fullOutput.length,
    retainedTotal: task.output.length,
    maxSeq: fullOutput.at(-1)?.seq ?? 0,
    fullText,
    maxTextChars,
  });
}

function taskIdsForStats(tasks: QueueTask[], selectedTask?: QueueTask | null): string[] {
  const ids = tasks.map((task) => task.id);
  if (selectedTask !== null && selectedTask !== undefined) ids.push(selectedTask.id);
  return Array.from(new Set(ids.filter(Boolean)));
}

function statsForTask(stats: Map<string, OaTraceStats>, task: QueueTask): OaTraceStats | null {
  return stats.get(taskScopeId(task.id)) ?? null;
}

function traceStatsFallbackForTask(task: QueueTask): TraceStatsFallback {
  const transcript = cachedPreviewTranscript(task).filter((line) => line.title !== "Submitted prompt");
  const stepCount = taskListStepCount(task);
  const outputMaxSeq = task.output.at(-1)?.seq ?? 0;
  const readCount = transcript.filter((line) => line.kind === "explored").length;
  const editCount = transcript.filter((line) => line.kind === "edited").length;
  const runCount = transcript.filter((line) => line.kind === "ran").length;
  const errorCount = transcript.filter((line) => line.kind === "error").length;
  return {
    stepCount,
    llmStepCount: stepCount,
    traceLineCount: transcript.length,
    outputMaxSeq,
    readCount,
    editCount,
    runCount,
    errorCount,
    reason: stepCount > 0 || transcript.length > 0 || outputMaxSeq > 0
      ? "oa-event-flow-stats-unavailable-retained-trace-present"
      : "no-trace-steps-yet",
  };
}

function applyStats(value: JsonValue, stats: Map<string, OaTraceStats>, task: QueueTask): JsonValue {
  return applyOaTraceStatsToTaskJson(value, statsForTask(stats, task), traceStatsFallbackForTask(task));
}

function taskForListResponse(task: QueueTask, lite = false, queueTasks?: QueueTask[]): JsonValue {
  const timing = taskTiming(task);
  const displayPrompt = task.basePrompt || userPromptForDisplay(task.prompt);
  if (lite) {
    return {
      id: task.id,
      queueId: ctx().queueIdOf(task),
      queueEnteredAt: ctx().taskQueueEnteredAt(task),
      prompt: prefixPreview(displayPrompt, 360),
      basePrompt: prefixPreview(task.basePrompt, 360),
      displayPrompt: prefixPreview(displayPrompt, 360),
      promptChars: task.prompt.length,
      basePromptChars: task.basePrompt.length,
      displayPromptChars: displayPrompt.length,
      promptEditable: ctx().queuedTaskPromptEditable(task),
      finalResponseChars: task.finalResponse.length,
      stepCount: null,
      llmStepCount: null,
      traceStats: null,
      statsSource: "unavailable",
      summaryOnly: true,
      referenceTaskIds: task.referenceTaskIds,
      referenceInjectionSummary: task.referenceInjection === null ? null : {
        injectedAt: task.referenceInjection.injectedAt,
        itemCount: task.referenceInjection.itemCount,
        directReferenceTaskIds: task.referenceInjection.directReferenceTaskIds,
        maxRounds: task.referenceInjection.maxRounds,
        truncated: task.referenceInjection.truncated,
      },
      providerId: task.providerId,
      executionMode: task.executionMode,
      requestedExecutionMode: task.requestedExecutionMode ?? null,
      executionModeInfo: codeExecutionModeInfo(task.executionMode),
      cwd: task.cwd,
      model: task.model,
      agentPort: codeAgentPortForModel(task.model),
      agentPortInfo: codeAgentPortInfo(codeAgentPortForModel(task.model)),
      reasoningEffort: task.reasoningEffort,
      maxAttempts: task.maxAttempts,
      status: task.status,
      ...queuedStatusPayload(task, queueTasks),
      createdAt: task.createdAt,
      updatedAt: task.updatedAt,
      startedAt: task.startedAt,
      finishedAt: task.finishedAt,
      readAt: task.readAt,
      currentAttempt: task.currentAttempt,
      currentMode: task.currentMode,
      judgeFailCount: task.judgeFailCount,
      judgeFailRetryLimit: ctx().judgeFailRetryLimit,
      schedulerHeartbeat: task.schedulerHeartbeat ?? null,
      codexThreadId: task.codexThreadId,
      activeTurnId: task.activeTurnId,
      lastError: task.lastError,
      lastJudge: task.lastJudge === null ? null : {
        decision: task.lastJudge.decision,
        confidence: task.lastJudge.confidence,
        source: task.lastJudge.source,
        reason: safePreview(task.lastJudge.reason, 260),
      },
      cancelRequested: task.cancelRequested,
      terminalUnread: terminalTaskUnread(task),
      outputCount: task.output.length,
      eventCount: task.events.length,
      attemptCount: task.attempts.length,
      timing,
    } as unknown as JsonValue;
  }
  return {
    id: task.id,
    queueId: ctx().queueIdOf(task),
    queueEnteredAt: ctx().taskQueueEnteredAt(task),
    prompt: safePreview(displayPrompt, 2000),
    basePrompt: safePreview(task.basePrompt, 2000),
    displayPrompt: safePreview(displayPrompt, 2000),
    promptChars: task.prompt.length,
    basePromptChars: task.basePrompt.length,
    displayPromptChars: displayPrompt.length,
    promptEditable: ctx().queuedTaskPromptEditable(task),
    finalResponseChars: task.finalResponse.length,
    stepCount: null,
    llmStepCount: null,
    traceStats: null,
    statsSource: "unavailable",
    summaryOnly: true,
    referenceTaskIds: task.referenceTaskIds,
    referenceInjection: task.referenceInjection,
    providerId: task.providerId,
    executionMode: task.executionMode,
    requestedExecutionMode: task.requestedExecutionMode ?? null,
    executionModeInfo: codeExecutionModeInfo(task.executionMode),
    cwd: task.cwd,
    model: task.model,
    agentPort: codeAgentPortForModel(task.model),
    agentPortInfo: codeAgentPortInfo(codeAgentPortForModel(task.model)),
    reasoningEffort: task.reasoningEffort,
    maxAttempts: task.maxAttempts,
    status: task.status,
    ...queuedStatusPayload(task, queueTasks),
    createdAt: task.createdAt,
    updatedAt: task.updatedAt,
    startedAt: task.startedAt,
    finishedAt: task.finishedAt,
    readAt: task.readAt,
    currentAttempt: task.currentAttempt,
    currentMode: task.currentMode,
    judgeFailCount: task.judgeFailCount,
    judgeFailRetryLimit: ctx().judgeFailRetryLimit,
    schedulerHeartbeat: task.schedulerHeartbeat ?? null,
    codexThreadId: task.codexThreadId,
    activeTurnId: task.activeTurnId,
    lastError: task.lastError,
    lastJudge: task.lastJudge,
    cancelRequested: task.cancelRequested,
    terminalUnread: terminalTaskUnread(task),
    outputCount: task.output.length,
    eventCount: task.events.length,
    attemptCount: task.attempts.length,
    attempts: task.attempts.slice(-3),
    timing,
  } as unknown as JsonValue;
}

function perQueueSummaries(tasks: QueueTask[] = ctx().tasks(), queueRecords: QueueRecord[] = ctx().queues()): JsonValue[] {
  const summaries = new Map<string, {
    name: string;
    total: number;
    counts: Record<string, number>;
    unreadTerminal: number;
    activeTaskId: string | null;
    runnableTaskId: string | null;
    createdAt: string | null;
    updatedAt: string | null;
  }>();
  for (const queue of queueRecords) {
    const name = ctx().safeQueueName(queue.name, queue.id);
    summaries.set(queue.id, {
      name,
      total: 0,
      counts: {},
      unreadTerminal: 0,
      activeTaskId: ctx().activeRuns.get(queue.id)?.taskId ?? null,
      runnableTaskId: null,
      createdAt: queue.createdAt,
      updatedAt: queue.updatedAt,
    });
  }
  for (const task of tasks) {
    const queueId = ctx().queueIdOf(task);
    let summary = summaries.get(queueId);
    if (summary === undefined) {
      summary = {
        name: queueId,
        total: 0,
        counts: {},
        unreadTerminal: 0,
        activeTaskId: ctx().activeRuns.get(queueId)?.taskId ?? null,
        runnableTaskId: null,
        createdAt: null,
        updatedAt: null,
      };
      summaries.set(queueId, summary);
    }
    summary.total += 1;
    summary.counts[task.status] = (summary.counts[task.status] ?? 0) + 1;
    if (terminalTaskUnread(task)) summary.unreadTerminal += 1;
  }
  for (const [queueId, summary] of summaries) {
    const activeRun = ctx().activeRuns.get(queueId);
    const head = ctx().queueHeadTask(queueId, tasks);
    summary.activeTaskId = activeRun?.taskId ?? null;
    summary.runnableTaskId = head !== null && ctx().queueTaskIsRunnable(head) ? head.id : null;
  }
  const rows = Array.from(summaries.entries()).sort(([left], [right]) => left.localeCompare(right)).map(([queueId, summary]) => {
    return {
      id: queueId,
      name: summary.name,
      total: summary.total,
      counts: summary.counts,
      unreadTerminal: summary.unreadTerminal,
      activeTaskId: summary.activeTaskId,
      runnableTaskId: summary.runnableTaskId,
      processing: ctx().processingQueues.has(queueId),
      createdAt: summary.createdAt,
      updatedAt: summary.updatedAt,
    } as unknown as JsonValue;
  });
  return rows;
}

function queueSummary(includeDevReady = true, tasks: QueueTask[] = ctx().tasks(), queueRecords: QueueRecord[] = ctx().queues()): JsonValue {
  const counts = tasks.reduce<Record<string, number>>((memo, task) => {
    memo[task.status] = (memo[task.status] ?? 0) + 1;
    return memo;
  }, {});
  const unreadTerminal = tasks.reduce((total, task) => total + (terminalTaskUnread(task) ? 1 : 0), 0);
  const activeRunSlots = ctx().activeRunSlotQueueIds();
  const activeTaskIdSet = new Set<string>(Array.from(ctx().activeRuns.values()).map((run) => run.taskId));
  const orphanedActiveTaskIds = tasks
    .filter((task) => (task.status === "running" || task.status === "judging") && !activeTaskIdSet.has(task.id))
    .map((task) => task.id)
    .sort();
  const activeTaskIds = Array.from(activeTaskIdSet).sort();
  const activeTaskId = activeTaskIds[0] ?? null;
  const queues = perQueueSummaries(tasks, queueRecords);
  const executionDiagnostics = buildExecutionDiagnostics({
    controlPlane: "D601-code-queue-scheduler",
    executionStateSource: "scheduler-execution-plane",
    tasks,
    activeRuns: ctx().activeRuns.values(),
    activeRunSlotCount: activeRunSlots.length,
    activeQueueIds: activeRunSlots,
    processingQueueIds: Array.from(ctx().processingQueues),
    orphanedActiveTaskIds,
    oaPublisher: ctx().oaEventPublisherStatus(),
    heartbeatStaleMs: schedulerHeartbeatStaleMs,
  });
  const summary: Record<string, JsonValue> = {
    total: tasks.length,
    defaultQueueId: ctx().defaultQueueId,
    queueCount: queues.length,
    queues,
    activeQueueIds: activeRunSlots,
    processingQueueIds: Array.from(ctx().processingQueues).sort(),
    activeRunSlotCount: activeRunSlots.length,
    activeRunSlotWaiters: ctx().activeRunSlotWaiterSummaries(),
    activeTaskIds,
    activeTaskId,
    orphanedActiveTaskIds,
    orphanedActiveTaskCount: orphanedActiveTaskIds.length,
    processing: ctx().processing(),
    executionDiagnostics: executionDiagnostics as unknown as JsonValue,
    schedulerHeartbeatStaleMs,
    counts,
    unreadTerminal,
    judgeConfigured: ctx().config.minimaxApiKey.length > 0,
    judgeFailRetryLimit: ctx().judgeFailRetryLimit,
    minimaxModel: ctx().config.minimaxModel,
    minimaxJudgeRepairAttempts: ctx().config.judgeRepairAttempts,
    minimaxJudgeMaxTokens: ctx().config.judgeMaxTokens,
    defaultModel: ctx().config.defaultModel,
    codeModels: ctx().config.codeModels,
    codexModels: ctx().config.codexModels,
    opencodeModels: opencodeModelsFor(ctx().config.codeModels),
    modelPorts: codeModelPortsFor(ctx().config.codeModels) as unknown as JsonValue,
    modelProviderConfig: codeModelProviderSourceContract(ctx().config) as unknown as JsonValue,
    executionModes: executionModeOptions(),
    executionModeInfo: Object.fromEntries(codeExecutionModes.map((mode) => [mode, codeExecutionModeInfo(mode)])) as unknown as JsonValue,
    runnerPermissions: {
      observed: true,
      scope: "code-queue-service-config",
      sandbox: ctx().config.sandbox,
      approvalPolicy: ctx().config.approvalPolicy,
      perTaskOverrideSupported: false,
      secretsPrinted: false,
    } as unknown as JsonValue,
    agentPorts: {
      codex: codeAgentPortInfo("codex"),
      opencode: codeAgentPortInfo("opencode"),
    } as unknown as JsonValue,
    defaultReasoningEffort: ctx().config.defaultReasoningEffort,
    modelReasoningEfforts: ctx().config.modelReasoningEfforts,
    defaultProviderId: ctx().config.mainProviderId,
    mainProviderId: ctx().config.mainProviderId,
    defaultWorkdir: ctx().config.defaultWorkdir,
    remoteDefaultWorkdir: ctx().config.remoteDefaultWorkdir,
    windowsNativeCodexDefaultWorkdir: ctx().config.windowsNativeCodexDefaultWorkdir,
    maxActiveQueues: ctx().config.maxActiveQueues,
    executionProviders: executionProviderOptions(),
    defaultWorkdirByProvider: Object.fromEntries((executionProviderOptions() as Array<Record<string, JsonValue>>).map((provider) => [String(provider.id), provider.defaultWorkdir ?? ctx().config.defaultWorkdir])) as JsonValue,
    notifications: {
      claudeqq: {
        enabled: ctx().config.notifyClaudeQqEnabled,
        configured: notificationTargetConfigured(),
        targetType: ctx().config.notifyClaudeQqTargetType,
        target: notificationTargetLabel(),
        baseUrl: ctx().config.notifyClaudeQqBaseUrl,
        maxResponseChars: ctx().config.notifyClaudeQqMaxResponseChars,
        timeoutMs: ctx().config.notifyClaudeQqTimeoutMs,
        sendAttempts: ctx().config.notifyClaudeQqSendAttempts,
        retryIntervalMs: ctx().config.notifyClaudeQqRetryIntervalMs,
        outbox: claudeQqNotificationOutboxStats(),
      },
    },
    storage: {
      primary: "postgres",
      postgresConfigured: true,
      postgresReady: ctx().databaseReady(),
      dirtyTaskCount: ctx().dirtyDatabaseTaskCount(),
      dirtyQueueCount: ctx().dirtyDatabaseQueueCount(),
      lastError: ctx().databaseLastError(),
      health: ctx().databaseStorageHealth(),
      outputArchiveDir: ctx().config.outputArchiveDir,
      inMemoryOutputRecords: ctx().config.maxInMemoryOutputRecords,
      inMemoryEventRecords: ctx().config.maxInMemoryEventRecords,
      codexSqliteLogExport: {
        enabled: ctx().config.codexSqliteLogExportEnabled,
        intervalMs: ctx().config.codexSqliteLogExportIntervalMs,
        batchSize: ctx().config.codexSqliteLogExportBatchSize,
        maxBytes: ctx().config.codexSqliteLogMaxBytes,
        running: ctx().codexSqliteLogExporter().running,
        lastRunAt: ctx().codexSqliteLogExporter().lastRunAt,
        lastExportedRows: ctx().codexSqliteLogExporter().lastExportedRows,
        totalExportedRows: ctx().codexSqliteLogExporter().totalExportedRows,
        lastDeletedRows: ctx().codexSqliteLogExporter().lastDeletedRows,
        lastVacuumAt: ctx().codexSqliteLogExporter().lastVacuumAt,
        lastError: ctx().codexSqliteLogExporter().lastError,
      },
    },
    reconcile: ctx().reconcileStatus(tasks),
  };
  if (includeDevReady) summary.devReady = ctx().collectDevReady();
  return summary;
}

async function loadAllTasksForRead(): Promise<QueueTask[]> {
  if (!ctx().databaseReady()) return ctx().tasks();
  try {
    const tasks = await ctx().loadTasksFromDatabase("all");
    const byId = new Map(tasks.map((task) => [task.id, task]));
    for (const active of ctx().tasks()) {
      const databaseTask = byId.get(active.id);
      if (databaseTask === undefined || preferHotTaskForRead(active, databaseTask)) byId.set(active.id, active);
    }
    ctx().runGarbageCollection();
    return Array.from(byId.values()).sort((left, right) => (timestampMs(left.createdAt) ?? 0) - (timestampMs(right.createdAt) ?? 0) || left.id.localeCompare(right.id));
  } catch (error) {
    rememberReadDatabaseError(error);
    return ctx().tasks();
  }
}

async function queueSummaryForResponse(includeDevReady = true, tasks?: QueueTask[], queueRecords?: QueueRecord[]): Promise<JsonValue> {
  if (tasks !== undefined || queueRecords !== undefined) return queueSummary(includeDevReady, tasks ?? ctx().tasks(), queueRecords ?? ctx().queues());
  return queueSummaryForHealth(includeDevReady);
}

async function queueSummaryForHealth(includeDevReady = true): Promise<JsonValue> {
  let queueRecords = ctx().queues();
  if (ctx().databaseReady()) {
    try {
      queueRecords = await ctx().loadQueuesFromDatabase();
    } catch (error) {
      rememberReadDatabaseError(error);
    }
  }
  const hotTasks = await loadFreshMemoryTasksForRead();
  const summary = queueSummary(includeDevReady, hotTasks, queueRecords) as Record<string, JsonValue>;
  if (!ctx().databaseReady()) return summary;
  let aggregateRows: QueueSummaryAggregateRow[];
  try {
    aggregateRows = await ctx().sql()<QueueSummaryAggregateRow[]>`
      SELECT
        (SELECT COUNT(*) FROM unidesk_code_queue_tasks) AS total,
        COALESCE((
          SELECT jsonb_object_agg(status, count)
          FROM (
            SELECT status, COUNT(*) AS count
            FROM unidesk_code_queue_tasks
            GROUP BY status
          ) AS status_counts
        ), '{}'::jsonb) AS status_counts,
        COALESCE((
          SELECT jsonb_agg(jsonb_build_object('queueId', queue_id, 'status', status, 'count', count))
          FROM (
            SELECT queue_id, status, COUNT(*) AS count
            FROM unidesk_code_queue_tasks
            GROUP BY queue_id, status
          ) AS queue_status_counts
        ), '[]'::jsonb) AS queue_status_counts,
        COALESCE((
          SELECT jsonb_agg(jsonb_build_object('queueId', queue_id, 'count', count))
          FROM (
            SELECT queue_id, COUNT(*) AS count
            FROM unidesk_code_queue_tasks
            WHERE status IN ('succeeded', 'failed', 'canceled')
              AND read_at IS NULL
            GROUP BY queue_id
          ) AS unread_counts
        ), '[]'::jsonb) AS unread_counts
    `;
  } catch (error) {
    rememberReadDatabaseError(error);
    return summary as JsonValue;
  }
  const aggregate = aggregateRows[0] ?? { total: ctx().tasks().length, status_counts: {}, queue_status_counts: [], unread_counts: [] };
  const counts: Record<string, number> = {};
  for (const [status, count] of Object.entries(aggregate.status_counts ?? {})) counts[status] = Number(count);
  const unreadByQueue = new Map((aggregate.unread_counts ?? []).map((row) => [ctx().safeQueueId(String(row.queueId ?? row.queue_id ?? "")), Number(row.count ?? 0)]));
  const summaries = new Map<string, {
    name: string;
    total: number;
    counts: Record<string, number>;
    unreadTerminal: number;
    activeTaskId: string | null;
    runnableTaskId: string | null;
    createdAt: string | null;
    updatedAt: string | null;
  }>();
  for (const queue of queueRecords) {
    summaries.set(queue.id, {
      name: ctx().safeQueueName(queue.name, queue.id),
      total: 0,
      counts: {},
      unreadTerminal: unreadByQueue.get(queue.id) ?? 0,
      activeTaskId: ctx().activeRuns.get(queue.id)?.taskId ?? null,
      runnableTaskId: null,
      createdAt: queue.createdAt,
      updatedAt: queue.updatedAt,
    });
  }
  for (const row of aggregate.queue_status_counts ?? []) {
    const queueId = ctx().safeQueueId(String(row.queueId ?? row.queue_id ?? ""));
    let queue = summaries.get(queueId);
    if (queue === undefined) {
      queue = {
        name: queueId,
        total: 0,
        counts: {},
        unreadTerminal: unreadByQueue.get(queueId) ?? 0,
        activeTaskId: ctx().activeRuns.get(queueId)?.taskId ?? null,
        runnableTaskId: null,
        createdAt: null,
        updatedAt: null,
      };
      summaries.set(queueId, queue);
    }
    const count = Number(row.count ?? 0);
    const status = String(row.status || "");
    queue.counts[status] = count;
    queue.total += count;
  }
  for (const [queueId, queue] of summaries) {
    const activeRun = ctx().activeRuns.get(queueId);
    const head = ctx().queueHeadTask(queueId, hotTasks);
    queue.activeTaskId = activeRun?.taskId ?? null;
    queue.runnableTaskId = head !== null && ctx().queueTaskIsRunnable(head) ? head.id : null;
  }
  const queues = Array.from(summaries.entries()).sort(([left], [right]) => left.localeCompare(right)).map(([id, queue]) => ({
    id,
    name: queue.name,
    total: queue.total,
    counts: queue.counts,
    unreadTerminal: queue.unreadTerminal,
    activeTaskId: queue.activeTaskId,
    runnableTaskId: queue.runnableTaskId,
    processing: ctx().processingQueues.has(id),
    createdAt: queue.createdAt,
    updatedAt: queue.updatedAt,
  })) as unknown as JsonValue[];
  summary.total = Number(aggregate.total ?? ctx().tasks().length);
  summary.counts = counts as unknown as JsonValue;
  summary.unreadTerminal = Array.from(unreadByQueue.values()).reduce((total, count) => total + count, 0);
  summary.queues = queues;
  summary.queueCount = queues.length;
  return summary as JsonValue;
}


function parseNamedLimit(url: URL, name: string, defaultValue: number): number {
  const value = Number(url.searchParams.get(name) ?? defaultValue);
  return Number.isInteger(value) && value > 0 ? Math.min(500, value) : defaultValue;
}

function activePriority(task: QueueTask): number {
  const statusRank: Record<TaskStatus, number> = {
    running: 0,
    judging: 1,
    retry_wait: 2,
    queued: 3,
    succeeded: 9,
    failed: 9,
    canceled: 9,
  };
  return statusRank[task.status] ?? 9;
}

function taskHasClaimMarkers(task: QueueTask): boolean {
  return task.status === "running"
    || task.status === "judging"
    || task.startedAt !== null
    || task.currentAttempt > 0
    || task.codexThreadId !== null
    || task.activeTurnId !== null;
}

function taskIsUnclaimedQueued(task: QueueTask): boolean {
  return (task.status === "queued" || task.status === "retry_wait")
    && task.startedAt === null
    && task.currentAttempt === 0
    && task.codexThreadId === null
    && task.activeTurnId === null;
}

function preferHotTaskForRead(hotTask: QueueTask, databaseTask: QueueTask): boolean {
  const hotActiveRun = Array.from(ctx().activeRuns.values()).some((run) => run.taskId === hotTask.id);
  if (hotActiveRun) return true;
  if (taskIsUnclaimedQueued(hotTask) && taskHasClaimMarkers(databaseTask)) return false;
  return taskUpdatedSortValue(hotTask) >= taskUpdatedSortValue(databaseTask);
}

function taskUpdatedSortValue(task: QueueTask): number {
  const time = Date.parse(task.updatedAt || task.createdAt);
  return Number.isFinite(time) ? time : 0;
}

function taskSearchTerms(url: URL): string[] {
  const query = String(url.searchParams.get("search") ?? url.searchParams.get("q") ?? "")
    .trim()
    .replace(/\s+/gu, " ")
    .slice(0, 200)
    .toLowerCase();
  return query.length === 0 ? [] : query.split(/\s+/u).filter(Boolean);
}

function taskMatchesSearch(task: QueueTask, terms: string[]): boolean {
  if (terms.length === 0) return true;
  const judge = task.lastJudge;
  const queued = queuedStatusPayload(task);
  const haystack = [
    task.id,
    ctx().queueIdOf(task),
    task.status,
    queued.queuedReasonLabel ?? "",
    queued.queuedReason?.code ?? "",
    queued.queuedReason?.message ?? "",
    task.providerId,
    task.executionMode,
    task.cwd,
    task.model,
    task.reasoningEffort ?? "",
    task.basePrompt,
    userPromptForDisplay(task.prompt),
    task.finalResponse,
    task.lastError ?? "",
    judge?.decision ?? "",
    judge?.reason ?? "",
    ...task.referenceTaskIds,
    ...task.promptHistory.map((item) => item.text),
    ...task.output.slice(-50).map((item) => `${item.channel} ${item.method ?? ""} ${item.text}`),
  ].join("\n").toLowerCase();
  return terms.every((term) => haystack.includes(term));
}

function taskPageRows(filteredTasks: QueueTask[], url: URL, limit: number): {
  rows: QueueTask[];
  total: number;
  returned: number;
  hasMore: boolean;
  nextBeforeId: string | null;
  beforeId: string | null;
  includeActive: boolean;
} {
  const beforeId = url.searchParams.get("beforeId");
  const includeActive = url.searchParams.get("includeActive") !== "0";
  const beforeIndex = beforeId === null ? -1 : filteredTasks.findIndex((task) => task.id === beforeId);
  const safeEndIndex = beforeId === null || beforeIndex < 0 ? filteredTasks.length : beforeIndex;
  const pageSource = filteredTasks.slice(Math.max(0, safeEndIndex - limit), safeEndIndex).reverse();
  const unreadTerminalRows = includeActive
    ? filteredTasks
      .filter(terminalTaskUnread)
      .sort((left, right) => taskUpdatedSortValue(right) - taskUpdatedSortValue(left))
    : [];
  const activeRows = includeActive
    ? filteredTasks
      .filter((task) => activePriority(task) < 3)
      .sort((left, right) => {
        const rankDelta = activePriority(left) - activePriority(right);
        if (rankDelta !== 0) return rankDelta;
        return taskUpdatedSortValue(right) - taskUpdatedSortValue(left);
      })
    : [];
  const byId = new Map<string, QueueTask>();
  for (const task of [...unreadTerminalRows, ...activeRows, ...pageSource]) {
    if (!byId.has(task.id)) byId.set(task.id, task);
  }
  const rows = Array.from(byId.values());
  const pageOldest = pageSource.at(-1) ?? null;
  return {
    rows,
    total: filteredTasks.length,
    returned: rows.length,
    hasMore: safeEndIndex - limit > 0,
    nextBeforeId: safeEndIndex - limit > 0 ? pageOldest?.id ?? null : null,
    beforeId,
    includeActive,
  };
}

type TaskIdRow = { id: string; created_at?: Date | string };
type CountRow = { count: string | number };
type QueueSummaryAggregateRow = {
  total: string | number;
  status_counts: Record<string, string | number> | null;
  queue_status_counts: Array<{ queueId?: string; queue_id?: string; status?: string; count?: string | number }> | null;
  unread_counts: Array<{ queueId?: string; queue_id?: string; count?: string | number }> | null;
};
type DailyCountRow = { date: string; count: string | number };
type DailyCompletedRow = {
  date: string;
  status: string;
  count: string | number;
  total_duration_ms: string | number | null;
  duration_samples: string | number;
};

const statsTimeZone = "Asia/Shanghai";
const statsDateFormatter = new Intl.DateTimeFormat("en-CA", {
  timeZone: statsTimeZone,
  year: "numeric",
  month: "2-digit",
  day: "2-digit",
});

function statsDateKey(value: Date | string | null | undefined): string | null {
  const date = value instanceof Date ? value : typeof value === "string" && value.length > 0 ? new Date(value) : null;
  if (date === null || Number.isNaN(date.getTime())) return null;
  const parts = statsDateFormatter.formatToParts(date).reduce<Record<string, string>>((memo, part) => {
    if (part.type !== "literal") memo[part.type] = part.value;
    return memo;
  }, {});
  return parts.year && parts.month && parts.day ? `${parts.year}-${parts.month}-${parts.day}` : null;
}

function shiftStatsDateKey(dateKey: string, offsetDays: number): string {
  const [year = "1970", month = "01", day = "01"] = dateKey.split("-");
  return new Date(Date.UTC(Number(year), Number(month) - 1, Number(day) + offsetDays)).toISOString().slice(0, 10);
}

function statsDateStartUtc(dateKey: string): Date {
  const [year = "1970", month = "01", day = "01"] = dateKey.split("-");
  return new Date(Date.UTC(Number(year), Number(month) - 1, Number(day)) - 8 * 60 * 60 * 1000);
}

function emptyDatabaseStatsBucket(date: string): {
  date: string;
  executedTasks: number;
  completedTasks: number;
  retryAttempts: number;
  succeededTasks: number;
  failedTasks: number;
  canceledTasks: number;
  totalDurationMs: number;
  durationSamples: number;
} {
  return {
    date,
    executedTasks: 0,
    completedTasks: 0,
    retryAttempts: 0,
    succeededTasks: 0,
    failedTasks: 0,
    canceledTasks: 0,
    totalDurationMs: 0,
    durationSamples: 0,
  };
}

function databaseStatsRange(url: URL): { days: number; startDate: string; endDate: string; startAt: string; endAt: string } {
  const generatedAt = new Date();
  const endDate = statsDateKey(generatedAt) ?? generatedAt.toISOString().slice(0, 10);
  const days = Math.max(1, Math.min(90, Math.floor(statsDaysFromUrl(url))));
  const startDate = shiftStatsDateKey(endDate, 1 - days);
  const endExclusiveDate = shiftStatsDateKey(endDate, 1);
  return {
    days,
    startDate,
    endDate,
    startAt: statsDateStartUtc(startDate).toISOString(),
    endAt: statsDateStartUtc(endExclusiveDate).toISOString(),
  };
}

const statisticsCache = new Map<string, { expiresAt: number; value: JsonValue }>();

async function databaseTaskStatisticsSummary(queueId: string | null, url: URL): Promise<JsonValue> {
  const range = databaseStatsRange(url);
  const cacheKey = `${queueId ?? "all"}:${range.days}:${range.startDate}`;
  const now = Date.now();
  const cached = statisticsCache.get(cacheKey);
  if (cached !== undefined && cached.expiresAt > now) return cached.value;
  const generatedAt = new Date().toISOString();
  const buckets = new Map<string, ReturnType<typeof emptyDatabaseStatsBucket>>();
  for (let offset = 0; offset < range.days; offset += 1) {
    const date = shiftStatsDateKey(range.startDate, offset);
    buckets.set(date, emptyDatabaseStatsBucket(date));
  }
  const [executedRows, completedRows, retryRows] = queueId === null
    ? await Promise.all([
      ctx().sql()<DailyCountRow[]>`
        SELECT to_char(started_at AT TIME ZONE 'Asia/Shanghai', 'YYYY-MM-DD') AS date, COUNT(*) AS count
        FROM unidesk_code_queue_tasks
        WHERE started_at >= ${range.startAt}
          AND started_at < ${range.endAt}
        GROUP BY date
      `,
      ctx().sql()<DailyCompletedRow[]>`
        SELECT
          to_char(COALESCE(finished_at, updated_at) AT TIME ZONE 'Asia/Shanghai', 'YYYY-MM-DD') AS date,
          status,
          COUNT(*) AS count,
          SUM(GREATEST(EXTRACT(EPOCH FROM (COALESCE(finished_at, updated_at) - COALESCE(started_at, created_at))) * 1000, 0)) AS total_duration_ms,
          COUNT(CASE WHEN COALESCE(started_at, created_at) IS NOT NULL THEN 1 END) AS duration_samples
        FROM unidesk_code_queue_tasks
        WHERE status IN ('succeeded', 'failed', 'canceled')
          AND COALESCE(finished_at, updated_at) >= ${range.startAt}
          AND COALESCE(finished_at, updated_at) < ${range.endAt}
        GROUP BY date, status
      `,
      ctx().sql()<DailyCountRow[]>`
        SELECT
          to_char(updated_at AT TIME ZONE 'Asia/Shanghai', 'YYYY-MM-DD') AS date,
          SUM(GREATEST(current_attempt - 1, attempt_count - 1, 0)) AS count
        FROM unidesk_code_queue_tasks
        WHERE updated_at >= ${range.startAt}
          AND updated_at < ${range.endAt}
          AND GREATEST(current_attempt - 1, attempt_count - 1, 0) > 0
        GROUP BY date
      `,
    ])
    : await Promise.all([
      ctx().sql()<DailyCountRow[]>`
        SELECT to_char(started_at AT TIME ZONE 'Asia/Shanghai', 'YYYY-MM-DD') AS date, COUNT(*) AS count
        FROM unidesk_code_queue_tasks
        WHERE queue_id = ${queueId}
          AND started_at >= ${range.startAt}
          AND started_at < ${range.endAt}
        GROUP BY date
      `,
      ctx().sql()<DailyCompletedRow[]>`
        SELECT
          to_char(COALESCE(finished_at, updated_at) AT TIME ZONE 'Asia/Shanghai', 'YYYY-MM-DD') AS date,
          status,
          COUNT(*) AS count,
          SUM(GREATEST(EXTRACT(EPOCH FROM (COALESCE(finished_at, updated_at) - COALESCE(started_at, created_at))) * 1000, 0)) AS total_duration_ms,
          COUNT(CASE WHEN COALESCE(started_at, created_at) IS NOT NULL THEN 1 END) AS duration_samples
        FROM unidesk_code_queue_tasks
        WHERE queue_id = ${queueId}
          AND status IN ('succeeded', 'failed', 'canceled')
          AND COALESCE(finished_at, updated_at) >= ${range.startAt}
          AND COALESCE(finished_at, updated_at) < ${range.endAt}
        GROUP BY date, status
      `,
      ctx().sql()<DailyCountRow[]>`
        SELECT
          to_char(updated_at AT TIME ZONE 'Asia/Shanghai', 'YYYY-MM-DD') AS date,
          SUM(GREATEST(current_attempt - 1, attempt_count - 1, 0)) AS count
        FROM unidesk_code_queue_tasks
        WHERE queue_id = ${queueId}
          AND updated_at >= ${range.startAt}
          AND updated_at < ${range.endAt}
          AND GREATEST(current_attempt - 1, attempt_count - 1, 0) > 0
        GROUP BY date
      `,
    ]);

  for (const row of executedRows) {
    const bucket = buckets.get(row.date);
    if (bucket !== undefined) bucket.executedTasks += Number(row.count);
  }
  for (const row of retryRows) {
    const bucket = buckets.get(row.date);
    if (bucket !== undefined) bucket.retryAttempts += Number(row.count);
  }
  for (const row of completedRows) {
    const bucket = buckets.get(row.date);
    if (bucket === undefined) continue;
    const count = Number(row.count);
    bucket.completedTasks += count;
    if (row.status === "succeeded") bucket.succeededTasks += count;
    if (row.status === "failed") bucket.failedTasks += count;
    if (row.status === "canceled") bucket.canceledTasks += count;
    bucket.totalDurationMs += Math.round(Number(row.total_duration_ms ?? 0));
    bucket.durationSamples += Number(row.duration_samples);
  }
  const daily = Array.from(buckets.values()).map((bucket) => ({
    ...bucket,
    avgDurationMs: bucket.durationSamples > 0 ? Math.round(bucket.totalDurationMs / bucket.durationSamples) : null,
  }));
  const totals = daily.reduce((memo, day) => {
    memo.executedTasks += day.executedTasks;
    memo.completedTasks += day.completedTasks;
    memo.retryAttempts += day.retryAttempts;
    memo.succeededTasks += day.succeededTasks;
    memo.failedTasks += day.failedTasks;
    memo.canceledTasks += day.canceledTasks;
    memo.totalDurationMs += day.totalDurationMs;
    memo.durationSamples += day.durationSamples;
    return memo;
  }, {
    executedTasks: 0,
    completedTasks: 0,
    retryAttempts: 0,
    succeededTasks: 0,
    failedTasks: 0,
    canceledTasks: 0,
    totalDurationMs: 0,
    durationSamples: 0,
  });
  const result = {
    generatedAt,
    timezone: statsTimeZone,
    days: range.days,
    range: { startDate: range.startDate, endDate: range.endDate },
    totals: {
      ...totals,
      avgDurationMs: totals.durationSamples > 0 ? Math.round(totals.totalDurationMs / totals.durationSamples) : null,
    },
    daily,
  } as unknown as JsonValue;
  statisticsCache.set(cacheKey, { expiresAt: now + 10_000, value: result });
  if (statisticsCache.size > 20) {
    for (const [key, entry] of statisticsCache) {
      if (entry.expiresAt <= now) statisticsCache.delete(key);
    }
  }
  return result;
}

async function databaseTaskTotal(queueId: string | null): Promise<number> {
  const rows = queueId === null
    ? await ctx().sql()<CountRow[]>`SELECT COUNT(*) AS count FROM unidesk_code_queue_tasks`
    : await ctx().sql()<CountRow[]>`SELECT COUNT(*) AS count FROM unidesk_code_queue_tasks WHERE queue_id = ${queueId}`;
  return Number(rows[0]?.count ?? 0);
}

async function databaseCursor(beforeId: string | null): Promise<TaskIdRow | null> {
  if (beforeId === null || beforeId.length === 0) return null;
  const rows = await ctx().sql()<TaskIdRow[]>`
    SELECT id, created_at
    FROM unidesk_code_queue_tasks
    WHERE id = ${beforeId}
    LIMIT 1
  `;
  return rows[0] ?? null;
}

async function databasePageTaskIds(queueId: string | null, beforeId: string | null, limit: number): Promise<{
  ids: string[];
  total: number;
  hasMore: boolean;
  nextBeforeId: string | null;
}> {
  const [total, cursor] = await Promise.all([databaseTaskTotal(queueId), databaseCursor(beforeId)]);
  const fetchLimit = limit + 1;
  let rows: TaskIdRow[];
  if (cursor === null && queueId === null) {
    rows = await ctx().sql()<TaskIdRow[]>`
        SELECT id
        FROM unidesk_code_queue_tasks
        ORDER BY created_at DESC, id DESC
        LIMIT ${fetchLimit}
      `;
  } else if (cursor === null) {
    rows = await ctx().sql()<TaskIdRow[]>`
        SELECT id
        FROM unidesk_code_queue_tasks
        WHERE queue_id = ${queueId}
        ORDER BY created_at DESC, id DESC
        LIMIT ${fetchLimit}
      `;
  } else if (queueId === null) {
    rows = await ctx().sql()<TaskIdRow[]>`
        SELECT id
        FROM unidesk_code_queue_tasks
        WHERE (created_at, id) < (${cursor.created_at ?? new Date(0)}, ${cursor.id})
        ORDER BY created_at DESC, id DESC
        LIMIT ${fetchLimit}
      `;
  } else {
    rows = await ctx().sql()<TaskIdRow[]>`
        SELECT id
        FROM unidesk_code_queue_tasks
        WHERE queue_id = ${queueId}
          AND (created_at, id) < (${cursor.created_at ?? new Date(0)}, ${cursor.id})
        ORDER BY created_at DESC, id DESC
        LIMIT ${fetchLimit}
      `;
  }
  const ids = rows.slice(0, limit).map((row) => row.id);
  const hasMore = rows.length > limit;
  return {
    ids,
    total,
    hasMore,
    nextBeforeId: hasMore ? ids.at(-1) ?? null : null,
  };
}

async function databasePriorityTaskIds(queueId: string | null, limit: number): Promise<string[]> {
  const [unreadRows, activeRows] = queueId === null
    ? await Promise.all([
      ctx().sql()<TaskIdRow[]>`
        SELECT id
        FROM unidesk_code_queue_tasks
        WHERE status IN ('succeeded', 'failed', 'canceled')
          AND read_at IS NULL
        ORDER BY updated_at DESC, id DESC
        LIMIT ${limit}
      `,
      ctx().sql()<TaskIdRow[]>`
        SELECT id
        FROM unidesk_code_queue_tasks
        WHERE status IN ('running', 'judging', 'retry_wait')
        ORDER BY CASE status WHEN 'running' THEN 0 WHEN 'judging' THEN 1 ELSE 2 END, updated_at DESC, id DESC
        LIMIT ${limit}
      `,
    ])
    : await Promise.all([
      ctx().sql()<TaskIdRow[]>`
        SELECT id
        FROM unidesk_code_queue_tasks
        WHERE queue_id = ${queueId}
          AND status IN ('succeeded', 'failed', 'canceled')
          AND read_at IS NULL
        ORDER BY updated_at DESC, id DESC
        LIMIT ${limit}
      `,
      ctx().sql()<TaskIdRow[]>`
        SELECT id
        FROM unidesk_code_queue_tasks
        WHERE queue_id = ${queueId}
          AND status IN ('running', 'judging', 'retry_wait')
        ORDER BY CASE status WHEN 'running' THEN 0 WHEN 'judging' THEN 1 ELSE 2 END, updated_at DESC, id DESC
        LIMIT ${limit}
      `,
    ]);
  return [...unreadRows.map((row) => row.id), ...activeRows.map((row) => row.id)];
}

function taskMatchesQueueFilter(task: QueueTask, queueId: string | null): boolean {
  return queueId === null || ctx().queueIdOf(task) === queueId;
}

function pushUniqueId(ids: string[], seen: Set<string>, id: string): void {
  if (id.length === 0 || seen.has(id)) return;
  seen.add(id);
  ids.push(id);
}

async function databaseTasksOverviewResponse(url: URL): Promise<Response | null> {
  if (!ctx().databaseReady()) return null;
  const searchTerms = taskSearchTerms(url);
  if (searchTerms.length > 0) return null;
  const limit = ctx().parseLimit(url);
  const compact = ctx().truthyParam(url, "compact");
  const queueFilter = url.searchParams.get("queueId");
  const queueId = queueFilter === null ? null : ctx().safeQueueId(queueFilter);
  const includeActive = url.searchParams.get("includeActive") !== "0";
  const includeSelected = url.searchParams.get("selected") !== "0";
  const includeStatistics = url.searchParams.get("stats") !== "0";
  const priorityLimit = parseNamedLimit(url, "priorityLimit", Math.max(100, limit));
  const beforeId = url.searchParams.get("beforeId");
  let queue: JsonValue;
  let statistics: JsonValue | null;
  let page: { ids: string[]; total: number; hasMore: boolean; nextBeforeId: string | null };
  let priorityIds: string[];
  try {
    [queue, statistics, page, priorityIds] = await Promise.all([
      queueSummaryForResponse(false),
      includeStatistics ? databaseTaskStatisticsSummary(queueId, url) : Promise.resolve(null),
      databasePageTaskIds(queueId, beforeId, limit),
      includeActive ? databasePriorityTaskIds(queueId, priorityLimit) : Promise.resolve([]),
    ]);
  } catch (error) {
    rememberReadDatabaseError(error);
    return null;
  }
  const orderedIds: string[] = [];
  const seenIds = new Set<string>();
  for (const id of priorityIds) pushUniqueId(orderedIds, seenIds, id);
  for (const id of page.ids) pushUniqueId(orderedIds, seenIds, id);
  for (const task of ctx().tasks()) {
    if (!includeActive || !taskMatchesQueueFilter(task, queueId)) continue;
    if (terminalTaskUnread(task) || activePriority(task) < 3) pushUniqueId(orderedIds, seenIds, task.id);
  }
  let loadedTasks: QueueTask[];
  try {
    loadedTasks = await ctx().loadTasksFromDatabaseByIds(orderedIds);
  } catch (error) {
    rememberReadDatabaseError(error);
    return null;
  }
  const byId = new Map<string, QueueTask>();
  for (const task of loadedTasks) byId.set(task.id, task);
  for (const task of ctx().tasks()) {
    const databaseTask = byId.get(task.id);
    if ((seenIds.has(task.id) || databaseTask !== undefined) && (databaseTask === undefined || preferHotTaskForRead(task, databaseTask))) byId.set(task.id, task);
  }
  const rowsSource = orderedIds
    .map((id) => byId.get(id) ?? null)
    .filter((task): task is QueueTask => task !== null && taskMatchesQueueFilter(task, queueId));
  const queueRecord = queue as Record<string, JsonValue>;
  const preferId = url.searchParams.get("preferId") ?? "";
  const activeTaskId = typeof queueRecord.activeTaskId === "string" ? queueRecord.activeTaskId : "";
  const selectedCandidates = includeSelected ? [preferId, activeTaskId, rowsSource[0]?.id ?? ""] : [];
  let selectedTask: QueueTask | null = null;
  for (const id of selectedCandidates) {
    if (id.length === 0) continue;
    const candidate = await loadTaskForReadByFreshness(id);
    if (candidate !== null && taskMatchesQueueFilter(candidate, queueId)) {
      selectedTask = candidate;
      break;
    }
  }
  let selected: JsonValue = null;
  if (selectedTask !== null) {
    const afterSeqRaw = Number(url.searchParams.get("afterSeq") ?? 0);
    const afterSeq = Number.isFinite(afterSeqRaw) ? afterSeqRaw : 0;
    const transcriptLimit = parseNamedLimit(url, "transcriptLimit", 500);
    const transcript = compact
      ? buildCompactTaskTranscript(selectedTask, transcriptLimit, Math.max(12, transcriptLimit * 3))
      : buildTaskTranscript(selectedTask, transcriptLimit, 0);
    const chunk = transcript.filter((line) => Number(line.seq) > afterSeq).slice(0, transcriptLimit);
    const nextAfterSeq = chunk.at(-1)?.seq ?? afterSeq;
    const outputMaxSeq = selectedTask.output.at(-1)?.seq ?? 0;
    const promptHistoryMaxSeq = selectedTask.promptHistory.at(-1)?.seq ?? 0;
    const maxSeq = Math.max(outputMaxSeq, promptHistoryMaxSeq, transcript.at(-1)?.seq ?? 0);
    selected = {
      task: compact ? taskForCompactMetaResponse(selectedTask) : taskForMetaResponse(selectedTask),
      transcript: chunk,
      afterSeq,
      nextAfterSeq,
      hasMore: maxSeq > Number(nextAfterSeq),
      preview: true,
      total: transcript.length,
      maxSeq,
    } as unknown as JsonValue;
  }
  const queueContextTasks = [...ctx().tasks(), ...rowsSource];
  const includeTrace = url.searchParams.get("skipTrace") !== "1";
  const traceStats = includeTrace
    ? await ctx().traceStatsForTasks(taskIdsForStats(rowsSource, selectedTask))
    : new Map<string, OaTraceStats>();
  if (selectedTask !== null && selected !== null && typeof selected === "object" && !Array.isArray(selected)) {
    const selectedRecord = selected as Record<string, JsonValue>;
    selectedRecord.task = applyStats(selectedRecord.task, traceStats, selectedTask);
  }
  return ctx().compactJsonResponse({
    ok: true,
    queue,
    statistics,
    tasks: rowsSource.map((task) => applyStats(taskForListResponse(task, true, queueContextTasks), traceStats, task)),
    selected,
    pagination: {
      limit,
      returned: rowsSource.length,
      total: page.total,
      hasMore: page.hasMore,
      nextBeforeId: page.nextBeforeId,
      beforeId,
      includeActive,
      priorityLimit,
    },
  });
}

async function tasksOverviewResponse(url: URL): Promise<Response> {
  const databaseResponse = await databaseTasksOverviewResponse(url);
  if (databaseResponse !== null) return databaseResponse;
  const limit = ctx().parseLimit(url);
  const compact = ctx().truthyParam(url, "compact");
  const queueFilter = url.searchParams.get("queueId");
  const searchTerms = taskSearchTerms(url);
  const allTasks = await loadAllTasksForRead();
  const filteredTasks = allTasks
    .filter((task) => queueFilter === null || ctx().queueIdOf(task) === ctx().safeQueueId(queueFilter))
    .filter((task) => taskMatchesSearch(task, searchTerms));
  const page = taskPageRows(filteredTasks, url, limit);
  const rowsSource = page.rows;
  const queue = queueSummary(false, allTasks) as Record<string, JsonValue>;
  const preferId = url.searchParams.get("preferId") ?? "";
  const activeTaskId = typeof queue.activeTaskId === "string" ? queue.activeTaskId : "";
  const selectedTask = filteredTasks.find((task) => task.id === preferId)
    ?? filteredTasks.find((task) => task.id === activeTaskId)
    ?? rowsSource[0]
    ?? null;
  let selected: JsonValue = null;
  if (selectedTask !== null) {
    const afterSeqRaw = Number(url.searchParams.get("afterSeq") ?? 0);
    const afterSeq = Number.isFinite(afterSeqRaw) ? afterSeqRaw : 0;
    const transcriptLimit = parseNamedLimit(url, "transcriptLimit", 500);
    const transcript = compact
      ? buildCompactTaskTranscript(selectedTask, transcriptLimit, Math.max(12, transcriptLimit * 3))
      : buildTaskTranscript(selectedTask, transcriptLimit, 0);
    const chunk = transcript.filter((line) => Number(line.seq) > afterSeq).slice(0, transcriptLimit);
    const nextAfterSeq = chunk.at(-1)?.seq ?? afterSeq;
    const outputMaxSeq = selectedTask.output.at(-1)?.seq ?? 0;
    const promptHistoryMaxSeq = selectedTask.promptHistory.at(-1)?.seq ?? 0;
    const maxSeq = Math.max(outputMaxSeq, promptHistoryMaxSeq, transcript.at(-1)?.seq ?? 0);
    selected = {
      task: compact ? taskForCompactMetaResponse(selectedTask) : taskForMetaResponse(selectedTask),
      transcript: chunk,
      afterSeq,
      nextAfterSeq,
      hasMore: maxSeq > Number(nextAfterSeq),
      preview: true,
      total: transcript.length,
      maxSeq,
    } as unknown as JsonValue;
  }
  const includeTrace = url.searchParams.get("skipTrace") !== "1";
  const traceStats = includeTrace
    ? await ctx().traceStatsForTasks(taskIdsForStats(rowsSource, selectedTask))
    : new Map<string, OaTraceStats>();
  if (selectedTask !== null && selected !== null && typeof selected === "object" && !Array.isArray(selected)) {
    const selectedRecord = selected as Record<string, JsonValue>;
    selectedRecord.task = applyStats(selectedRecord.task, traceStats, selectedTask);
  }
  return ctx().compactJsonResponse({
    ok: true,
    queue,
    statistics: taskStatisticsSummary(filteredTasks, statsDaysFromUrl(url)),
    tasks: rowsSource.map((task) => applyStats(taskForListResponse(task, true, allTasks), traceStats, task)),
    selected,
    pagination: {
      limit,
      returned: page.returned,
      total: page.total,
      hasMore: page.hasMore,
      nextBeforeId: page.nextBeforeId,
      beforeId: page.beforeId,
      includeActive: page.includeActive,
    },
  });
}


export {
  loadAllTasksForRead,
  outputChunkResponse,
  perQueueSummaries,
  queueSummary,
  queueSummaryForHealth,
  queueSummaryForResponse,
  taskMatchesSearch,
  taskPageRows,
  taskSearchTerms,
  tasksOverviewResponse,
  taskForListResponse,
  transcriptChunkResponse,
};
