authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-05 22:07:28-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-05 22:07:28-07:00
log226abe5f916ff828d8be2c19f1148b10feebfe43
tree1e412cb274a63e61e63645014828077313bd284e
parentfdcc491e0b36245d4b4c74d1fd338d874f4ec84f
signature Signed by PGP key B5690EEEBB952194

refactor(web): keep feature component helpers private (#10226)


31 files changed, 46 insertions(+), 79 deletions(-)

apps/web/src/components/BranchToolbarEnvModeSelector.tsx+1-1
...@@ -18,7 +18,7 @@ import {...@@ -18,7 +18,7 @@ import {
18 SelectValue,18 SelectValue,
19} from "./ui/select";19} from "./ui/select";
2020
21export const PREVIOUS_WORKTREE_SELECT_VALUE = "previous-worktree";21const PREVIOUS_WORKTREE_SELECT_VALUE = "previous-worktree";
2222
23interface BranchToolbarEnvModeSelectorProps {23interface BranchToolbarEnvModeSelectorProps {
24 envLocked: boolean;24 envLocked: boolean;
apps/web/src/components/ConfirmDialogHost.tsx+1-1
...@@ -23,7 +23,7 @@ type ConfirmationCopy = {...@@ -23,7 +23,7 @@ type ConfirmationCopy = {
23 readonly description: string | null;23 readonly description: string | null;
24};24};
2525
26export function resolveConfirmDialogCopy(message: string): ConfirmationCopy {26function resolveConfirmDialogCopy(message: string): ConfirmationCopy {
27 const normalizedMessage = message.trim();27 const normalizedMessage = message.trim();
28 const lines = normalizedMessage.split("\n");28 const lines = normalizedMessage.split("\n");
29 const questionLineIndex = lines.findIndex((line) => line.trim().endsWith("?"));29 const questionLineIndex = lines.findIndex((line) => line.trim().endsWith("?"));
apps/web/src/components/DiffPanel.tsx-2
...@@ -104,8 +104,6 @@ interface DiffPanelProps {...@@ -104,8 +104,6 @@ interface DiffPanelProps {
104 workspaceMutationId: string | null;104 workspaceMutationId: string | null;
105}105}
106106
107export { DiffWorkerPoolProvider } from "./DiffWorkerPoolProvider";
108
109export default function DiffPanel({107export default function DiffPanel({
110 mode = "inline",108 mode = "inline",
111 composerDraftTarget,109 composerDraftTarget,
apps/web/src/components/EnvironmentMachineIcon.tsx+2-2
...@@ -23,7 +23,7 @@ function LucideLike(props: SVGProps<SVGSVGElement>) {...@@ -23,7 +23,7 @@ function LucideLike(props: SVGProps<SVGSVGElement>) {
23}23}
2424
25/** A Mac mini: squat rounded slab with a front-edge LED. */25/** A Mac mini: squat rounded slab with a front-edge LED. */
26export function MacMiniIcon(props: SVGProps<SVGSVGElement>) {26function MacMiniIcon(props: SVGProps<SVGSVGElement>) {
27 return (27 return (
28 <LucideLike {...props}>28 <LucideLike {...props}>
29 <rect width="20" height="8" x="2" y="8" rx="2" />29 <rect width="20" height="8" x="2" y="8" rx="2" />
...@@ -33,7 +33,7 @@ export function MacMiniIcon(props: SVGProps<SVGSVGElement>) {...@@ -33,7 +33,7 @@ export function MacMiniIcon(props: SVGProps<SVGSVGElement>) {
33}33}
3434
35/** A Mac Studio: the same slab twice as tall, ports along the front foot. */35/** A Mac Studio: the same slab twice as tall, ports along the front foot. */
36export function MacStudioIcon(props: SVGProps<SVGSVGElement>) {36function MacStudioIcon(props: SVGProps<SVGSVGElement>) {
37 return (37 return (
38 <LucideLike {...props}>38 <LucideLike {...props}>
39 <rect width="18" height="14" x="3" y="5" rx="2" />39 <rect width="18" height="14" x="3" y="5" rx="2" />
apps/web/src/components/LegacySidebar.tsx+1-1
...@@ -354,7 +354,7 @@ interface SidebarThreadRowProps {...@@ -354,7 +354,7 @@ interface SidebarThreadRowProps {
354 ) => boolean;354 ) => boolean;
355}355}
356356
357export const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowProps) {357const SidebarThreadRow = memo(function SidebarThreadRow(props: SidebarThreadRowProps) {
358 const {358 const {
359 orderedProjectThreadKeys,359 orderedProjectThreadKeys,
360 isActive,360 isActive,
apps/web/src/components/ProviderUpdateLaunchNotification.logic.ts+2-2
...@@ -220,7 +220,7 @@ export function providerUpdateNotificationKey(...@@ -220,7 +220,7 @@ export function providerUpdateNotificationKey(
220 return parts.length > 0 ? parts.join("|") : null;220 return parts.length > 0 ? parts.join("|") : null;
221}221}
222222
223export function formatProviderList(providers: ReadonlyArray<Pick<ServerProvider, "driver">>) {223function formatProviderList(providers: ReadonlyArray<Pick<ServerProvider, "driver">>) {
224 const names = providers.map(224 const names = providers.map(
225 (provider) => PROVIDER_DISPLAY_NAMES[provider.driver] ?? provider.driver,225 (provider) => PROVIDER_DISPLAY_NAMES[provider.driver] ?? provider.driver,
226 );226 );
...@@ -249,7 +249,7 @@ export function shouldShowPrimaryProviderUpdateToast(view: ProviderUpdateToastVi...@@ -249,7 +249,7 @@ export function shouldShowPrimaryProviderUpdateToast(view: ProviderUpdateToastVi
249 return view.phase !== "running";249 return view.phase !== "running";
250}250}
251251
252export function getProviderUpdateRunningToastView(providerCount: number): ProviderUpdateToastView {252function getProviderUpdateRunningToastView(providerCount: number): ProviderUpdateToastView {
253 return {253 return {
254 phase: "running",254 phase: "running",
255 type: "loading",255 type: "loading",
apps/web/src/components/Sidebar.logic.ts+4-11
...@@ -15,7 +15,7 @@ import type { SidebarThreadSummary, Thread } from "../types";...@@ -15,7 +15,7 @@ import type { SidebarThreadSummary, Thread } from "../types";
15import { cn } from "../lib/utils";15import { cn } from "../lib/utils";
16import { isLatestTurnSettled } from "../session-logic";16import { isLatestTurnSettled } from "../session-logic";
1717
18export const THREAD_SELECTION_SAFE_SELECTOR = "[data-thread-item], [data-thread-selection-safe]";18const THREAD_SELECTION_SAFE_SELECTOR = "[data-thread-item], [data-thread-selection-safe]";
19export const THREAD_JUMP_HINT_SHOW_DELAY_MS = 200;19export const THREAD_JUMP_HINT_SHOW_DELAY_MS = 200;
20// Visible sidebar rows are prewarmed into the thread-detail cache so opening a20// Visible sidebar rows are prewarmed into the thread-detail cache so opening a
21// nearby thread usually reuses an already-hot subscription. Each prewarmed21// nearby thread usually reuses an already-hot subscription. Each prewarmed
...@@ -23,10 +23,10 @@ export const THREAD_JUMP_HINT_SHOW_DELAY_MS = 200;...@@ -23,10 +23,10 @@ export const THREAD_JUMP_HINT_SHOW_DELAY_MS = 200;
23// activities, growing as agents work) for as long as the row stays visible,23// activities, growing as agents work) for as long as the row stays visible,
24// so this limit is a direct renderer-heap and server-load multiplier — keep24// so this limit is a direct renderer-heap and server-load multiplier — keep
25// it small; cold opens still render instantly from the cached snapshot.25// it small; cold opens still render instantly from the cached snapshot.
26export const SIDEBAR_THREAD_PREWARM_LIMIT = 3;26const SIDEBAR_THREAD_PREWARM_LIMIT = 3;
27// A small buffer keeps the next few rows warm without leasing every row that27// A small buffer keeps the next few rows warm without leasing every row that
28// content-visibility leaves mounted below the scroll viewport.28// content-visibility leaves mounted below the scroll viewport.
29export const SIDEBAR_ROW_SUBSCRIPTION_OVERSCAN_PX = 160;29const SIDEBAR_ROW_SUBSCRIPTION_OVERSCAN_PX = 160;
3030
31export function useSidebarRowSubscriptionLease(isActive: boolean): {31export function useSidebarRowSubscriptionLease(isActive: boolean): {
32 readonly leaseLiveStatus: boolean;32 readonly leaseLiveStatus: boolean;
...@@ -544,13 +544,6 @@ export function resolveSidebarThreadStatus(thread: SidebarThreadStatusInput): Si...@@ -544,13 +544,6 @@ export function resolveSidebarThreadStatus(thread: SidebarThreadStatusInput): Si
544 return "ready";544 return "ready";
545}545}
546546
547/** NaN-safe Date.parse for sort comparators: a malformed timestamp must not
548 poison the whole ordering, so it sinks to the epoch instead. */
549export function parseTimestampMs(isoDate: string): number {
550 const parsed = Date.parse(isoDate);
551 return Number.isNaN(parsed) ? 0 : parsed;
552}
553
554/** First VALID timestamp wins: `a ?? b` falls through on null, but a present-547/** First VALID timestamp wins: `a ?? b` falls through on null, but a present-
555 yet-malformed string must also fall through to the next candidate rather548 yet-malformed string must also fall through to the next candidate rather
556 than sink the row to the epoch. */549 than sink the row to the epoch. */
...@@ -567,7 +560,7 @@ export function firstValidTimestampMs(...@@ -567,7 +560,7 @@ export function firstValidTimestampMs(
567560
568/** String twin of firstValidTimestampMs for callers that need the ISO string561/** String twin of firstValidTimestampMs for callers that need the ISO string
569 (display labels, tick anchors) rather than epoch ms. */562 (display labels, tick anchors) rather than epoch ms. */
570export function firstValidTimestamp(563function firstValidTimestamp(
571 ...candidates: ReadonlyArray<string | null | undefined>564 ...candidates: ReadonlyArray<string | null | undefined>
572): string | null {565): string | null {
573 for (const candidate of candidates) {566 for (const candidate of candidates) {
apps/web/src/components/ThreadCommandSubtitle.tsx+1-2
...@@ -15,8 +15,7 @@ export type ThreadCommandSubtitleVariant =...@@ -15,8 +15,7 @@ export type ThreadCommandSubtitleVariant =
15 | "favicon-workspace"15 | "favicon-workspace"
16 | "favicon-branch-harness";16 | "favicon-branch-harness";
1717
18export const THREAD_COMMAND_SUBTITLE_VARIANT: ThreadCommandSubtitleVariant =18const THREAD_COMMAND_SUBTITLE_VARIANT: ThreadCommandSubtitleVariant = "favicon-workspace-harness";
19 "favicon-workspace-harness";
2019
21export const COMMAND_PALETTE_META_ICON_CLASS = "size-3 shrink-0 text-muted-foreground/70";20export const COMMAND_PALETTE_META_ICON_CLASS = "size-3 shrink-0 text-muted-foreground/70";
2221
apps/web/src/components/chat/ComposerPendingElementContexts.tsx+1-1
...@@ -39,7 +39,7 @@ function buildTooltipContent(context: ElementContextDraft): string {...@@ -39,7 +39,7 @@ function buildTooltipContent(context: ElementContextDraft): string {
39 return lines.join("\n");39 return lines.join("\n");
40}40}
4141
42export function ComposerPendingElementContextChip({42function ComposerPendingElementContextChip({
43 context,43 context,
44 onRemove,44 onRemove,
45}: ComposerPendingElementContextChipProps) {45}: ComposerPendingElementContextChipProps) {
apps/web/src/components/chat/ComposerPendingTerminalContexts.tsx-22
...@@ -1,4 +1,3 @@...@@ -1,4 +1,3 @@
1import { cn } from "~/lib/utils";
2import {1import {
3 type TerminalContextDraft,2 type TerminalContextDraft,
4 formatTerminalContextLabel,3 formatTerminalContextLabel,
...@@ -6,11 +5,6 @@ import {...@@ -6,11 +5,6 @@ import {
6} from "~/lib/terminalContext";5} from "~/lib/terminalContext";
7import { TerminalContextInlineChip } from "./TerminalContextInlineChip";6import { TerminalContextInlineChip } from "./TerminalContextInlineChip";
87
9interface ComposerPendingTerminalContextsProps {
10 contexts: ReadonlyArray<TerminalContextDraft>;
11 className?: string;
12}
13
14interface ComposerPendingTerminalContextChipProps {8interface ComposerPendingTerminalContextChipProps {
15 context: TerminalContextDraft;9 context: TerminalContextDraft;
16}10}
...@@ -26,19 +20,3 @@ export function ComposerPendingTerminalContextChip({...@@ -26,19 +20,3 @@ export function ComposerPendingTerminalContextChip({
2620
27 return <TerminalContextInlineChip label={label} tooltipText={tooltipText} expired={expired} />;21 return <TerminalContextInlineChip label={label} tooltipText={tooltipText} expired={expired} />;
28}22}
29
30export function ComposerPendingTerminalContexts(props: ComposerPendingTerminalContextsProps) {
31 const { contexts, className } = props;
32
33 if (contexts.length === 0) {
34 return null;
35 }
36
37 return (
38 <div className={cn("flex flex-wrap gap-1.5", className)}>
39 {contexts.map((context) => (
40 <ComposerPendingTerminalContextChip key={context.id} context={context} />
41 ))}
42 </div>
43 );
44}
apps/web/src/components/chat/ContextWindowMeter.logic.ts+2-2
...@@ -9,8 +9,8 @@ import {...@@ -9,8 +9,8 @@ import {
9} from "../../providerInstances";9} from "../../providerInstances";
10import { getTriggerDisplayModelName, type ModelEsque } from "./providerIconUtils";10import { getTriggerDisplayModelName, type ModelEsque } from "./providerIconUtils";
1111
12export const CLAUDE_RESUME_COMPACTION_MINUTES = 70;12const CLAUDE_RESUME_COMPACTION_MINUTES = 70;
13export const CLAUDE_RESUME_COMPACTION_TOKENS = 100_000;13const CLAUDE_RESUME_COMPACTION_TOKENS = 100_000;
1414
15export function providerSupportsManualCompaction(15export function providerSupportsManualCompaction(
16 provider: ProviderInstanceEntry | null | undefined,16 provider: ProviderInstanceEntry | null | undefined,
apps/web/src/components/chat/MessagesTimeline.logic.ts+8-9
...@@ -14,7 +14,6 @@ import {...@@ -14,7 +14,6 @@ import {
14} from "@t3tools/client-runtime/work-log/presentation";14} from "@t3tools/client-runtime/work-log/presentation";
15export {15export {
16 normalizeCompactToolLabel,16 normalizeCompactToolLabel,
17 summarizeToolGroup,
18 toolGroupAction,17 toolGroupAction,
19} from "@t3tools/client-runtime/work-log/presentation";18} from "@t3tools/client-runtime/work-log/presentation";
20import {19import {
...@@ -31,11 +30,11 @@ import { type ChatMessage, type ProposedPlan, type TurnDiffSummary } from "../.....@@ -31,11 +30,11 @@ import { type ChatMessage, type ProposedPlan, type TurnDiffSummary } from "../..
31import { type MessageId, type OrchestrationLatestTurn, type TurnId } from "@t3tools/contracts";30import { type MessageId, type OrchestrationLatestTurn, type TurnId } from "@t3tools/contracts";
32import { formatWorkspaceRelativePath } from "../../filePathDisplay";31import { formatWorkspaceRelativePath } from "../../filePathDisplay";
3332
34export const TIMELINE_MINIMAP_ITEM_SPACING = 8;33const TIMELINE_MINIMAP_ITEM_SPACING = 8;
35export const TIMELINE_MINIMAP_MIN_ITEMS = 2;34export const TIMELINE_MINIMAP_MIN_ITEMS = 2;
36export const TIMELINE_MINIMAP_MAX_HEIGHT_CSS = "calc(100vh - 18rem)";35const TIMELINE_MINIMAP_MAX_HEIGHT_CSS = "calc(100vh - 18rem)";
37export const TIMELINE_CONTENT_MAX_WIDTH = 768;36const TIMELINE_CONTENT_MAX_WIDTH = 768;
38export const TIMELINE_MINIMAP_PERSISTENT_GUTTER = 48;37const TIMELINE_MINIMAP_PERSISTENT_GUTTER = 48;
3938
40function singleToolCallLabel(entry: WorkLogEntry): string {39function singleToolCallLabel(entry: WorkLogEntry): string {
41 const toolPresentation = resolveWorkEntryToolPresentation(entry, "completed");40 const toolPresentation = resolveWorkEntryToolPresentation(entry, "completed");
...@@ -145,7 +144,7 @@ export interface TimelineEndState {...@@ -145,7 +144,7 @@ export interface TimelineEndState {
145 * A small pixel band (instead of the 1px isAtEnd epsilon alone) keeps re-arming144 * A small pixel band (instead of the 1px isAtEnd epsilon alone) keeps re-arming
146 * reliable while streaming content is still growing under the viewport.145 * reliable while streaming content is still growing under the viewport.
147 */146 */
148export const TIMELINE_FOLLOW_REARM_THRESHOLD_PX = 40;147const TIMELINE_FOLLOW_REARM_THRESHOLD_PX = 40;
149148
150export function resolveTimelineIsAtEnd(state: TimelineEndState | undefined): boolean | undefined {149export function resolveTimelineIsAtEnd(state: TimelineEndState | undefined): boolean | undefined {
151 if (!state) {150 if (!state) {
...@@ -207,9 +206,9 @@ export function resolveTimelineMinimapHasPersistentGutter(viewportWidth: number)...@@ -207,9 +206,9 @@ export function resolveTimelineMinimapHasPersistentGutter(viewportWidth: number)
207 return sideGutter >= TIMELINE_MINIMAP_PERSISTENT_GUTTER;206 return sideGutter >= TIMELINE_MINIMAP_PERSISTENT_GUTTER;
208}207}
209208
210export const TIMELINE_MINIMAP_HIT_STRIP_LEFT = 12;209const TIMELINE_MINIMAP_HIT_STRIP_LEFT = 12;
211export const TIMELINE_MINIMAP_HIT_STRIP_MAX_WIDTH = 40;210const TIMELINE_MINIMAP_HIT_STRIP_MAX_WIDTH = 40;
212export const TIMELINE_MINIMAP_EXPANDED_HIT_STRIP_WIDTH = "22rem";211const TIMELINE_MINIMAP_EXPANDED_HIT_STRIP_WIDTH = "22rem";
213212
214/**213/**
215 * The minimap overlays the viewport's left edge while the content column is214 * The minimap overlays the viewport's left edge while the content column is
apps/web/src/components/chat/externalLinkContextMenu.ts+1-1
...@@ -35,7 +35,7 @@ const EXTERNAL_LINK_CONTEXT_MENU_ITEMS = [...@@ -35,7 +35,7 @@ const EXTERNAL_LINK_CONTEXT_MENU_ITEMS = [
35 * whole menu with the one item that cannot be honoured is what left a right-click on a link35 * whole menu with the one item that cannot be honoured is what left a right-click on a link
36 * showing the platform's cut-and-paste menu instead of a way to copy the link.36 * showing the platform's cut-and-paste menu instead of a way to copy the link.
37 */37 */
38export function externalLinkContextMenuItems(options: {38function externalLinkContextMenuItems(options: {
39 readonly canOpenInPreview: boolean;39 readonly canOpenInPreview: boolean;
40 readonly threadLinkAction?: "link-to-thread" | "unlink-from-thread" | undefined;40 readonly threadLinkAction?: "link-to-thread" | "unlink-from-thread" | undefined;
41}): readonly ContextMenuItem<ExternalLinkContextMenuAction>[] {41}): readonly ContextMenuItem<ExternalLinkContextMenuAction>[] {
apps/web/src/components/cloud/CloudEnvironmentConnectList.tsx+1-1
...@@ -32,7 +32,7 @@ export interface SavedCloudEnvironmentConnection {...@@ -32,7 +32,7 @@ export interface SavedCloudEnvironmentConnection {
32 readonly connection: EnvironmentConnectionPresentation;32 readonly connection: EnvironmentConnectionPresentation;
33}33}
3434
35export function RemoteEnvironmentRowsSkeleton() {35function RemoteEnvironmentRowsSkeleton() {
36 return (36 return (
37 <div className={ITEM_ROW_CLASSNAME}>37 <div className={ITEM_ROW_CLASSNAME}>
38 <div className={ITEM_ROW_INNER_CLASSNAME}>38 <div className={ITEM_ROW_INNER_CLASSNAME}>
apps/web/src/components/composerFooterLayout.ts+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1export const COMPOSER_FOOTER_COMPACT_BREAKPOINT_PX = 620;1export const COMPOSER_FOOTER_COMPACT_BREAKPOINT_PX = 620;
2export const COMPOSER_FOOTER_WIDE_ACTIONS_COMPACT_BREAKPOINT_PX = 780;2export const COMPOSER_FOOTER_WIDE_ACTIONS_COMPACT_BREAKPOINT_PX = 780;
3export const RESTING_COMPOSER_IMAGE_THUMBNAIL_LIMIT = 3;3const RESTING_COMPOSER_IMAGE_THUMBNAIL_LIMIT = 3;
44
5export function getRestingComposerImagePreviewCounts(imageCount: number): {5export function getRestingComposerImagePreviewCounts(imageCount: number): {
6 visibleCount: number;6 visibleCount: number;
apps/web/src/components/files/projectFilesQueryState.ts+1-1
...@@ -33,7 +33,7 @@ interface ProjectQueryState<A> {...@@ -33,7 +33,7 @@ interface ProjectQueryState<A> {
33 readonly refresh: () => void;33 readonly refresh: () => void;
34}34}
3535
36export function getProjectEntriesQueryAtom(environmentId: EnvironmentId, cwd: string) {36function getProjectEntriesQueryAtom(environmentId: EnvironmentId, cwd: string) {
37 return projectEnvironment.listEntries({ environmentId, input: { cwd } });37 return projectEnvironment.listEntries({ environmentId, input: { cwd } });
38}38}
3939
apps/web/src/components/media/MediaActions.tsx+1-1
...@@ -33,7 +33,7 @@ function mediaFileName(source: MediaActionSource): string {...@@ -33,7 +33,7 @@ function mediaFileName(source: MediaActionSource): string {
33}33}
3434
35/** Explicit byte operations get fresh capabilities without replacing a player's active source. */35/** Explicit byte operations get fresh capabilities without replacing a player's active source. */
36export function useMediaActions(source: MediaActionSource) {36function useMediaActions(source: MediaActionSource) {
37 const createAssetUrl = useAtomQueryRunner(assetEnvironment.createUrl, {37 const createAssetUrl = useAtomQueryRunner(assetEnvironment.createUrl, {
38 reportFailure: false,38 reportFailure: false,
39 refresh: true,39 refresh: true,
apps/web/src/components/preview/previewAutomationErrors.ts+1-1
...@@ -216,7 +216,7 @@ export const PreviewAutomationHostError = Schema.Union([...@@ -216,7 +216,7 @@ export const PreviewAutomationHostError = Schema.Union([
216]);216]);
217export type PreviewAutomationHostError = typeof PreviewAutomationHostError.Type;217export type PreviewAutomationHostError = typeof PreviewAutomationHostError.Type;
218218
219export const isPreviewAutomationHostError = Schema.is(PreviewAutomationHostError);219const isPreviewAutomationHostError = Schema.is(PreviewAutomationHostError);
220220
221export function serializePreviewAutomationHostError(221export function serializePreviewAutomationHostError(
222 error: PreviewAutomationHostError,222 error: PreviewAutomationHostError,
apps/web/src/components/preview/previewMiniPlayerLayout.ts+1-1
...@@ -4,7 +4,7 @@ export const PREVIEW_MINI_PLAYER_EDGE_GAP = 12;...@@ -4,7 +4,7 @@ export const PREVIEW_MINI_PLAYER_EDGE_GAP = 12;
4// The mini-player shell straddles this webview at 47 and 49; dialogs begin at 50.4// The mini-player shell straddles this webview at 47 and 49; dialogs begin at 50.
5export const PREVIEW_MINI_PLAYER_WEBVIEW_Z_INDEX = 48;5export const PREVIEW_MINI_PLAYER_WEBVIEW_Z_INDEX = 48;
6export const PREVIEW_MINI_PLAYER_DEFAULT_SIZE = { width: 320, height: 200 } as const;6export const PREVIEW_MINI_PLAYER_DEFAULT_SIZE = { width: 320, height: 200 } as const;
7export const PREVIEW_MINI_PLAYER_MIN_SIZE = { width: 240, height: 150 } as const;7const PREVIEW_MINI_PLAYER_MIN_SIZE = { width: 240, height: 150 } as const;
88
9export function clampPreviewMiniPlayerSize(9export function clampPreviewMiniPlayerSize(
10 size: PreviewMiniPlayerSize,10 size: PreviewMiniPlayerSize,
apps/web/src/components/projectScriptEditor.tsx+1-1
...@@ -49,7 +49,7 @@ import { Popover, PopoverPopup, PopoverTrigger } from "./ui/popover";...@@ -49,7 +49,7 @@ import { Popover, PopoverPopup, PopoverTrigger } from "./ui/popover";
49import { Switch } from "./ui/switch";49import { Switch } from "./ui/switch";
50import { Textarea } from "./ui/textarea";50import { Textarea } from "./ui/textarea";
5151
52export const SCRIPT_ICONS: Array<{ id: ProjectScriptIcon; label: string }> = [52const SCRIPT_ICONS: Array<{ id: ProjectScriptIcon; label: string }> = [
53 { id: "play", label: "Play" },53 { id: "play", label: "Play" },
54 { id: "test", label: "Test" },54 { id: "test", label: "Test" },
55 { id: "lint", label: "Lint" },55 { id: "lint", label: "Lint" },
apps/web/src/components/pullRequest/PullRequestCodeTab.tsx+1-1
...@@ -187,7 +187,7 @@ function getReviewPositionAnchor(position: PullRequestReviewPosition): {...@@ -187,7 +187,7 @@ function getReviewPositionAnchor(position: PullRequestReviewPosition): {
187 * host sit under the line they were written on, and a new comment joins the review being187 * host sit under the line they were written on, and a new comment joins the review being
188 * drafted rather than being posted as it is typed.188 * drafted rather than being posted as it is typed.
189 */189 */
190export function PullRequestCodeTab({190function PullRequestCodeTab({
191 environmentId,191 environmentId,
192 reference,192 reference,
193 detail,193 detail,
apps/web/src/components/pullRequest/pullRequestLinkContextMenu.ts+1-1
...@@ -8,7 +8,7 @@ import { toastManager } from "../ui/toast";...@@ -8,7 +8,7 @@ import { toastManager } from "../ui/toast";
8export type PullRequestLinkContextMenuAction = "copy-link" | "open-external";8export type PullRequestLinkContextMenuAction = "copy-link" | "open-external";
99
10/** Named for the host rather than "externally": the point is where you will land. */10/** Named for the host rather than "externally": the point is where you will land. */
11export const OPEN_ON_HOST_LABELS: Partial<Record<string, string>> = {11const OPEN_ON_HOST_LABELS: Partial<Record<string, string>> = {
12 github: "Open on GitHub",12 github: "Open on GitHub",
13 gitlab: "Open on GitLab",13 gitlab: "Open on GitLab",
14 bitbucket: "Open on Bitbucket",14 bitbucket: "Open on Bitbucket",
apps/web/src/components/pullRequest/pullRequestList.logic.ts+1-1
...@@ -67,7 +67,7 @@ export type PullRequestViewers = PullRequestListResult["viewers"];...@@ -67,7 +67,7 @@ export type PullRequestViewers = PullRequestListResult["viewers"];
67/** A row plus the environment that read it, where the caller has one to give. */67/** A row plus the environment that read it, where the caller has one to give. */
68type ScopedEntry = PullRequestListEntry & { readonly environmentId?: string };68type ScopedEntry = PullRequestListEntry & { readonly environmentId?: string };
6969
70export const pullRequestViewerKey = (entry: ScopedEntry): string =>70const pullRequestViewerKey = (entry: ScopedEntry): string =>
71 `${entry.environmentId ?? ""} ${entry.host}`;71 `${entry.environmentId ?? ""} ${entry.host}`;
7272
73const GROUP_LABELS: Record<PullRequestGroupKey, string> = {73const GROUP_LABELS: Record<PullRequestGroupKey, string> = {
apps/web/src/components/pullRequest/pullRequestListPreferences.ts+1-1
...@@ -37,7 +37,7 @@ export type PullRequestListPreferencePatch = {...@@ -37,7 +37,7 @@ export type PullRequestListPreferencePatch = {
37 [Key in keyof PullRequestListPreferences]?: PullRequestListPreferences[Key] | undefined;37 [Key in keyof PullRequestListPreferences]?: PullRequestListPreferences[Key] | undefined;
38};38};
3939
40export const DEFAULT_PULL_REQUEST_LIST_PREFERENCES = {40const DEFAULT_PULL_REQUEST_LIST_PREFERENCES = {
41 involvement: "all",41 involvement: "all",
42 state: "open",42 state: "open",
43} as const satisfies PullRequestListPreferences;43} as const satisfies PullRequestListPreferences;
apps/web/src/components/settings/KeybindingsSettings.logic.ts+1-1
...@@ -291,7 +291,7 @@ function titleCaseCommandSegment(segment: string): string {...@@ -291,7 +291,7 @@ function titleCaseCommandSegment(segment: string): string {
291 return words.join(" ");291 return words.join(" ");
292}292}
293293
294export function normalizeShortcutKeyToken(key: string): string | null {294function normalizeShortcutKeyToken(key: string): string | null {
295 const normalized = key.toLowerCase();295 const normalized = key.toLowerCase();
296 if (296 if (
297 normalized === "meta" ||297 normalized === "meta" ||
apps/web/src/components/settings/ProjectSettingsPanel.tsx+3-3
...@@ -127,14 +127,14 @@ const ProjectIconPickerDialog = lazy(() =>...@@ -127,14 +127,14 @@ const ProjectIconPickerDialog = lazy(() =>
127 })),127 })),
128);128);
129129
130export const PROJECT_GROUPING_MODE_LABELS: Record<SidebarProjectGroupingMode, string> = {130const PROJECT_GROUPING_MODE_LABELS: Record<SidebarProjectGroupingMode, string> = {
131 repository: "Group by repository",131 repository: "Group by repository",
132 repository_path: "Group by repository path",132 repository_path: "Group by repository path",
133 separate: "Keep separate",133 separate: "Keep separate",
134};134};
135135
136/** Logical project groups for the settings page, sorted by display name. */136/** Logical project groups for the settings page, sorted by display name. */
137export function useSettingsProjectGroups(): SidebarProjectSnapshot[] {137function useSettingsProjectGroups(): SidebarProjectSnapshot[] {
138 const projects = useProjects();138 const projects = useProjects();
139 const projectGroupingSettings = useClientSettings(selectProjectGroupingSettings);139 const projectGroupingSettings = useClientSettings(selectProjectGroupingSettings);
140 const primaryEnvironmentId = usePrimaryEnvironmentId();140 const primaryEnvironmentId = usePrimaryEnvironmentId();
...@@ -253,7 +253,7 @@ function ProjectSettingsBreadcrumb({ projectKey }: { projectKey: string }) {...@@ -253,7 +253,7 @@ function ProjectSettingsBreadcrumb({ projectKey }: { projectKey: string }) {
253 );253 );
254}254}
255255
256export function ProjectSettingsPanel({ projectKey }: { projectKey: string }) {256function ProjectSettingsPanel({ projectKey }: { projectKey: string }) {
257 const groups = useSettingsProjectGroups();257 const groups = useSettingsProjectGroups();
258 const navigate = useNavigate();258 const navigate = useNavigate();
259259
apps/web/src/components/settings/SettingsSidebarNav.tsx+1-1
...@@ -80,7 +80,7 @@ const SETTINGS_SECTION_ICONS: Readonly<...@@ -80,7 +80,7 @@ const SETTINGS_SECTION_ICONS: Readonly<
80 "/settings/archived": ArchiveIcon,80 "/settings/archived": ArchiveIcon,
81};81};
8282
83export const SETTINGS_NAV_ITEMS: ReadonlyArray<{83const SETTINGS_NAV_ITEMS: ReadonlyArray<{
84 label: string;84 label: string;
85 to: SettingsPath;85 to: SettingsPath;
86 icon: ComponentType<{ className?: string }>;86 icon: ComponentType<{ className?: string }>;
apps/web/src/components/settings/ThemeWireframe.tsx+1-1
...@@ -4,7 +4,7 @@ import type { ThemeCardPreviewColors } from "./ThemePreviewCircles";...@@ -4,7 +4,7 @@ import type { ThemeCardPreviewColors } from "./ThemePreviewCircles";
4// A simple miniature of the app: sidebar, a short conversation, the4// A simple miniature of the app: sidebar, a short conversation, the
5// composer, and the orchestrator panel floating over the interface as an5// composer, and the orchestrator panel floating over the interface as an
6// island with horizontal agent rows.6// island with horizontal agent rows.
7export function ThemeWireframePane({7function ThemeWireframePane({
8 colors,8 colors,
9 clip,9 clip,
10}: {10}: {
apps/web/src/components/settings/customModelEditor.logic.ts+2-2
...@@ -104,7 +104,7 @@ export const DESCRIPTOR_PRESETS_BY_KIND: Partial<...@@ -104,7 +104,7 @@ export const DESCRIPTOR_PRESETS_BY_KIND: Partial<
104};104};
105105
106let nextKey = 0;106let nextKey = 0;
107export function newEditorKey(): string {107function newEditorKey(): string {
108 nextKey += 1;108 nextKey += 1;
109 return `k${nextKey}`;109 return `k${nextKey}`;
110}110}
...@@ -140,7 +140,7 @@ export function emptyEditorChoice(): EditorChoice {...@@ -140,7 +140,7 @@ export function emptyEditorChoice(): EditorChoice {
140 * by built-in runtime profiles a custom entry does not have, so they are140 * by built-in runtime profiles a custom entry does not have, so they are
141 * dropped rather than stored as a plain option value.141 * dropped rather than stored as a plain option value.
142 */142 */
143export function descriptorToEditor(descriptor: ProviderOptionDescriptor): EditorDescriptor {143function descriptorToEditor(descriptor: ProviderOptionDescriptor): EditorDescriptor {
144 const promptInjected = new Set(144 const promptInjected = new Set(
145 descriptor.type === "select" ? (descriptor.promptInjectedValues ?? []) : [],145 descriptor.type === "select" ? (descriptor.promptInjectedValues ?? []) : [],
146 );146 );
apps/web/src/components/settings/providerDriverMeta.ts+2-2
...@@ -43,7 +43,7 @@ export interface ProviderClientDefinition {...@@ -43,7 +43,7 @@ export interface ProviderClientDefinition {
43 readonly badgeLabel?: string;43 readonly badgeLabel?: string;
44}44}
4545
46export const PROVIDER_CLIENT_DEFINITIONS: readonly ProviderClientDefinition[] = [46const PROVIDER_CLIENT_DEFINITIONS: readonly ProviderClientDefinition[] = [
47 {47 {
48 value: ProviderDriverKind.make("codex"),48 value: ProviderDriverKind.make("codex"),
49 label: "Codex",49 label: "Codex",
...@@ -84,7 +84,7 @@ export const PROVIDER_CLIENT_DEFINITIONS: readonly ProviderClientDefinition[] =...@@ -84,7 +84,7 @@ export const PROVIDER_CLIENT_DEFINITIONS: readonly ProviderClientDefinition[] =
84 },84 },
85];85];
8686
87export const PROVIDER_CLIENT_DEFINITION_BY_VALUE: Partial<87const PROVIDER_CLIENT_DEFINITION_BY_VALUE: Partial<
88 Record<ProviderDriverKind, ProviderClientDefinition>88 Record<ProviderDriverKind, ProviderClientDefinition>
89> = Object.fromEntries(89> = Object.fromEntries(
90 PROVIDER_CLIENT_DEFINITIONS.map((definition) => [definition.value, definition]),90 PROVIDER_CLIENT_DEFINITIONS.map((definition) => [definition.value, definition]),
apps/web/src/components/settings/themeInspector.ts+1-1
...@@ -14,7 +14,7 @@ const THEME_PAINT_KIND_ORDER: ReadonlyArray<ThemePaintKind> = [...@@ -14,7 +14,7 @@ const THEME_PAINT_KIND_ORDER: ReadonlyArray<ThemePaintKind> = [
14 "foreground",14 "foreground",
15];15];
1616
17export const THEME_INSPECTOR_MATCH_ATTRIBUTE = "data-theme-inspector-match";17const THEME_INSPECTOR_MATCH_ATTRIBUTE = "data-theme-inspector-match";
1818
19const THEME_TOKEN_PROBE_ATTRIBUTE = "data-theme-token-probe";19const THEME_TOKEN_PROBE_ATTRIBUTE = "data-theme-token-probe";
20const THEME_TOKEN_PROBE_COLOR = "#01fea7";20const THEME_TOKEN_PROBE_COLOR = "#01fea7";