1393 lines · 40.3 KB · TypeScript
RawDownload
import * as Option from "effect/Option";import * as Arr from "effect/Array";import {  ApprovalRequestId,  isToolLifecycleItemType,  type OrchestrationLatestTurn,  type OrchestrationThreadActivity,  type OrchestrationProposedPlanId,  ProviderDriverKind,  type ToolLifecycleItemType,  type UserInputQuestion,  type ThreadId,  type TurnId,} from "@t3tools/contracts"; import type {  ChatMessage,  ProposedPlan,  SessionPhase,  Thread,  ThreadSession,  TurnDiffSummary,} from "./types"; export type ProviderPickerKind = ProviderDriverKind; export const PROVIDER_OPTIONS: Array<{  value: ProviderPickerKind;  label: string;  available: boolean;  /** Shown on the model picker sidebar when relevant */  pickerSidebarBadge?: "new" | "soon";}> = [  { value: ProviderDriverKind.make("codex"), label: "Codex", available: true },  { value: ProviderDriverKind.make("claudeAgent"), label: "Claude", available: true },  {    value: ProviderDriverKind.make("opencode"),    label: "OpenCode",    available: true,    pickerSidebarBadge: "new",  },  {    value: ProviderDriverKind.make("cursor"),    label: "Cursor",    available: true,    pickerSidebarBadge: "new",  },  {    value: ProviderDriverKind.make("grok"),    label: "Grok",    available: true,    pickerSidebarBadge: "new",  },]; export type WorkLogToolLifecycleStatus =  | "inProgress"  | "completed"  | "failed"  | "declined"  | "stopped"; export interface WorkLogEntry {  id: string;  createdAt: string;  turnId?: TurnId | null;  label: string;  detail?: string;  command?: string;  rawCommand?: string;  changedFiles?: ReadonlyArray<string>;  tone: "thinking" | "tool" | "info" | "error";  toolTitle?: string;  toolData?: unknown;  itemType?: ToolLifecycleItemType;  requestKind?: PendingApproval["requestKind"];  /** From runtime item / task payload `status` when present (e.g. tool.updated). */  toolLifecycleStatus?: WorkLogToolLifecycleStatus;  /** Originating orchestration activity kind (e.g. `user-input.requested`) for row chrome. */  sourceActivityKind?: OrchestrationThreadActivity["kind"];} interface DerivedWorkLogEntry extends WorkLogEntry {  activityKind: OrchestrationThreadActivity["kind"];  collapseKey?: string;  toolCallId?: string;} export interface PendingApproval {  requestId: ApprovalRequestId;  requestKind: "command" | "file-read" | "file-change";  createdAt: string;  detail?: string;} export interface PendingUserInput {  requestId: ApprovalRequestId;  createdAt: string;  questions: ReadonlyArray<UserInputQuestion>;} export interface ActivePlanState {  createdAt: string;  turnId: TurnId | null;  explanation?: string | null;  steps: Array<{    step: string;    status: "pending" | "inProgress" | "completed";  }>;} export interface LatestProposedPlanState {  id: OrchestrationProposedPlanId;  createdAt: string;  updatedAt: string;  turnId: TurnId | null;  planMarkdown: string;  implementedAt: string | null;  implementationThreadId: ThreadId | null;} export type TimelineEntry =  | {      id: string;      kind: "message";      createdAt: string;      message: ChatMessage;    }  | {      id: string;      kind: "proposed-plan";      createdAt: string;      proposedPlan: ProposedPlan;    }  | {      id: string;      kind: "work";      createdAt: string;      entry: WorkLogEntry;    }; export function workLogEntryIsToolLike(entry: WorkLogEntry): boolean {  if (entry.tone === "tool" || entry.tone === "thinking" || entry.tone === "error") {    return true;  }  if (entry.command !== undefined && entry.command.trim().length > 0) {    return true;  }  if (entry.requestKind !== undefined) {    return true;  }  return entry.itemType !== undefined && isToolLifecycleItemType(entry.itemType);} /** Heuristic: providers often emit successful lifecycle status while error text lives in `detail` / `command`. */function toolDetailTextLooksLikeFailure(text: string): boolean {  const t = text.toLowerCase();  if (t.includes("file not found")) {    return true;  }  if (t.includes("no files found")) {    return true;  }  if (    t.includes("enoent") ||    t.includes("no such file or directory") ||    t.includes("no such file")  ) {    return true;  }  if (t.includes("cannot find path") && t.includes("because it does not exist")) {    return true;  }  if (t.includes("commandnotfoundexception")) {    return true;  }  if (t.includes("is not recognized as the name of a cmdlet")) {    return true;  }  if (t.includes("is not recognized") && t.includes("the term '")) {    return true;  }  if (t.includes("a parameter cannot be found that matches parameter name")) {    return true;  }  if (t.includes("command not found")) {    return true;  }  if (/<exited with exit code\s+[1-9]\d*\s*>/i.test(text)) {    return true;  }  if (/exit(?:ed)? with exit code\s+[1-9]\d*/i.test(text)) {    return true;  }  if (/exit code\s*[:\s]\s*[1-9]\d*\b/i.test(text)) {    return true;  }  return false;} /** True when the row should show a failure affordance (explicit status/tone or error-shaped tool output). */export function workEntryIndicatesToolFailure(entry: WorkLogEntry): boolean {  if (entry.tone === "error") {    return true;  }  const ls = entry.toolLifecycleStatus;  if (ls === "failed" || ls === "declined") {    return true;  }  if (!workLogEntryIsToolLike(entry)) {    return false;  }  const parts: string[] = [];  if (entry.detail) {    parts.push(entry.detail);  }  if (entry.command) {    parts.push(entry.command);  }  const blob = parts.join("\n");  if (blob.length === 0) {    return false;  }  return toolDetailTextLooksLikeFailure(blob);} /** Tool/command row completed without failure (blue check affordance). */export function workEntryIndicatesToolSuccess(entry: WorkLogEntry): boolean {  if (!workLogEntryIsToolLike(entry)) {    return false;  }  if (workEntryIndicatesToolFailure(entry)) {    return false;  }  if (entry.tone === "thinking") {    return false;  }  const ls = entry.toolLifecycleStatus;  if (ls === "failed" || ls === "declined") {    return false;  }  if (ls === "inProgress") {    return false;  }  if (ls === "stopped") {    return false;  }  return true;} /** Tool-like row with neither clear success nor failure (empty, incomplete, in progress, etc.). */export function workEntryIndicatesToolNeutralStatus(entry: WorkLogEntry): boolean {  if (!workLogEntryIsToolLike(entry)) {    return false;  }  if (workEntryIndicatesToolFailure(entry)) {    return false;  }  if (workEntryIndicatesToolSuccess(entry)) {    return false;  }  return true;} export function formatDuration(durationMs: number): string {  if (!Number.isFinite(durationMs) || durationMs < 0) return "0ms";  if (durationMs < 1_000) return `${Math.max(1, Math.round(durationMs))}ms`;  if (durationMs < 10_000) {    const tenths = Math.round(durationMs / 100) / 10;    // 9.95s+ rounds up to the next bucket — render "10s", not "10.0s".    return tenths >= 10 ? "10s" : `${tenths.toFixed(1)}s`;  }  if (durationMs < 60_000) return `${Math.round(durationMs / 1_000)}s`;  const minutes = Math.floor(durationMs / 60_000);  const seconds = Math.round((durationMs % 60_000) / 1_000);  if (seconds === 0) return `${minutes}m`;  if (seconds === 60) return `${minutes + 1}m`;  return `${minutes}m ${seconds}s`;} export function formatElapsed(startIso: string, endIso: string | undefined): string | null {  if (!endIso) return null;  const startedAt = Date.parse(startIso);  const endedAt = Date.parse(endIso);  if (Number.isNaN(startedAt) || Number.isNaN(endedAt) || endedAt < startedAt) {    return null;  }  return formatDuration(endedAt - startedAt);} type LatestTurnTiming = Pick<OrchestrationLatestTurn, "turnId" | "startedAt" | "completedAt">;type SessionActivityState = Pick<NonNullable<Thread["session"]>, "status" | "activeTurnId">; export function isLatestTurnSettled(  latestTurn: LatestTurnTiming | null,  session: SessionActivityState | null,): boolean {  if (!latestTurn?.startedAt) return false;  if (!latestTurn.completedAt) return false;  if (!session) return true;  if (session.status === "running") return false;  return true;} export function deriveActiveWorkStartedAt(  latestTurn: LatestTurnTiming | null,  session: SessionActivityState | null,  sendStartedAt: string | null,): string | null {  const runningTurnId = session?.status === "running" ? session.activeTurnId : null;  if (runningTurnId !== null) {    if (latestTurn?.turnId === runningTurnId) {      return latestTurn.startedAt ?? sendStartedAt;    }    return sendStartedAt;  }  if (!isLatestTurnSettled(latestTurn, session)) {    return latestTurn?.startedAt ?? sendStartedAt;  }  return sendStartedAt;} function requestKindFromRequestType(requestType: unknown): PendingApproval["requestKind"] | null {  switch (requestType) {    case "command_execution_approval":    case "exec_command_approval":    case "dynamic_tool_call":      return "command";    case "file_read_approval":      return "file-read";    case "file_change_approval":    case "apply_patch_approval":      return "file-change";    default:      return null;  }} function isStalePendingRequestFailureDetail(detail: string | undefined): boolean {  const normalized = detail?.toLowerCase();  if (!normalized) {    return false;  }  return (    normalized.includes("stale pending approval request") ||    normalized.includes("stale pending user-input request") ||    normalized.includes("unknown pending approval request") ||    normalized.includes("unknown pending permission request") ||    normalized.includes("unknown pending user-input request") ||    normalized.includes("unknown pending user input request") ||    normalized.includes("unknown pending codex user input request")  );} export function derivePendingApprovals(  activities: ReadonlyArray<OrchestrationThreadActivity>,): PendingApproval[] {  const openByRequestId = new Map<ApprovalRequestId, PendingApproval>();  const ordered = [...activities].toSorted(compareActivitiesByOrder);   for (const activity of ordered) {    const payload =      activity.payload && typeof activity.payload === "object"        ? (activity.payload as Record<string, unknown>)        : null;    const requestId =      payload && typeof payload.requestId === "string"        ? ApprovalRequestId.make(payload.requestId)        : null;    const requestKind =      payload &&      (payload.requestKind === "command" ||        payload.requestKind === "file-read" ||        payload.requestKind === "file-change")        ? payload.requestKind        : payload          ? requestKindFromRequestType(payload.requestType)          : null;    const detail = payload && typeof payload.detail === "string" ? payload.detail : undefined;     if (activity.kind === "approval.requested" && requestId && requestKind) {      openByRequestId.set(requestId, {        requestId,        requestKind,        createdAt: activity.createdAt,        ...(detail ? { detail } : {}),      });      continue;    }     if (activity.kind === "approval.resolved" && requestId) {      openByRequestId.delete(requestId);      continue;    }     if (      activity.kind === "provider.approval.respond.failed" &&      requestId &&      isStalePendingRequestFailureDetail(detail)    ) {      openByRequestId.delete(requestId);      continue;    }  }   return [...openByRequestId.values()].toSorted((left, right) =>    left.createdAt.localeCompare(right.createdAt),  );} function parseUserInputQuestions(  payload: Record<string, unknown> | null,): ReadonlyArray<UserInputQuestion> | null {  const questions = payload?.questions;  if (!Array.isArray(questions)) {    return null;  }  const parsed = questions    .map<UserInputQuestion | null>((entry) => {      if (!entry || typeof entry !== "object") return null;      const question = entry as Record<string, unknown>;      if (        typeof question.id !== "string" ||        typeof question.header !== "string" ||        typeof question.question !== "string" ||        !Array.isArray(question.options)      ) {        return null;      }      const options = question.options        .map<UserInputQuestion["options"][number] | null>((option) => {          if (!option || typeof option !== "object") return null;          const optionRecord = option as Record<string, unknown>;          if (            typeof optionRecord.label !== "string" ||            typeof optionRecord.description !== "string"          ) {            return null;          }          return {            label: optionRecord.label,            description: optionRecord.description,          };        })        .filter((option): option is UserInputQuestion["options"][number] => option !== null);      if (options.length === 0) {        return null;      }      return {        id: question.id,        header: question.header,        question: question.question,        options,        multiSelect: question.multiSelect === true,      };    })    .filter((question): question is UserInputQuestion => question !== null);  return parsed.length > 0 ? parsed : null;} export function derivePendingUserInputs(  activities: ReadonlyArray<OrchestrationThreadActivity>,): PendingUserInput[] {  const openByRequestId = new Map<ApprovalRequestId, PendingUserInput>();  const ordered = [...activities].toSorted(compareActivitiesByOrder);   for (const activity of ordered) {    const payload =      activity.payload && typeof activity.payload === "object"        ? (activity.payload as Record<string, unknown>)        : null;    const requestId =      payload && typeof payload.requestId === "string"        ? ApprovalRequestId.make(payload.requestId)        : null;    const detail = payload && typeof payload.detail === "string" ? payload.detail : undefined;     if (activity.kind === "user-input.requested" && requestId) {      const questions = parseUserInputQuestions(payload);      if (!questions) {        continue;      }      openByRequestId.set(requestId, {        requestId,        createdAt: activity.createdAt,        questions,      });      continue;    }     if (activity.kind === "user-input.resolved" && requestId) {      openByRequestId.delete(requestId);      continue;    }     if (      activity.kind === "provider.user-input.respond.failed" &&      requestId &&      isStalePendingRequestFailureDetail(detail)    ) {

Lines 1–500 of 1393.