import { getTerminalLabel } from "@t3tools/shared/terminalLabels";import * as Schema from "effect/Schema";import { confirmTerminalClose, isTerminalCloseConfirmPending } from "../lib/terminalCloseConfirm";import { Minimize2Icon } from "lucide-react";import { type AssistantCitation, type ChatFileAttachment, DEFAULT_MODEL, type ChatAttachment as ContractChatAttachment, type EnvironmentId, type MessageId, type ModelSelection, type ProjectScript, type ProjectId, type ProviderApprovalDecision, type PreviewAnnotationPayload, ProviderInstanceId, type ServerProvider, type ResolvedKeybindingsConfig, type ScopedThreadRef, type ThreadId, type RunId, type RuntimeRequestId, type KeybindingCommand, PROVIDER_SEND_TURN_MAX_ATTACHMENTS, ProviderInteractionMode, ProviderDriverKind, resolveEnvironmentMachineKind, RuntimeMode, TerminalOpenInput,} from "@t3tools/contracts";import { type EnvironmentConnectionPresentation } from "@t3tools/client-runtime/connection";import { deriveThreadTitleSeed } from "@t3tools/client-runtime/operations";import { effectiveSnoozed, threadWokeAt } from "@t3tools/client-runtime/state/thread-settled";import { useThreadActions } from "../hooks/useThreadActions";import { deriveThreadActivityRun, deriveLatestThreadRun, deriveThreadRuntime,} from "@t3tools/client-runtime/state/thread-execution";import { resolveThreadProviderSession } from "@t3tools/client-runtime/state/thread-workflows";import { codexFeedbackMessage, parseCodexFeedbackCommand, shouldShowLoadEarlierControl, submitCodexFeedback, type CodexFeedbackSubmission,} from "@t3tools/client-runtime/state/threads";import { resolveThreadLastVisitedAt } from "./Sidebar.logic";import { derivePendingThreadRequests } from "@t3tools/client-runtime/state/thread-requests";import { parseScopedThreadKey, scopedThreadKey, scopeProjectRef, scopeThreadRef,} from "@t3tools/client-runtime/environment";import { applyClaudePromptEffortPrefix, createModelSelection, resolvePromptInjectedEffort,} from "@t3tools/shared/model";import { CHAT_LIST_ANCHOR_OFFSET } from "@t3tools/shared/chatList";import { derivePendingBackgroundWork } from "@t3tools/shared/orchestrationV2PendingBackgroundWork";import { projectScriptCwd, projectScriptRuntimeEnv } from "@t3tools/shared/projectScripts";import { truncate } from "@t3tools/shared/String";import { resolveThreadReferenceCopyTarget } from "@t3tools/shared/threadReference";import { nextTerminalId, resolveTerminalSessionLabel } from "@t3tools/shared/terminalLabels";import { Debouncer } from "@tanstack/react-pacer";import { useAtomValue } from "@effect/atom-react";import { lazy, memo, Suspense, useCallback, useEffect, useEffectEvent, useLayoutEffect, useMemo, useRef, useState,} from "react";import { flushSync } from "react-dom";import { useLocation, useNavigate } from "@tanstack/react-router";import { assistantCitationFromLocation } from "../lib/assistantCitationNavigation";import type { AssistantCitationSourceAnchor } from "~/lib/assistantTextSelection";import { useShallow } from "zustand/react/shallow";import { isAtomCommandInterrupted, mapAtomCommandResult, settlePromise, squashAtomCommandFailure, type AtomCommandResult,} from "@t3tools/client-runtime/state/runtime";import * as Cause from "effect/Cause";import { AsyncResult } from "effect/unstable/reactivity";import { isElectron } from "../env";import { readLocalApi } from "../localApi";import { useDiffPanelStore } from "../diffPanelStore";import { collapseExpandedComposerCursor, parseStandaloneComposerSlashCommand,} from "../composer-logic";import { derivePendingApprovals, derivePendingUserInputs, derivePhase, deriveTimelineEntriesFromVisibleTurnItemsWithState, selectHandoffImageResources, type TimelineEntriesProjection, deriveRevertTurnCountByUserMessageId, deriveActivePlanState, deriveActiveWorkStartedAt, findLatestProposedPlan, hasActionableProposedPlan, isLatestRunSettled,} from "../session-logic";import { type LegendListRef } from "@legendapp/list/react";import { CHAT_TIMELINE_ANCHOR_OFFSET, type TimelineScrollMode,} from "./chat/timelineScrollAnchoring";import { buildPendingUserInputAnswers, derivePendingUserInputProgress, setPendingUserInputCustomAnswer, togglePendingUserInputOptionSelection, type PendingUserInputDraftAnswer,} from "../pendingUserInput";import { useUiStateStore } from "../uiStateStore";import { useWorkspaceMutationRefresh } from "../hooks/useWorkspaceMutationRefresh";import { buildPlanImplementationThreadTitle, buildPlanImplementationPrompt, resolvePlanFollowUpSubmission,} from "../proposedPlan";import { DEFAULT_INTERACTION_MODE, DEFAULT_RUNTIME_MODE, DEFAULT_THREAD_TERMINAL_ID, MAX_TERMINALS_PER_GROUP, type ChatMessage, isBrowserPreviewAttachment, type SessionPhase, type Thread, type TurnDiffSummary,} from "../types";import { useTheme } from "../hooks/useTheme";import { writeTextToClipboard } from "../hooks/useCopyToClipboard";import { useTurnDiffSummaries } from "../hooks/useTurnDiffSummaries";import { isCommandPaletteOpen } from "../commandPaletteBus";import { useMediaQuery } from "../hooks/useMediaQuery";import { useElementWidth } from "../hooks/useElementWidth";import { usePreviewPanelInlineSize } from "../hooks/usePreviewPanelInlineSize";import { RIGHT_PANEL_INLINE_LAYOUT_MEDIA_QUERY, resolveThreadPanelPresentation,} from "../rightPanelLayout";import { selectActiveRightPanel, selectActiveRightPanelSurface, selectThreadPanelOpen, selectThreadRightPanelState, type RightPanelSurface, useRightPanelStore,} from "../rightPanelStore";import { isPreviewSupportedInRuntime, setActivePreviewTab, useThreadPreviewState,} from "../previewStateStore";import { addBrowserSurface } from "./preview/addBrowserSurface";import { closePreviewSession } from "./preview/closePreviewSession";import { ThreadPreviewMiniPlayer } from "./preview/ThreadPreviewMiniPlayer";import { subscribePreviewAction } from "./preview/previewActionBus";import { getConfiguredPreviewUrls } from "./preview/previewEmptyStateLogic";import { selectThreadPreviewMiniPlayer, usePreviewMiniPlayerStore,} from "../previewMiniPlayerStore";import { isThreadOwnPullRequest } from "./pullRequest/pullRequestDetail.logic";import { PullRequestDetailPanel } from "./pullRequest/PullRequestDetailPanel";import { PullRequestDetailGhost } from "./pullRequest/PullRequestGhosts";import { PullRequestsUnavailableState } from "./pullRequest/PullRequestsUnavailableState";import { RightPanelTabs, type PullRequestTabStatus } from "./RightPanelTabs";import { BranchToolbar } from "./BranchToolbar";import { resolveShortcutCommand, shortcutLabelForCommand } from "../keybindings";import { makeWorkspaceFileDropHandlers } from "./chat/workspaceFileDrop";import ThreadTerminalDrawer from "./ThreadTerminalDrawer";import { AlarmClockIcon, CheckCircle2Icon, PaperclipIcon, ChevronDownIcon, GitBranchIcon, WifiOffIcon,} from "lucide-react";import { cn } from "~/lib/utils";import { COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS } from "~/workspaceTitlebar";import { stackedThreadToast, toastManager } from "./ui/toast";import { decodeProjectScriptKeybindingRule } from "~/lib/projectScriptKeybindings";import { type NewProjectScriptInput } from "./ProjectScriptsControl";import { buildProjectScript, commandForProjectScript, nextProjectScriptId, projectScriptIdFromCommand,} from "~/projectScripts";import { newDraftId, newMessageId, newThreadId } from "~/lib/utils";import { registerFaviconProjectForThread } from "~/browserFaviconStore";import { getProviderModelCapabilities } from "../providerModels";import { applyProviderInstanceSettings, deriveProviderInstanceEntries, NO_PROVIDER_MODEL_SELECTION, sortProviderInstanceEntries,} from "../providerInstances";import { useClientSettingsHydrated, useEnvironmentSettings } from "../hooks/useSettings";import { useNowMinute } from "../hooks/useNowMinute";import { usePanelAnimationSettings, usePanelPresence } from "../panelAnimations";import { useNewThreadHandler } from "../hooks/useHandleNewThread";import { useOpenPanelPullRequestUrl } from "../hooks/useOpenPanelPullRequestUrl";import { resolveAppModelSelectionForInstance } from "../modelSelection";import { deriveLatestContextWindowSnapshot } from "../lib/contextWindow";import { getTerminalFocusOwner } from "../lib/terminalFocus";import { preventRepeatedTerminalCloseShortcut, preventTerminalCloseShortcut,} from "../lib/terminalCloseShortcut";import { resolveNewDraftStartFromOrigin } from "../lib/chatThreadActions";import { deriveLogicalProjectKeyFromSettings, selectProjectGroupingSettings,} from "../logicalProject";import { buildDraftThreadRouteParams, buildThreadRouteParams } from "../threadRoutes";import { composerDraftHasUserContent, type ComposerFileAttachment, type ComposerImageAttachment, type DraftThreadEnvMode, useComposerDraftStore, DraftId,} from "../composerDraftStore";import { appendTerminalContextsToPrompt, formatTerminalContextLabel, type TerminalContextDraft, type TerminalContextSelection,} from "../lib/terminalContext";import { appendElementContextsToPrompt, type ElementContextDraft, formatElementContextLabel,} from "../lib/elementContext";import { appendPreviewAnnotationPrompt } from "../lib/previewAnnotation";import { appendReviewCommentsToPrompt, type ReviewCommentContext } from "../reviewCommentContext";import { environmentCatalog } from "../connection/catalog";import { selectThreadTerminalUiState, useTerminalUiStateStore } from "../terminalUiStateStore";import { useKnownTerminalSessions, useThreadRunningTerminalIds } from "../state/terminalSessions";import { projectEnvironment } from "../state/projects";import { useEnvironmentQuery } from "../state/query";import { environmentServerConfigsAtom, primaryServerAvailableEditorsAtom, primaryServerKeybindingsAtom, primaryServerSettingsAtom, serverEnvironment,} from "../state/server";import { terminalEnvironment } from "../state/terminal";import { threadEnvironment } from "../state/threads";import { resolveProviderSkillsForCwd } from "@t3tools/client-runtime/providerSkills";import { vcsEnvironment } from "../state/vcs";import { useEnvironments, usePrimaryEnvironment } from "../state/environments";import { resolveThreadDetailRef, useProject, useProjects, useThreadProjection, useThreadStatus, useThreadHistory, useThreadShell, useThreadRefs, useThreadVisibleTurnItems, waitForThreadShell,} from "../state/entities";import { environmentShell } from "../state/shell";import { ChatComposer, type ChatComposerHandle } from "./chat/ChatComposer";import { createPageScrollController, type PageScrollKey } from "./chat/pageScrollController";import { DraftHeroHeadline } from "./chat/DraftHeroHeadline";import { ExpandedImageDialog } from "./chat/ExpandedImageDialog";import { PullRequestThreadDialog } from "./PullRequestThreadDialog";import type { AssistantCitationRequest } from "./chat/AssistantCitationSource";import { MessagesTimeline, type MessagesTimelineHistoryControls } from "./chat/MessagesTimeline";import { resolveTimelineIsAtEnd } from "./chat/MessagesTimeline.logic";import { resolveComposerTimelineInset } from "./composerFooterLayout";import { ChatHeader } from "./chat/ChatHeader";import { useRemoteOpenState } from "~/remoteOpen";import { shouldShowOpenInPicker } from "./chat/OpenInPicker.logic";import { useOpenFavoriteEditorShortcut } from "./chat/OpenInPickerShortcut";import { PanelLayoutControls, type PanelLayoutControlsProps, RightPanelMaximizeControl,} from "./chat/PanelLayoutControls";import { expandedImageKey, type ExpandedImagePreview } from "./chat/ExpandedImagePreview";import { ThreadDetailsPanel, type ThreadDetailsPanelProps } from "./chat/ThreadDetailsPanel";import { NoActiveThreadState } from "./NoActiveThreadState";import { AgentsPanel } from "./AgentsPanel";import { deriveAgentPanelModel, projectedSubagentsToRuntime,} from "@t3tools/client-runtime/state/subagentRuntime";import { type EnvironmentOption, resolveEffectiveEnvMode, resolveLocalCheckoutBranchMismatch, shouldShowComposerContextStrip, shouldShowEnvironmentIndicator,} from "./BranchToolbar.logic";import { getProviderStatusBannerKey, ProviderStatusBanner, shouldShowProviderStatusBanner,} from "./chat/ProviderStatusBanner";import { dismissThreadErrorBannerForSession, getThreadErrorBannerKey, isThreadErrorBannerDismissedForSession, shouldShowThreadErrorBanner, ThreadErrorBanner,} from "./chat/ThreadErrorBanner";import { QueuedRunsControl, type EditQueuedRunRequest } from "./chat/QueuedRunsControl";import { resolveDisplayedThreadPr, threadChangeRequestSnapshotsAtom, useLinkedThreadPullRequest,} from "./ThreadStatusIndicators";import type { ComposerBannerStackItem } from "./chat/ComposerBannerStack";import { ComposerSurface } from "./chat/ComposerSurface";import { resolveThreadSyncPhase } from "../threadSync";import { hasAvailableCompactionProvider, hasDismissedResumeCompaction, shouldOfferResumeCompaction,} from "./chat/ContextWindowMeter.logic";import { formatContextWindowTokens } from "../lib/contextWindow";import { DRAFT_HERO_TRANSITION_ANIMATION_ID, DRAFT_HERO_TRANSITION_DURATION_MS, DRAFT_HERO_TRANSITION_EASING, MOBILE_COMPOSER_VIEW_TRANSITION_NAME, MOBILE_DRAFT_HEADLINE_VIEW_TRANSITION_NAME, runMobileComposerTransition,} from "./chat/draftHeroTransition";import type { ComposerDispatchMode } from "./chat/composerDispatch";import { MAX_HIDDEN_MOUNTED_TERMINAL_THREADS, agentControlledBrowserCloseConfirmation, branchMismatchKey, buildExpiredTerminalContextToastCopy, buildLocalDraftThread, collectUserMessageBlobPreviewUrls, createLocalDispatchSnapshot, deriveCommittedServerUserMessageIds, deriveComposerSendState, dismissBranchMismatchForSession, hasEnvironmentReconnectWarningGraceElapsed, scheduleEnvironmentReconnectWarning, hasServerAcknowledgedLocalDispatch, isBranchMismatchDismissedForSession, shouldShowBranchMismatchBanner, shouldShowPlanFollowUpPrompt, shouldOpenProactivePullRequest, shouldOpenProactiveTurnDiff, shouldReleaseTimelineAnchorForToolActivity, shouldRenderPreviewMiniPlayer, getStartedThreadModelChangeBlockReason, LAST_INVOKED_SCRIPT_BY_PROJECT_KEY, LastInvokedScriptByProjectSchema, type LocalDispatchSnapshot, PullRequestDialogState, cloneComposerImageForRetry, deriveLockedProvider, readFileAsDataUrl, resolveFileAttachmentUrl, reconcileMountedTerminalThreadIds, resolveComposerInteractionMode, resolveComposerProviderSelection, resolveProactiveTurnDiffAction, resolveThreadMetadataUpdateForNextTurn, resolveSendEnvMode, revokeBlobPreviewUrl, revokeUserMessagePreviewUrls, startNewThreadForProject, codexArtifactTemplatePromptToAppend, toolGroupConsumesUpwardNavigation, waitForStartedServerThread,} from "./ChatView.logic";import { useLocalStorage } from "~/hooks/useLocalStorage";import { useComposerHandleContext } from "../composerHandleContext";import { awaitAttachmentUploads, getUploadedAttachments, releaseDraftAttachments, startAttachmentUpload,} from "../lib/attachmentUploadQueue";import { sanitizeThreadErrorMessage } from "~/rpc/transportError";import { RightPanelSheet } from "./RightPanelSheet";import { previewEnvironment } from "../state/preview";import { clampFileAttachmentUploadBytes } from "@t3tools/client-runtime/state/attachments";import { appAtomRegistry } from "../rpc/atomRegistry";import { fileAttachmentCapabilityBlockReason } from "./chat/composerAttachmentFiles";import { assetEnvironment } from "../state/assets";import { readPreparedConnection } from "../state/session";import { useAtomCommand } from "../state/use-atom-command";import { useAtomQueryRunner } from "../state/use-atom-query-runner";import { Button } from "./ui/button";import { AlertDialog, AlertDialogClose, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogPopup, AlertDialogTitle,} from "./ui/alert-dialog";import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip";import { ServerUpdateAction } from "./ServerUpdateAction";import { ComposerServerUpdateIcon, ComposerServerUpdateStatus,} from "./chat/ComposerServerUpdateStatus";import { buildVersionMismatchDismissalKey, dismissServerUpdateFailure, dismissVersionMismatch, isServerUpdateFailureDismissed, isVersionMismatchDismissed, resolveServerConfigVersionMismatch, resolveServerSelfUpdateCapability, serverUpdateGuidance, supportsDesktopAppUpdate, supportsServerUpdateThreadContinuation,} from "../versionSkew";import { useAssetUrls } from "../assets/assetUrls";import type { CodexArtifactTemplate } from "@t3tools/client-runtime/codex-artifact-templates"; const TIMELINE_SCROLL_CANCEL_SENTINEL = Object.freeze({});const ATTACHMENT_ONLY_BOOTSTRAP_PROMPT = "[User attached one or more files without additional text. Respond using the conversation context and the attached files.]";const EMPTY_PROVIDERS: ServerProvider[] = [];const EMPTY_FEEDBACK_SUBMISSIONS: ReadonlyArray<CodexFeedbackSubmission> = [];// During an active turn the thread's updatedAt advances several times per// second, and every server-side visit is a full command dispatch plus a// broadcast to all shell subscribers. Mid-turn bumps carry no unread signal// (unread flips on run completions, which bypass the throttle), so one// watermark per interval is plenty.const VISIT_DISPATCH_THROTTLE_MS = 10_000;const EMPTY_PROVIDER_SKILLS: ServerProvider["skills"] = [];const EMPTY_PENDING_USER_INPUT_ANSWERS: Record<string, PendingUserInputDraftAnswer> = {}; function useDraftHeroLayoutTransition(isDraftHeroState: boolean) { const transitionGroupRef = useRef<HTMLDivElement | null>(null); const composerAnchorRef = useRef<HTMLDivElement | null>(null); const previousStateRef = useRef(isDraftHeroState); const previousComposerRectRef = useRef<DOMRect | null>(null); const animationRef = useRef<Animation | null>(null); const attachTransitionGroupRef = (element: HTMLDivElement | null) => { transitionGroupRef.current = element; }; const attachComposerAnchorRef = (element: HTMLDivElement | null) => { composerAnchorRef.current = element; }; const captureComposerRect = () => { previousComposerRectRef.current = composerAnchorRef.current?.getBoundingClientRect() ?? null; }; useLayoutEffect(() => { const transitionGroup = transitionGroupRef.current; const nextComposerRect = composerAnchorRef.current?.getBoundingClientRect() ?? null; const stateChanged = previousStateRef.current !== isDraftHeroState; const prefersReducedMotion = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches; const mobileComposerTransitionActive = typeof document !== "undefined" && document.documentElement.dataset.mobileComposerRouteTransition === "true"; animationRef.current?.cancel(); animationRef.current = null; const previousComposerRect = previousComposerRectRef.current; if ( stateChanged && !prefersReducedMotion && !mobileComposerTransitionActive && transitionGroup && previousComposerRect && nextComposerRect && typeof transitionGroup.animate === "function" ) {Lines 1–500 of 8775. Load more
import { getTerminalLabel } from "@t3tools/shared/terminalLabels"; import * as Schema from "effect/Schema"; import { confirmTerminalClose, isTerminalCloseConfirmPending } from "../lib/terminalCloseConfirm"; import { Minimize2Icon } from "lucide-react"; import { type AssistantCitation, type ChatFileAttachment, DEFAULT_MODEL, type ChatAttachment as ContractChatAttachment, type EnvironmentId, type MessageId, type ModelSelection, type ProjectScript, type ProjectId, type ProviderApprovalDecision, type PreviewAnnotationPayload, ProviderInstanceId, type ServerProvider, type ResolvedKeybindingsConfig, type ScopedThreadRef, type ThreadId, type RunId, type RuntimeRequestId, type KeybindingCommand, PROVIDER_SEND_TURN_MAX_ATTACHMENTS, ProviderInteractionMode, ProviderDriverKind, resolveEnvironmentMachineKind, RuntimeMode, TerminalOpenInput, } from "@t3tools/contracts"; import { type EnvironmentConnectionPresentation } from "@t3tools/client-runtime/connection"; import { deriveThreadTitleSeed } from "@t3tools/client-runtime/operations"; import { effectiveSnoozed, threadWokeAt } from "@t3tools/client-runtime/state/thread-settled"; import { useThreadActions } from "../hooks/useThreadActions"; import { deriveThreadActivityRun, deriveLatestThreadRun, deriveThreadRuntime, } from "@t3tools/client-runtime/state/thread-execution"; import { resolveThreadProviderSession } from "@t3tools/client-runtime/state/thread-workflows"; import { codexFeedbackMessage, parseCodexFeedbackCommand, shouldShowLoadEarlierControl, submitCodexFeedback, type CodexFeedbackSubmission, } from "@t3tools/client-runtime/state/threads"; import { resolveThreadLastVisitedAt } from "./Sidebar.logic"; import { derivePendingThreadRequests } from "@t3tools/client-runtime/state/thread-requests"; import { parseScopedThreadKey, scopedThreadKey, scopeProjectRef, scopeThreadRef, } from "@t3tools/client-runtime/environment"; import { applyClaudePromptEffortPrefix, createModelSelection, resolvePromptInjectedEffort, } from "@t3tools/shared/model"; import { CHAT_LIST_ANCHOR_OFFSET } from "@t3tools/shared/chatList"; import { derivePendingBackgroundWork } from "@t3tools/shared/orchestrationV2PendingBackgroundWork"; import { projectScriptCwd, projectScriptRuntimeEnv } from "@t3tools/shared/projectScripts"; import { truncate } from "@t3tools/shared/String"; import { resolveThreadReferenceCopyTarget } from "@t3tools/shared/threadReference"; import { nextTerminalId, resolveTerminalSessionLabel } from "@t3tools/shared/terminalLabels"; import { Debouncer } from "@tanstack/react-pacer"; import { useAtomValue } from "@effect/atom-react"; import { lazy, memo, Suspense, useCallback, useEffect, useEffectEvent, useLayoutEffect, useMemo, useRef, useState, } from "react"; import { flushSync } from "react-dom"; import { useLocation, useNavigate } from "@tanstack/react-router"; import { assistantCitationFromLocation } from "../lib/assistantCitationNavigation"; import type { AssistantCitationSourceAnchor } from "~/lib/assistantTextSelection"; import { useShallow } from "zustand/react/shallow"; import { isAtomCommandInterrupted, mapAtomCommandResult, settlePromise, squashAtomCommandFailure, type AtomCommandResult, } from "@t3tools/client-runtime/state/runtime"; import * as Cause from "effect/Cause"; import { AsyncResult } from "effect/unstable/reactivity"; import { isElectron } from "../env"; import { readLocalApi } from "../localApi"; import { useDiffPanelStore } from "../diffPanelStore"; import { collapseExpandedComposerCursor, parseStandaloneComposerSlashCommand, } from "../composer-logic"; import { derivePendingApprovals, derivePendingUserInputs, derivePhase, deriveTimelineEntriesFromVisibleTurnItemsWithState, selectHandoffImageResources, type TimelineEntriesProjection, deriveRevertTurnCountByUserMessageId, deriveActivePlanState, deriveActiveWorkStartedAt, findLatestProposedPlan, hasActionableProposedPlan, isLatestRunSettled, } from "../session-logic"; import { type LegendListRef } from "@legendapp/list/react"; import { CHAT_TIMELINE_ANCHOR_OFFSET, type TimelineScrollMode, } from "./chat/timelineScrollAnchoring"; import { buildPendingUserInputAnswers, derivePendingUserInputProgress, setPendingUserInputCustomAnswer, togglePendingUserInputOptionSelection, type PendingUserInputDraftAnswer, } from "../pendingUserInput"; import { useUiStateStore } from "../uiStateStore"; import { useWorkspaceMutationRefresh } from "../hooks/useWorkspaceMutationRefresh"; import { buildPlanImplementationThreadTitle, buildPlanImplementationPrompt, resolvePlanFollowUpSubmission, } from "../proposedPlan"; import { DEFAULT_INTERACTION_MODE, DEFAULT_RUNTIME_MODE, DEFAULT_THREAD_TERMINAL_ID, MAX_TERMINALS_PER_GROUP, type ChatMessage, isBrowserPreviewAttachment, type SessionPhase, type Thread, type TurnDiffSummary, } from "../types"; import { useTheme } from "../hooks/useTheme"; import { writeTextToClipboard } from "../hooks/useCopyToClipboard"; import { useTurnDiffSummaries } from "../hooks/useTurnDiffSummaries"; import { isCommandPaletteOpen } from "../commandPaletteBus"; import { useMediaQuery } from "../hooks/useMediaQuery"; import { useElementWidth } from "../hooks/useElementWidth"; import { usePreviewPanelInlineSize } from "../hooks/usePreviewPanelInlineSize"; import { RIGHT_PANEL_INLINE_LAYOUT_MEDIA_QUERY, resolveThreadPanelPresentation, } from "../rightPanelLayout"; import { selectActiveRightPanel, selectActiveRightPanelSurface, selectThreadPanelOpen, selectThreadRightPanelState, type RightPanelSurface, useRightPanelStore, } from "../rightPanelStore"; import { isPreviewSupportedInRuntime, setActivePreviewTab, useThreadPreviewState, } from "../previewStateStore"; import { addBrowserSurface } from "./preview/addBrowserSurface"; import { closePreviewSession } from "./preview/closePreviewSession"; import { ThreadPreviewMiniPlayer } from "./preview/ThreadPreviewMiniPlayer"; import { subscribePreviewAction } from "./preview/previewActionBus"; import { getConfiguredPreviewUrls } from "./preview/previewEmptyStateLogic"; import { selectThreadPreviewMiniPlayer, usePreviewMiniPlayerStore, } from "../previewMiniPlayerStore"; import { isThreadOwnPullRequest } from "./pullRequest/pullRequestDetail.logic"; import { PullRequestDetailPanel } from "./pullRequest/PullRequestDetailPanel"; import { PullRequestDetailGhost } from "./pullRequest/PullRequestGhosts"; import { PullRequestsUnavailableState } from "./pullRequest/PullRequestsUnavailableState"; import { RightPanelTabs, type PullRequestTabStatus } from "./RightPanelTabs"; import { BranchToolbar } from "./BranchToolbar"; import { resolveShortcutCommand, shortcutLabelForCommand } from "../keybindings"; import { makeWorkspaceFileDropHandlers } from "./chat/workspaceFileDrop"; import ThreadTerminalDrawer from "./ThreadTerminalDrawer"; import { AlarmClockIcon, CheckCircle2Icon, PaperclipIcon, ChevronDownIcon, GitBranchIcon, WifiOffIcon, } from "lucide-react"; import { cn } from "~/lib/utils"; import { COLLAPSED_SIDEBAR_TITLEBAR_INSET_CLASS } from "~/workspaceTitlebar"; import { stackedThreadToast, toastManager } from "./ui/toast"; import { decodeProjectScriptKeybindingRule } from "~/lib/projectScriptKeybindings"; import { type NewProjectScriptInput } from "./ProjectScriptsControl"; import { buildProjectScript, commandForProjectScript, nextProjectScriptId, projectScriptIdFromCommand, } from "~/projectScripts"; import { newDraftId, newMessageId, newThreadId } from "~/lib/utils"; import { registerFaviconProjectForThread } from "~/browserFaviconStore"; import { getProviderModelCapabilities } from "../providerModels"; import { applyProviderInstanceSettings, deriveProviderInstanceEntries, NO_PROVIDER_MODEL_SELECTION, sortProviderInstanceEntries, } from "../providerInstances"; import { useClientSettingsHydrated, useEnvironmentSettings } from "../hooks/useSettings"; import { useNowMinute } from "../hooks/useNowMinute"; import { usePanelAnimationSettings, usePanelPresence } from "../panelAnimations"; import { useNewThreadHandler } from "../hooks/useHandleNewThread"; import { useOpenPanelPullRequestUrl } from "../hooks/useOpenPanelPullRequestUrl"; import { resolveAppModelSelectionForInstance } from "../modelSelection"; import { deriveLatestContextWindowSnapshot } from "../lib/contextWindow"; import { getTerminalFocusOwner } from "../lib/terminalFocus"; import { preventRepeatedTerminalCloseShortcut, preventTerminalCloseShortcut, } from "../lib/terminalCloseShortcut"; import { resolveNewDraftStartFromOrigin } from "../lib/chatThreadActions"; import { deriveLogicalProjectKeyFromSettings, selectProjectGroupingSettings, } from "../logicalProject"; import { buildDraftThreadRouteParams, buildThreadRouteParams } from "../threadRoutes"; import { composerDraftHasUserContent, type ComposerFileAttachment, type ComposerImageAttachment, type DraftThreadEnvMode, useComposerDraftStore, DraftId, } from "../composerDraftStore"; import { appendTerminalContextsToPrompt, formatTerminalContextLabel, type TerminalContextDraft, type TerminalContextSelection, } from "../lib/terminalContext"; import { appendElementContextsToPrompt, type ElementContextDraft, formatElementContextLabel, } from "../lib/elementContext"; import { appendPreviewAnnotationPrompt } from "../lib/previewAnnotation"; import { appendReviewCommentsToPrompt, type ReviewCommentContext } from "../reviewCommentContext"; import { environmentCatalog } from "../connection/catalog"; import { selectThreadTerminalUiState, useTerminalUiStateStore } from "../terminalUiStateStore"; import { useKnownTerminalSessions, useThreadRunningTerminalIds } from "../state/terminalSessions"; import { projectEnvironment } from "../state/projects"; import { useEnvironmentQuery } from "../state/query"; import { environmentServerConfigsAtom, primaryServerAvailableEditorsAtom, primaryServerKeybindingsAtom, primaryServerSettingsAtom, serverEnvironment, } from "../state/server"; import { terminalEnvironment } from "../state/terminal"; import { threadEnvironment } from "../state/threads"; import { resolveProviderSkillsForCwd } from "@t3tools/client-runtime/providerSkills"; import { vcsEnvironment } from "../state/vcs"; import { useEnvironments, usePrimaryEnvironment } from "../state/environments"; import { resolveThreadDetailRef, useProject, useProjects, useThreadProjection, useThreadStatus, useThreadHistory, useThreadShell, useThreadRefs, useThreadVisibleTurnItems, waitForThreadShell, } from "../state/entities"; import { environmentShell } from "../state/shell"; import { ChatComposer, type ChatComposerHandle } from "./chat/ChatComposer"; import { createPageScrollController, type PageScrollKey } from "./chat/pageScrollController"; import { DraftHeroHeadline } from "./chat/DraftHeroHeadline"; import { ExpandedImageDialog } from "./chat/ExpandedImageDialog"; import { PullRequestThreadDialog } from "./PullRequestThreadDialog"; import type { AssistantCitationRequest } from "./chat/AssistantCitationSource"; import { MessagesTimeline, type MessagesTimelineHistoryControls } from "./chat/MessagesTimeline"; import { resolveTimelineIsAtEnd } from "./chat/MessagesTimeline.logic"; import { resolveComposerTimelineInset } from "./composerFooterLayout"; import { ChatHeader } from "./chat/ChatHeader"; import { useRemoteOpenState } from "~/remoteOpen"; import { shouldShowOpenInPicker } from "./chat/OpenInPicker.logic"; import { useOpenFavoriteEditorShortcut } from "./chat/OpenInPickerShortcut"; import { PanelLayoutControls, type PanelLayoutControlsProps, RightPanelMaximizeControl, } from "./chat/PanelLayoutControls"; import { expandedImageKey, type ExpandedImagePreview } from "./chat/ExpandedImagePreview"; import { ThreadDetailsPanel, type ThreadDetailsPanelProps } from "./chat/ThreadDetailsPanel"; import { NoActiveThreadState } from "./NoActiveThreadState"; import { AgentsPanel } from "./AgentsPanel"; import { deriveAgentPanelModel, projectedSubagentsToRuntime, } from "@t3tools/client-runtime/state/subagentRuntime"; import { type EnvironmentOption, resolveEffectiveEnvMode, resolveLocalCheckoutBranchMismatch, shouldShowComposerContextStrip, shouldShowEnvironmentIndicator, } from "./BranchToolbar.logic"; import { getProviderStatusBannerKey, ProviderStatusBanner, shouldShowProviderStatusBanner, } from "./chat/ProviderStatusBanner"; import { dismissThreadErrorBannerForSession, getThreadErrorBannerKey, isThreadErrorBannerDismissedForSession, shouldShowThreadErrorBanner, ThreadErrorBanner, } from "./chat/ThreadErrorBanner"; import { QueuedRunsControl, type EditQueuedRunRequest } from "./chat/QueuedRunsControl"; import { resolveDisplayedThreadPr, threadChangeRequestSnapshotsAtom, useLinkedThreadPullRequest, } from "./ThreadStatusIndicators"; import type { ComposerBannerStackItem } from "./chat/ComposerBannerStack"; import { ComposerSurface } from "./chat/ComposerSurface"; import { resolveThreadSyncPhase } from "../threadSync"; import { hasAvailableCompactionProvider, hasDismissedResumeCompaction, shouldOfferResumeCompaction, } from "./chat/ContextWindowMeter.logic"; import { formatContextWindowTokens } from "../lib/contextWindow"; import { DRAFT_HERO_TRANSITION_ANIMATION_ID, DRAFT_HERO_TRANSITION_DURATION_MS, DRAFT_HERO_TRANSITION_EASING, MOBILE_COMPOSER_VIEW_TRANSITION_NAME, MOBILE_DRAFT_HEADLINE_VIEW_TRANSITION_NAME, runMobileComposerTransition, } from "./chat/draftHeroTransition"; import type { ComposerDispatchMode } from "./chat/composerDispatch"; import { MAX_HIDDEN_MOUNTED_TERMINAL_THREADS, agentControlledBrowserCloseConfirmation, branchMismatchKey, buildExpiredTerminalContextToastCopy, buildLocalDraftThread, collectUserMessageBlobPreviewUrls, createLocalDispatchSnapshot, deriveCommittedServerUserMessageIds, deriveComposerSendState, dismissBranchMismatchForSession, hasEnvironmentReconnectWarningGraceElapsed, scheduleEnvironmentReconnectWarning, hasServerAcknowledgedLocalDispatch, isBranchMismatchDismissedForSession, shouldShowBranchMismatchBanner, shouldShowPlanFollowUpPrompt, shouldOpenProactivePullRequest, shouldOpenProactiveTurnDiff, shouldReleaseTimelineAnchorForToolActivity, shouldRenderPreviewMiniPlayer, getStartedThreadModelChangeBlockReason, LAST_INVOKED_SCRIPT_BY_PROJECT_KEY, LastInvokedScriptByProjectSchema, type LocalDispatchSnapshot, PullRequestDialogState, cloneComposerImageForRetry, deriveLockedProvider, readFileAsDataUrl, resolveFileAttachmentUrl, reconcileMountedTerminalThreadIds, resolveComposerInteractionMode, resolveComposerProviderSelection, resolveProactiveTurnDiffAction, resolveThreadMetadataUpdateForNextTurn, resolveSendEnvMode, revokeBlobPreviewUrl, revokeUserMessagePreviewUrls, startNewThreadForProject, codexArtifactTemplatePromptToAppend, toolGroupConsumesUpwardNavigation, waitForStartedServerThread, } from "./ChatView.logic"; import { useLocalStorage } from "~/hooks/useLocalStorage"; import { useComposerHandleContext } from "../composerHandleContext"; import { awaitAttachmentUploads, getUploadedAttachments, releaseDraftAttachments, startAttachmentUpload, } from "../lib/attachmentUploadQueue"; import { sanitizeThreadErrorMessage } from "~/rpc/transportError"; import { RightPanelSheet } from "./RightPanelSheet"; import { previewEnvironment } from "../state/preview"; import { clampFileAttachmentUploadBytes } from "@t3tools/client-runtime/state/attachments"; import { appAtomRegistry } from "../rpc/atomRegistry"; import { fileAttachmentCapabilityBlockReason } from "./chat/composerAttachmentFiles"; import { assetEnvironment } from "../state/assets"; import { readPreparedConnection } from "../state/session"; import { useAtomCommand } from "../state/use-atom-command"; import { useAtomQueryRunner } from "../state/use-atom-query-runner"; import { Button } from "./ui/button"; import { AlertDialog, AlertDialogClose, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogPopup, AlertDialogTitle, } from "./ui/alert-dialog"; import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; import { ServerUpdateAction } from "./ServerUpdateAction"; import { ComposerServerUpdateIcon, ComposerServerUpdateStatus, } from "./chat/ComposerServerUpdateStatus"; import { buildVersionMismatchDismissalKey, dismissServerUpdateFailure, dismissVersionMismatch, isServerUpdateFailureDismissed, isVersionMismatchDismissed, resolveServerConfigVersionMismatch, resolveServerSelfUpdateCapability, serverUpdateGuidance, supportsDesktopAppUpdate, supportsServerUpdateThreadContinuation, } from "../versionSkew"; import { useAssetUrls } from "../assets/assetUrls"; import type { CodexArtifactTemplate } from "@t3tools/client-runtime/codex-artifact-templates"; const TIMELINE_SCROLL_CANCEL_SENTINEL = Object.freeze({}); const ATTACHMENT_ONLY_BOOTSTRAP_PROMPT = "[User attached one or more files without additional text. Respond using the conversation context and the attached files.]"; const EMPTY_PROVIDERS: ServerProvider[] = []; const EMPTY_FEEDBACK_SUBMISSIONS: ReadonlyArray<CodexFeedbackSubmission> = []; // During an active turn the thread's updatedAt advances several times per // second, and every server-side visit is a full command dispatch plus a // broadcast to all shell subscribers. Mid-turn bumps carry no unread signal // (unread flips on run completions, which bypass the throttle), so one // watermark per interval is plenty. const VISIT_DISPATCH_THROTTLE_MS = 10_000; const EMPTY_PROVIDER_SKILLS: ServerProvider["skills"] = []; const EMPTY_PENDING_USER_INPUT_ANSWERS: Record<string, PendingUserInputDraftAnswer> = {}; function useDraftHeroLayoutTransition(isDraftHeroState: boolean) { const transitionGroupRef = useRef<HTMLDivElement | null>(null); const composerAnchorRef = useRef<HTMLDivElement | null>(null); const previousStateRef = useRef(isDraftHeroState); const previousComposerRectRef = useRef<DOMRect | null>(null); const animationRef = useRef<Animation | null>(null); const attachTransitionGroupRef = (element: HTMLDivElement | null) => { transitionGroupRef.current = element; }; const attachComposerAnchorRef = (element: HTMLDivElement | null) => { composerAnchorRef.current = element; }; const captureComposerRect = () => { previousComposerRectRef.current = composerAnchorRef.current?.getBoundingClientRect() ?? null; }; useLayoutEffect(() => { const transitionGroup = transitionGroupRef.current; const nextComposerRect = composerAnchorRef.current?.getBoundingClientRect() ?? null; const stateChanged = previousStateRef.current !== isDraftHeroState; const prefersReducedMotion = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches; const mobileComposerTransitionActive = typeof document !== "undefined" && document.documentElement.dataset.mobileComposerRouteTransition === "true"; animationRef.current?.cancel(); animationRef.current = null; const previousComposerRect = previousComposerRectRef.current; if ( stateChanged && !prefersReducedMotion && !mobileComposerTransitionActive && transitionGroup && previousComposerRect && nextComposerRect && typeof transitionGroup.animate === "function" ) {