@alivault/pico 0.10.1 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ import { i as __toESM } from "../_runtime.mjs";
2
2
  import { $ as require_react, A as TabsTab, B as Input, C as MenuPositioner, D as MenuGroupLabel, E as MenuItem, F as DialogPopup, H as useRender, I as DialogDescription$1, L as DialogClose, M as DialogTitle$1, N as DialogRoot, O as MenuGroup, P as DialogPortal$1, Q as require_jsx_runtime, R as DialogBackdrop, S as MenuRoot, T as MenuPopup, V as Button, Y as mergeProps, _ as AccordionItem$1, a as ContextMenuRoot, b as MenuTrigger, c as CollapsibleRoot, d as PopoverPortal, f as PopoverTrigger$1, g as AccordionHeader, h as AccordionTrigger$1, i as ContextMenuTrigger$1, j as TabsRoot, k as TabsList$1, l as PopoverPopup, m as AccordionPanel, n as ToggleGroup, o as CollapsiblePanel, p as PopoverRoot, r as Toggle, s as CollapsibleTrigger$1, t as AlertDialogRoot, u as PopoverPositioner, v as AccordionRoot, w as MenuPortal, x as MenuSubmenuRoot, y as MenuSubmenuTrigger, z as Separator } from "../_libs/@base-ui/react+[...].mjs";
3
3
  import { t as cva } from "../_libs/class-variance-authority+clsx.mjs";
4
4
  import { A as ExternalLink, B as ChevronRight, C as ImagePlus, D as Folder, E as GitCommitHorizontal, F as Command, G as ArrowUpRight, H as Check, J as ArrowDown, L as ChevronsUpDown, M as EllipsisVertical, N as Download, O as FolderPlus, P as Copy, R as ChevronsDownUp, T as GitBranch, U as ArrowUp, V as ChevronDown, W as ArrowUpToLine, _ as OctagonX, a as TriangleAlert, b as ListStart, c as SquarePen, d as Plus, f as PanelRight, h as PanelLeftClose, i as Undo2, j as Ellipsis, k as FileDiff, l as Settings2, m as PanelLeftOpen, n as WandSparkles, o as Tag, p as PanelLeft, q as ArrowLeft, r as Upload, s as Square, t as X, u as Search, v as Minimize2, w as GitPullRequestArrow, x as ListEnd, y as Maximize2 } from "../_libs/lucide-react.mjs";
5
- import { $ as promptDraftKeyMatchesOwner, C as THEME_COLOR_MODES, D as TitleTooltip, E as THEME_STORAGE_KEY, F as buildItemsFromSync, I as cn, J as normalizeStoredDirectoryList, K as normalizePromptImage, M as VIEWER_CONTEXT_STORAGE_KEY, N as appliedThemeClass, O as Tooltip$1, Q as promptDraftKey, R as createContextId, S as Spinner, T as THEME_FAMILIES, U as flattenTree, W as getSessionTitle, X as normalizeThemeFamily, Y as normalizeThemeColorMode, Z as previewUrlForImage, _ as RIGHT_SIDEBAR_WIDTHS_STORAGE_KEY, _t as sameContextUsage, a as COLLAPSED_DIRECTORIES_STORAGE_KEY, at as readStoredPinnedSessionKeys, b as SESSION_DONE_SOUND_ENABLED_STORAGE_KEY, bt as themeFamilyLabel, c as Kbd, ct as readStoredRightSidebarOpen, d as RECENT_DIRECTORIES_STORAGE_KEY, dt as readStoredSidebarDirectories, et as readStoredAutoScrollEnabled, f as RIGHT_SIDEBAR_ACTIVE_TAB_STORAGE_KEY, ft as readStoredTheme, g as RIGHT_SIDEBAR_OPEN_STORAGE_KEY, gt as safeLocalStorageSetItem, h as RIGHT_SIDEBAR_HISTORY_TAB_STORAGE_KEY, ht as safeLocalStorageGetItem, i as CENTER_MESSAGES_STORAGE_KEY, it as readStoredHideToolBlocks, j as TooltipTrigger, k as TooltipContent, l as KeyboardShortcutContent, lt as readStoredSessionDoneDesktopNotificationsEnabled, m as RIGHT_SIDEBAR_HISTORY_HEIGHT_STORAGE_KEY, mt as rememberStoredPromptDraft, n as APPLIED_THEME_STORAGE_KEY, nt as readStoredCollapsedDirectories, o as DRAFT_DIRECTORY_STORAGE_KEY, ot as readStoredPromptDraft, p as RIGHT_SIDEBAR_FILE_TREE_WIDTH_STORAGE_KEY, pt as readStoredThemeColorMode, q as normalizeSessionSelectionKeys, r as AUTO_SCROLL_ENABLED_STORAGE_KEY, rt as readStoredDraftDirectory, s as HIDE_TOOL_BLOCKS_STORAGE_KEY, st as readStoredRecentDirectories, tt as readStoredCenterMessages, u as PINNED_SESSIONS_STORAGE_KEY, ut as readStoredSessionDoneSoundEnabled, v as Route, vt as sessionListEntryKey, w as THEME_COLOR_MODE_STORAGE_KEY, x as SIDEBAR_DIRECTORIES_STORAGE_KEY, xt as thinkingSummaryText, y as SESSION_DONE_DESKTOP_NOTIFICATIONS_ENABLED_STORAGE_KEY, yt as themeColorModeLabel, z as createInitialSessionState } from "./routes-DbGwM-bj.mjs";
5
+ import { $ as normalizeThemeFamily, A as Tooltip$1, C as SESSION_DONE_SOUND_ENABLED_STORAGE_KEY, Ct as themeFamilyDescription, D as THEME_FAMILIES, Dt as themeFamilySupportsColorMode, E as THEME_COLOR_MODE_STORAGE_KEY, Et as themeFamilyLabel, F as appliedThemeClass, H as createInitialSessionState, I as appliedThemeClassColorMode, K as flattenTree, N as TooltipTrigger, O as THEME_STORAGE_KEY, Ot as thinkingSummaryText, P as VIEWER_CONTEXT_STORAGE_KEY, Q as normalizeThemeColorMode, R as buildItemsFromSync, S as SESSION_DONE_DESKTOP_NOTIFICATIONS_ENABLED_STORAGE_KEY, St as themeColorModeLabel, T as Spinner, Tt as themeFamilyKeywords, V as createContextId, X as normalizeSessionSelectionKeys, Y as normalizePromptImage, Z as normalizeStoredDirectoryList, _ as RIGHT_SIDEBAR_HISTORY_HEIGHT_STORAGE_KEY, _t as rememberStoredPromptDraft, a as COLLAPSED_DIRECTORIES_STORAGE_KEY, at as readStoredCollapsedDirectories, b as RIGHT_SIDEBAR_WIDTHS_STORAGE_KEY, bt as sameContextUsage, c as Kbd, ct as readStoredPinnedSessionKeys, d as PICO_DIFF_SHIKI_THEMES, dt as readStoredRightSidebarOpen, et as previewUrlForImage, f as PICO_SHIKI_VARIABLE_DEFAULTS, ft as readStoredSessionDoneDesktopNotificationsEnabled, g as RIGHT_SIDEBAR_FILE_TREE_WIDTH_STORAGE_KEY, gt as readStoredThemeColorMode, h as RIGHT_SIDEBAR_ACTIVE_TAB_STORAGE_KEY, ht as readStoredTheme, i as CENTER_MESSAGES_STORAGE_KEY, it as readStoredCenterMessages, j as TooltipContent, k as TitleTooltip, l as KeyboardShortcutContent, lt as readStoredPromptDraft, m as RECENT_DIRECTORIES_STORAGE_KEY, mt as readStoredSidebarDirectories, n as APPLIED_THEME_STORAGE_KEY, nt as promptDraftKeyMatchesOwner, o as DRAFT_DIRECTORY_STORAGE_KEY, ot as readStoredDraftDirectory, p as PINNED_SESSIONS_STORAGE_KEY, pt as readStoredSessionDoneSoundEnabled, q as getSessionTitle, r as AUTO_SCROLL_ENABLED_STORAGE_KEY, rt as readStoredAutoScrollEnabled, s as HIDE_TOOL_BLOCKS_STORAGE_KEY, st as readStoredHideToolBlocks, tt as promptDraftKey, ut as readStoredRecentDirectories, v as RIGHT_SIDEBAR_HISTORY_TAB_STORAGE_KEY, vt as safeLocalStorageGetItem, w as SIDEBAR_DIRECTORIES_STORAGE_KEY, wt as themeFamilyFixedMode, x as Route, xt as sessionListEntryKey, y as RIGHT_SIDEBAR_OPEN_STORAGE_KEY, yt as safeLocalStorageSetItem, z as cn } from "./routes-CHNxptm_.mjs";
6
6
  import { i as useQuery, n as useIsMutating, o as useQueryClient, r as useIsFetching, t as useMutation } from "../_libs/tanstack__react-query.mjs";
7
7
  import { t as useHotkeys } from "../_libs/tanstack__react-hotkeys.mjs";
8
8
  import { a as matchesKeyboardEvent, i as batch, o as formatForDisplay, r as createStore } from "../_libs/@tanstack/hotkeys+[...].mjs";
@@ -10,10 +10,10 @@ import { t as shallow } from "../_libs/tanstack__store.mjs";
10
10
  import { t as useSelector } from "../_libs/tanstack__react-store.mjs";
11
11
  import { n as z } from "../_libs/next-themes.mjs";
12
12
  import { n as toast } from "../_libs/sonner.mjs";
13
+ import { a as registerCustomTheme, i as parsePatchFiles, n as MultiFileDiff, o as RegisteredCustomThemes, r as FileDiff$1, t as PatchDiff, u as createCssVariablesTheme } from "../_libs/@pierre/diffs+[...].mjs";
13
14
  import { i as AsyncDebouncer, r as Batcher, t as Throttler } from "../_libs/tanstack__pacer.mjs";
14
15
  import { t as _e } from "../_libs/cmdk.mjs";
15
16
  import { t as Drawer } from "../_libs/vaul.mjs";
16
- import { i as parsePatchFiles, n as MultiFileDiff, r as FileDiff$1, t as PatchDiff } from "../_libs/@pierre/diffs+[...].mjs";
17
17
  import { t as Markdown } from "../_libs/react-markdown+[...].mjs";
18
18
  import { t as rehypeRaw } from "../_libs/rehype-raw.mjs";
19
19
  import { n as defaultSchema } from "../_libs/hast-util-sanitize.mjs";
@@ -22,7 +22,7 @@ import { t as remarkGfm } from "../_libs/remark-gfm.mjs";
22
22
  import { a as getBuiltInSpriteSheet, i as getBuiltInFileIconColor, n as FileTree, r as createFileTreeIconResolver, t as useFileTree } from "../_libs/@pierre/trees+[...].mjs";
23
23
  import { a as closestCenter, c as useDraggable, d as useSensors, f as CSS$1, i as PointerSensor, n as DragOverlay, t as DndContext, u as useSensor } from "../_libs/@dnd-kit/core+[...].mjs";
24
24
  import { a as verticalListSortingStrategy, i as useSortable, n as arrayMove, r as horizontalListSortingStrategy, t as SortableContext } from "../_libs/dnd-kit__sortable.mjs";
25
- //#region node_modules/.nitro/vite/services/ssr/assets/routes-NB2wmfpS.js
25
+ //#region node_modules/.nitro/vite/services/ssr/assets/routes-CELGJtcT.js
26
26
  var import_react = /* @__PURE__ */ __toESM(require_react());
27
27
  var import_jsx_runtime = require_jsx_runtime();
28
28
  var MOBILE_BREAKPOINT = 768;
@@ -980,7 +980,7 @@ function CommandGroup({ className, ...props }) {
980
980
  function CommandItem({ className, children, ...props }) {
981
981
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(_e.Item, {
982
982
  "data-slot": "command-item",
983
- className: cn("group/command-item relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none in-data-[slot=dialog-content]:rounded-lg! data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-selected:bg-muted data-selected:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-selected:*:[svg]:text-foreground", className),
983
+ className: cn("group/command-item relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none in-data-[slot=dialog-content]:rounded-lg! data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-selected:bg-accent data-selected:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-selected:*:[svg]:text-foreground", className),
984
984
  ...props,
985
985
  children: [children, /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: "ml-auto opacity-0 group-has-data-[slot=command-shortcut]/command-item:hidden group-data-[checked=true]/command-item:opacity-100" })]
986
986
  });
@@ -3100,19 +3100,84 @@ function AppShellSessionsDialogController({ ref, openStateRef, ...props }) {
3100
3100
  });
3101
3101
  }
3102
3102
  var THEME_OPTIONS = [...THEME_FAMILIES];
3103
- var THEME_COLOR_MODE_OPTIONS = [...THEME_COLOR_MODES];
3104
- function createInitialSettingsDialogState(currentTheme) {
3103
+ var THEME_SELECTION_SECTIONS = [
3104
+ {
3105
+ heading: "Auto",
3106
+ colorMode: "auto"
3107
+ },
3108
+ {
3109
+ heading: "Dark",
3110
+ colorMode: "dark"
3111
+ },
3112
+ {
3113
+ heading: "Light",
3114
+ colorMode: "light"
3115
+ }
3116
+ ].map((section) => ({
3117
+ ...section,
3118
+ themes: THEME_OPTIONS.filter((theme) => themeFamilySupportsColorMode(theme, section.colorMode))
3119
+ }));
3120
+ var SETTINGS_DIALOG_AUTO_FOCUS_MEDIA = "(min-width: 768px)";
3121
+ function shouldAutoFocusSettingsDialogInput() {
3122
+ return typeof window !== "undefined" && window.matchMedia(SETTINGS_DIALOG_AUTO_FOCUS_MEDIA).matches;
3123
+ }
3124
+ function isThemeColorMode(value) {
3125
+ return value === "auto" || value === "light" || value === "dark";
3126
+ }
3127
+ function themeSelectionKey(selection) {
3128
+ return `${selection.colorMode}:${selection.theme}`;
3129
+ }
3130
+ function themeSelectionFromKey(value) {
3131
+ const separatorIndex = value.indexOf(":");
3132
+ if (separatorIndex < 0) return void 0;
3133
+ const colorMode = value.slice(0, separatorIndex);
3134
+ const theme = value.slice(separatorIndex + 1);
3135
+ if (!isThemeColorMode(colorMode)) return void 0;
3136
+ if (!THEME_OPTIONS.includes(theme)) return void 0;
3137
+ const normalizedTheme = theme;
3138
+ if (!themeFamilySupportsColorMode(normalizedTheme, colorMode)) return;
3139
+ return {
3140
+ theme: normalizedTheme,
3141
+ colorMode
3142
+ };
3143
+ }
3144
+ function themeSelectionForCurrent(theme, colorMode) {
3145
+ return {
3146
+ theme,
3147
+ colorMode: themeFamilyFixedMode(theme) ?? colorMode
3148
+ };
3149
+ }
3150
+ function themeSelectionModeLabel(selection, systemTheme) {
3151
+ if (selection.colorMode === "auto") return themeColorModeLabel(selection.colorMode, systemTheme);
3152
+ return selection.colorMode === "light" ? "Light" : "Dark";
3153
+ }
3154
+ function themeSelectionValueLabel(selection, systemTheme) {
3155
+ return `${themeFamilyLabel(selection.theme)} · ${themeSelectionModeLabel(selection, systemTheme)}`;
3156
+ }
3157
+ function themeSelectionDescription(selection) {
3158
+ if (selection.colorMode === "auto") return `Auto: ${themeFamilyDescription(selection.theme)}`;
3159
+ if (themeFamilyFixedMode(selection.theme)) return `${themeSelectionModeLabel(selection)} only: ${themeFamilyDescription(selection.theme)}`;
3160
+ return themeFamilyDescription(selection.theme);
3161
+ }
3162
+ function themeSelectionKeywords(selection) {
3163
+ return [
3164
+ selection.colorMode,
3165
+ themeSelectionModeLabel(selection),
3166
+ ...themeFamilyKeywords(selection.theme)
3167
+ ];
3168
+ }
3169
+ function createInitialSettingsDialogState(currentTheme, currentThemeColorMode) {
3105
3170
  return {
3106
3171
  query: "",
3107
3172
  themeQuery: "",
3108
3173
  stage: "browse",
3109
3174
  selectedCommandId: "theme",
3110
- selectedTheme: currentTheme
3175
+ selectedTheme: themeSelectionForCurrent(currentTheme, currentThemeColorMode)
3111
3176
  };
3112
3177
  }
3113
3178
  function settingsDialogReducer(state, action) {
3114
3179
  switch (action.type) {
3115
- case "reset": return createInitialSettingsDialogState(action.currentTheme);
3180
+ case "reset": return createInitialSettingsDialogState(action.currentTheme, action.currentThemeColorMode);
3116
3181
  case "set-query": return {
3117
3182
  ...state,
3118
3183
  query: action.query
@@ -3128,7 +3193,7 @@ function settingsDialogReducer(state, action) {
3128
3193
  case "open-theme": return {
3129
3194
  ...state,
3130
3195
  stage: "theme",
3131
- selectedTheme: action.currentTheme
3196
+ selectedTheme: themeSelectionForCurrent(action.currentTheme, action.currentThemeColorMode)
3132
3197
  };
3133
3198
  case "close-theme": return {
3134
3199
  ...state,
@@ -3150,23 +3215,6 @@ function desktopNotificationPermissionLabel(permission) {
3150
3215
  function formatToggleValue(enabled) {
3151
3216
  return enabled ? "On" : "Off";
3152
3217
  }
3153
- function nextThemeColorMode(currentMode) {
3154
- return THEME_COLOR_MODE_OPTIONS[(THEME_COLOR_MODE_OPTIONS.indexOf(currentMode) + 1) % THEME_COLOR_MODE_OPTIONS.length] ?? "auto";
3155
- }
3156
- function themeDescription(theme) {
3157
- switch (theme) {
3158
- case "default": return "Use Pico's default palette.";
3159
- case "flexoki": return "Use Flexoki's warm paper and inky dark palettes.";
3160
- default: return "Use this theme.";
3161
- }
3162
- }
3163
- function themeKeywords(theme) {
3164
- return [
3165
- theme,
3166
- themeFamilyLabel(theme),
3167
- themeDescription(theme)
3168
- ];
3169
- }
3170
3218
  function settingsCommandKeywords(command) {
3171
3219
  return [
3172
3220
  command.title,
@@ -3180,7 +3228,7 @@ function settingsCommandFilter(value, search, keywords) {
3180
3228
  if (!query) return 1;
3181
3229
  return [value, ...keywords ?? []].join(" ").toLowerCase().includes(query) ? 1 : 0;
3182
3230
  }
3183
- function getSettingsCommandGroups({ currentTheme, currentThemeColorMode, systemTheme, hideThinkingBlocks, onHideThinkingBlocksChange, hideToolBlocks, onHideToolBlocksChange, centerMessages, onCenterMessagesChange, autoScrollEnabled, onAutoScrollEnabledChange, sessionDoneSoundEnabled, onSessionDoneSoundEnabledChange, sessionDoneDesktopNotificationsEnabled, onSessionDoneDesktopNotificationsEnabledChange, desktopNotificationPermission, onLoginProviders, onLogoutProviders, onThemeCommand, onThemeColorModeCommand }) {
3231
+ function getSettingsCommandGroups({ currentTheme, currentThemeColorMode, systemTheme, hideThinkingBlocks, onHideThinkingBlocksChange, hideToolBlocks, onHideToolBlocksChange, centerMessages, onCenterMessagesChange, autoScrollEnabled, onAutoScrollEnabledChange, sessionDoneSoundEnabled, onSessionDoneSoundEnabledChange, sessionDoneDesktopNotificationsEnabled, onSessionDoneDesktopNotificationsEnabledChange, desktopNotificationPermission, onLoginProviders, onLogoutProviders, onThemeCommand }) {
3184
3232
  const desktopNotificationDescription = desktopNotificationPermissionLabel(desktopNotificationPermission);
3185
3233
  return [
3186
3234
  {
@@ -3188,29 +3236,19 @@ function getSettingsCommandGroups({ currentTheme, currentThemeColorMode, systemT
3188
3236
  commands: [{
3189
3237
  id: "theme",
3190
3238
  title: "Theme",
3191
- description: "Choose between Default and Flexoki.",
3192
- valueLabel: themeFamilyLabel(currentTheme),
3193
- keywords: [
3194
- "color",
3195
- "mode",
3196
- "default",
3197
- "flexoki"
3198
- ],
3199
- onSelect: onThemeCommand
3200
- }, {
3201
- id: "theme-color-mode",
3202
- title: "Light/dark mode",
3203
- description: "Follow OS appearance, or force light or dark mode.",
3204
- valueLabel: themeColorModeLabel(currentThemeColorMode, systemTheme),
3239
+ description: "Choose an auto, dark, or light color palette.",
3240
+ valueLabel: themeSelectionValueLabel(themeSelectionForCurrent(currentTheme, currentThemeColorMode), systemTheme),
3205
3241
  keywords: [
3206
3242
  "auto",
3207
3243
  "system",
3208
3244
  "light",
3209
3245
  "dark",
3246
+ "color",
3210
3247
  "mode",
3211
- "color"
3248
+ "palette",
3249
+ ...THEME_OPTIONS.flatMap((theme) => themeFamilyKeywords(theme))
3212
3250
  ],
3213
- onSelect: onThemeColorModeCommand
3251
+ onSelect: onThemeCommand
3214
3252
  }]
3215
3253
  },
3216
3254
  {
@@ -3334,6 +3372,11 @@ function getSettingsCommandGroups({ currentTheme, currentThemeColorMode, systemT
3334
3372
  ];
3335
3373
  }
3336
3374
  function SettingsBrowseBody({ query, selectedCommandId, settingGroups, onQueryChange, onSelectedCommandIdChange, onSelectCommand }) {
3375
+ const inputRef = import_react.useRef(null);
3376
+ import_react.useEffect(() => {
3377
+ if (!shouldAutoFocusSettingsDialogInput()) return;
3378
+ inputRef.current?.focus();
3379
+ }, []);
3337
3380
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Command$1, {
3338
3381
  shouldFilter: true,
3339
3382
  filter: settingsCommandFilter,
@@ -3343,6 +3386,7 @@ function SettingsBrowseBody({ query, selectedCommandId, settingGroups, onQueryCh
3343
3386
  className: "min-h-0 flex-1",
3344
3387
  children: [
3345
3388
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandInput, {
3389
+ ref: inputRef,
3346
3390
  value: query,
3347
3391
  onValueChange: onQueryChange,
3348
3392
  placeholder: "Search settings",
@@ -3380,7 +3424,12 @@ function SettingsBrowseBody({ query, selectedCommandId, settingGroups, onQueryCh
3380
3424
  ]
3381
3425
  });
3382
3426
  }
3383
- function SettingsThemeBody({ currentTheme, selectedTheme, themeQuery, onThemeQueryChange, onThemePreview, onThemeSelect, onCancelThemePreview }) {
3427
+ function SettingsThemeBody({ currentTheme, currentThemeColorMode, selectedTheme, systemTheme, themeQuery, onThemeQueryChange, onThemePreview, onThemeSelect, onCancelThemePreview }) {
3428
+ const inputRef = import_react.useRef(null);
3429
+ import_react.useEffect(() => {
3430
+ if (!shouldAutoFocusSettingsDialogInput()) return;
3431
+ inputRef.current?.focus();
3432
+ }, []);
3384
3433
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
3385
3434
  role: "presentation",
3386
3435
  className: "flex min-h-0 flex-1 flex-col",
@@ -3406,17 +3455,25 @@ function SettingsThemeBody({ currentTheme, selectedTheme, themeQuery, onThemeQue
3406
3455
  children: "Choose theme"
3407
3456
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
3408
3457
  className: "truncate text-xs text-muted-foreground",
3409
- children: ["Current: ", themeFamilyLabel(currentTheme)]
3458
+ children: [
3459
+ "Current:",
3460
+ " ",
3461
+ themeSelectionValueLabel(themeSelectionForCurrent(currentTheme, currentThemeColorMode), systemTheme)
3462
+ ]
3410
3463
  })]
3411
3464
  })]
3412
3465
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Command$1, {
3413
3466
  shouldFilter: true,
3414
3467
  loop: true,
3415
- value: selectedTheme,
3416
- onValueChange: (value) => onThemePreview(value),
3468
+ value: themeSelectionKey(selectedTheme),
3469
+ onValueChange: (value) => {
3470
+ const selection = themeSelectionFromKey(value);
3471
+ if (selection) onThemePreview(selection);
3472
+ },
3417
3473
  className: "min-h-0 flex-1 rounded-none!",
3418
3474
  children: [
3419
3475
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandInput, {
3476
+ ref: inputRef,
3420
3477
  value: themeQuery,
3421
3478
  onValueChange: onThemeQueryChange,
3422
3479
  placeholder: "Search themes",
@@ -3424,27 +3481,35 @@ function SettingsThemeBody({ currentTheme, selectedTheme, themeQuery, onThemeQue
3424
3481
  }),
3425
3482
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CommandList, {
3426
3483
  className: "max-h-none min-h-0 flex-1 md:max-h-[min(70vh,28rem)]",
3427
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandEmpty, { children: "No themes found." }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandGroup, {
3428
- heading: "Themes",
3429
- children: THEME_OPTIONS.map((theme) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandItem, {
3430
- value: theme,
3431
- keywords: themeKeywords(theme),
3432
- onMouseEnter: () => onThemePreview(theme),
3433
- onSelect: () => onThemeSelect(theme),
3434
- "data-checked": theme === currentTheme ? true : void 0,
3435
- className: "items-start py-2",
3436
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
3437
- className: "flex min-w-0 flex-1 flex-col gap-0.5",
3438
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
3439
- className: "truncate font-medium",
3440
- children: themeFamilyLabel(theme)
3441
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
3442
- className: "line-clamp-2 text-xs text-muted-foreground",
3443
- children: themeDescription(theme)
3444
- })]
3445
- })
3446
- }, theme))
3447
- })]
3484
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandEmpty, { children: "No themes found." }), THEME_SELECTION_SECTIONS.map((section) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandGroup, {
3485
+ heading: section.heading,
3486
+ className: "**:[[cmdk-group-heading]]:sticky **:[[cmdk-group-heading]]:top-0 **:[[cmdk-group-heading]]:z-10 **:[[cmdk-group-heading]]:bg-popover",
3487
+ children: section.themes.map((theme) => {
3488
+ const selection = {
3489
+ theme,
3490
+ colorMode: section.colorMode
3491
+ };
3492
+ const selectionKey = themeSelectionKey(selection);
3493
+ const currentSelection = themeSelectionForCurrent(currentTheme, currentThemeColorMode);
3494
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandItem, {
3495
+ value: selectionKey,
3496
+ keywords: themeSelectionKeywords(selection),
3497
+ onSelect: () => onThemeSelect(selection),
3498
+ "data-checked": selectionKey === themeSelectionKey(currentSelection) ? true : void 0,
3499
+ className: "items-start py-2",
3500
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
3501
+ className: "flex min-w-0 flex-1 flex-col gap-0.5",
3502
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
3503
+ className: "truncate font-medium",
3504
+ children: themeFamilyLabel(theme)
3505
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
3506
+ className: "line-clamp-2 text-xs text-muted-foreground",
3507
+ children: themeSelectionDescription(selection)
3508
+ })]
3509
+ })
3510
+ }, selectionKey);
3511
+ })
3512
+ }, section.colorMode))]
3448
3513
  }),
3449
3514
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
3450
3515
  className: "hidden border-t border-border/70 px-3 py-2 text-xs text-muted-foreground md:block",
@@ -3459,18 +3524,23 @@ function SettingsDialogBody({ stage, browseBodyProps, themeBodyProps }) {
3459
3524
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SettingsBrowseBody, { ...browseBodyProps });
3460
3525
  }
3461
3526
  function AppShellSettingsDialog({ open, onOpenChange, currentTheme, currentThemeColorMode, onThemeChange, onThemeColorModeChange, onThemePreviewChange, systemTheme, hideThinkingBlocks, onHideThinkingBlocksChange, hideToolBlocks, onHideToolBlocksChange, centerMessages, onCenterMessagesChange, autoScrollEnabled, onAutoScrollEnabledChange, sessionDoneSoundEnabled, onSessionDoneSoundEnabledChange, sessionDoneDesktopNotificationsEnabled, onSessionDoneDesktopNotificationsEnabledChange, desktopNotificationPermission, onLoginProviders, onLogoutProviders }) {
3462
- const [state, dispatch] = import_react.useReducer(settingsDialogReducer, currentTheme, createInitialSettingsDialogState);
3463
- const themePreviewInitialRef = import_react.useRef(currentTheme);
3527
+ const [state, dispatch] = import_react.useReducer(settingsDialogReducer, {
3528
+ currentTheme,
3529
+ currentThemeColorMode
3530
+ }, ({ currentTheme: initialTheme, currentThemeColorMode: initialColorMode }) => createInitialSettingsDialogState(initialTheme, initialColorMode));
3531
+ const themePreviewInitialRef = import_react.useRef(themeSelectionForCurrent(currentTheme, currentThemeColorMode));
3464
3532
  const isMobile = useIsMobile();
3465
3533
  import_react.useEffect(() => {
3466
3534
  if (open) return;
3467
- if (state.stage === "theme") onThemePreviewChange(themePreviewInitialRef.current);
3535
+ if (state.stage === "theme") onThemePreviewChange(themePreviewInitialRef.current.theme, themePreviewInitialRef.current.colorMode);
3468
3536
  dispatch({
3469
3537
  type: "reset",
3470
- currentTheme
3538
+ currentTheme,
3539
+ currentThemeColorMode
3471
3540
  });
3472
3541
  }, [
3473
3542
  currentTheme,
3543
+ currentThemeColorMode,
3474
3544
  onThemePreviewChange,
3475
3545
  open,
3476
3546
  state.stage
@@ -3480,21 +3550,24 @@ function AppShellSettingsDialog({ open, onOpenChange, currentTheme, currentTheme
3480
3550
  console.error(error);
3481
3551
  });
3482
3552
  };
3483
- const handleThemePreview = (theme) => {
3484
- if (!THEME_OPTIONS.includes(theme)) return;
3553
+ const handleThemePreview = (selection) => {
3554
+ if (!THEME_OPTIONS.includes(selection.theme)) return;
3555
+ if (!themeFamilySupportsColorMode(selection.theme, selection.colorMode)) return;
3485
3556
  dispatch({
3486
3557
  type: "preview-theme",
3487
- selectedTheme: theme
3558
+ selectedTheme: selection
3488
3559
  });
3489
- onThemePreviewChange(theme);
3560
+ onThemePreviewChange(selection.theme, selection.colorMode);
3490
3561
  };
3491
- const handleThemeSelect = (theme) => {
3562
+ const handleThemeSelect = (selection) => {
3492
3563
  dispatch({
3493
3564
  type: "preview-theme",
3494
- selectedTheme: theme
3565
+ selectedTheme: selection
3495
3566
  });
3496
- themePreviewInitialRef.current = theme;
3497
- onThemeChange(theme);
3567
+ themePreviewInitialRef.current = selection;
3568
+ onThemeColorModeChange(selection.colorMode);
3569
+ onThemeChange(selection.theme);
3570
+ onOpenChange(false);
3498
3571
  };
3499
3572
  const cancelThemePreview = () => {
3500
3573
  const initialTheme = themePreviewInitialRef.current;
@@ -3502,7 +3575,7 @@ function AppShellSettingsDialog({ open, onOpenChange, currentTheme, currentTheme
3502
3575
  type: "close-theme",
3503
3576
  selectedTheme: initialTheme
3504
3577
  });
3505
- onThemePreviewChange(initialTheme);
3578
+ onThemePreviewChange(initialTheme.theme, initialTheme.colorMode);
3506
3579
  };
3507
3580
  const settingGroups = getSettingsCommandGroups({
3508
3581
  currentTheme,
@@ -3524,13 +3597,13 @@ function AppShellSettingsDialog({ open, onOpenChange, currentTheme, currentTheme
3524
3597
  onLoginProviders,
3525
3598
  onLogoutProviders,
3526
3599
  onThemeCommand: () => {
3527
- themePreviewInitialRef.current = currentTheme;
3600
+ themePreviewInitialRef.current = themeSelectionForCurrent(currentTheme, currentThemeColorMode);
3528
3601
  dispatch({
3529
3602
  type: "open-theme",
3530
- currentTheme
3603
+ currentTheme,
3604
+ currentThemeColorMode
3531
3605
  });
3532
- },
3533
- onThemeColorModeCommand: () => onThemeColorModeChange(nextThemeColorMode(currentThemeColorMode))
3606
+ }
3534
3607
  });
3535
3608
  const settingsCommandBody = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SettingsDialogBody, {
3536
3609
  stage: state.stage,
@@ -3550,7 +3623,9 @@ function AppShellSettingsDialog({ open, onOpenChange, currentTheme, currentTheme
3550
3623
  },
3551
3624
  themeBodyProps: {
3552
3625
  currentTheme,
3626
+ currentThemeColorMode,
3553
3627
  selectedTheme: state.selectedTheme,
3628
+ systemTheme,
3554
3629
  themeQuery: state.themeQuery,
3555
3630
  onThemeQueryChange: (themeQuery) => dispatch({
3556
3631
  type: "set-theme-query",
@@ -6068,6 +6143,74 @@ function updateDirectoryIndexLoadingState(current, directories, loading) {
6068
6143
  }
6069
6144
  return changed ? next : current;
6070
6145
  }
6146
+ function upsertOptimisticSidebarSessionEntry(current, entry) {
6147
+ const directory = entry.cwd.trim();
6148
+ const optimisticId = entry.id.trim();
6149
+ if (!directory || !optimisticId) return current;
6150
+ const currentSnapshot = current[directory];
6151
+ const currentSessions = currentSnapshot?.sessions || [];
6152
+ const existingEntry = currentSessions.find((session) => session.id === optimisticId);
6153
+ const nextSessions = [{
6154
+ ...existingEntry,
6155
+ ...entry,
6156
+ id: optimisticId,
6157
+ cwd: directory,
6158
+ optimistic: true
6159
+ }, ...currentSessions.filter((session) => session.id !== optimisticId)];
6160
+ const totalCountBaseline = Math.max(currentSnapshot?.totalCount ?? 0, currentSessions.length);
6161
+ return {
6162
+ ...current,
6163
+ [directory]: {
6164
+ directory,
6165
+ totalCount: existingEntry ? totalCountBaseline : totalCountBaseline + 1,
6166
+ revision: `optimistic:${optimisticId}:${currentSnapshot?.revision || "initial"}:${entry.modified || ""}`,
6167
+ sessions: nextSessions
6168
+ }
6169
+ };
6170
+ }
6171
+ function removeOptimisticSidebarSessionEntry(current, optimisticId) {
6172
+ const targetId = optimisticId?.trim() || "";
6173
+ if (!targetId) return current;
6174
+ let changed = false;
6175
+ const next = { ...current };
6176
+ for (const [directory, snapshot] of Object.entries(current)) {
6177
+ const nextSessions = snapshot.sessions.filter((entry) => entry.id !== targetId);
6178
+ if (nextSessions.length === snapshot.sessions.length) continue;
6179
+ changed = true;
6180
+ next[directory] = {
6181
+ ...snapshot,
6182
+ totalCount: Math.max(0, snapshot.totalCount - 1),
6183
+ revision: `remove-optimistic:${targetId}:${snapshot.revision}`,
6184
+ sessions: nextSessions
6185
+ };
6186
+ }
6187
+ return changed ? next : current;
6188
+ }
6189
+ function isOptimisticSidebarSessionEntry(entry) {
6190
+ return Boolean(entry.optimistic || entry.id?.startsWith("optimistic:") && !entry.path);
6191
+ }
6192
+ function mergeDirectoryIndexDataPreservingOptimistic(current, next) {
6193
+ let merged = mergeDirectoryIndexData(current, next);
6194
+ for (const [directory, snapshot] of Object.entries(current)) {
6195
+ const optimisticSessions = snapshot.sessions.filter(isOptimisticSidebarSessionEntry);
6196
+ if (optimisticSessions.length === 0) continue;
6197
+ const targetSnapshot = merged[directory];
6198
+ if (!targetSnapshot) continue;
6199
+ const targetIds = new Set(targetSnapshot.sessions.flatMap((entry) => entry.id ? [entry.id] : []));
6200
+ const missingOptimisticSessions = optimisticSessions.filter((entry) => entry.id && !targetIds.has(entry.id));
6201
+ if (missingOptimisticSessions.length === 0) continue;
6202
+ merged = {
6203
+ ...merged,
6204
+ [directory]: {
6205
+ ...targetSnapshot,
6206
+ totalCount: targetSnapshot.totalCount + missingOptimisticSessions.length,
6207
+ revision: `preserve-optimistic:${targetSnapshot.revision}`,
6208
+ sessions: [...missingOptimisticSessions, ...targetSnapshot.sessions]
6209
+ }
6210
+ };
6211
+ }
6212
+ return merged;
6213
+ }
6071
6214
  function sameSessionEntryRecord(left, right) {
6072
6215
  const leftKeys = Object.keys(left);
6073
6216
  const rightKeys = Object.keys(right);
@@ -6239,11 +6382,11 @@ function computeAppShellSidebarDerived(state) {
6239
6382
  const sidebarSessions = Array.from(sidebarSessionEntriesByKey.values());
6240
6383
  const pinnedSidebarSessions = state.pinnedSidebarSessionKeys.flatMap((key) => {
6241
6384
  const entry = sidebarSessionEntriesByKey.get(key);
6242
- return entry?.path || entry?.id ? [entry] : [];
6385
+ return entry?.path || entry?.id && !isOptimisticSidebarSessionEntry(entry) ? [entry] : [];
6243
6386
  });
6244
6387
  const selectedSidebarSessions = state.selectedSidebarSessionKeys.flatMap((key) => {
6245
6388
  const entry = sidebarSessionEntriesByKey.get(key);
6246
- return entry?.path || entry?.id ? [entry] : [];
6389
+ return entry?.path || entry?.id && !isOptimisticSidebarSessionEntry(entry) ? [entry] : [];
6247
6390
  });
6248
6391
  const workspaceVersion = [
6249
6392
  baseSidebarDirectories.join("\n"),
@@ -7383,54 +7526,98 @@ function FooterKbd({ children }) {
7383
7526
  }
7384
7527
  function RenameSessionDialog({ open, onOpenChange, renameValue, onRenameValueChange, onRenameSession }) {
7385
7528
  const isMobile = useIsMobile();
7386
- const renameInput = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Input$1, {
7387
- value: renameValue,
7388
- onChange: (event) => onRenameValueChange(event.target.value),
7389
- onKeyDown: (event) => {
7390
- if (event.key !== "Enter" || event.nativeEvent.isComposing) return;
7391
- event.preventDefault();
7392
- onRenameSession();
7393
- },
7394
- placeholder: "Session name"
7529
+ const renameInputRef = import_react.useRef(null);
7530
+ import_react.useEffect(() => {
7531
+ if (!open) return;
7532
+ const frame = window.requestAnimationFrame(() => {
7533
+ renameInputRef.current?.focus();
7534
+ renameInputRef.current?.select();
7535
+ });
7536
+ return () => {
7537
+ window.cancelAnimationFrame(frame);
7538
+ };
7539
+ }, [open]);
7540
+ const body = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
7541
+ className: "flex min-h-0 flex-1 flex-col",
7542
+ children: [
7543
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
7544
+ className: "border-b border-border/70 px-3 py-2",
7545
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7546
+ className: "truncate text-sm font-medium",
7547
+ children: "Rename session"
7548
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7549
+ className: "truncate text-xs text-muted-foreground",
7550
+ children: "Update the display name shown in the sidebar."
7551
+ })]
7552
+ }),
7553
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7554
+ className: "flex min-h-0 flex-1 items-center p-3",
7555
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Input$1, {
7556
+ ref: renameInputRef,
7557
+ value: renameValue,
7558
+ onChange: (event) => onRenameValueChange(event.target.value),
7559
+ onKeyDown: (event) => {
7560
+ if (event.key === "Escape") {
7561
+ event.preventDefault();
7562
+ event.stopPropagation();
7563
+ onOpenChange(false);
7564
+ return;
7565
+ }
7566
+ if (event.key !== "Enter" || event.nativeEvent.isComposing) return;
7567
+ event.preventDefault();
7568
+ event.stopPropagation();
7569
+ onRenameSession();
7570
+ },
7571
+ placeholder: "Session name",
7572
+ className: "min-w-0 flex-1"
7573
+ })
7574
+ }),
7575
+ isMobile ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
7576
+ className: "hidden flex-wrap items-center gap-x-3 gap-y-1 border-t border-border/70 px-3 py-2 text-xs text-muted-foreground md:flex",
7577
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
7578
+ className: "inline-flex items-center gap-1",
7579
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FooterKbd, { children: "Enter" }), " Save"]
7580
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
7581
+ className: "inline-flex items-center gap-1",
7582
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FooterKbd, { children: "Esc" }), " Cancel"]
7583
+ })]
7584
+ })
7585
+ ]
7395
7586
  });
7396
7587
  if (isMobile) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Drawer$1, {
7397
7588
  open,
7398
7589
  onOpenChange,
7399
7590
  autoFocus: false,
7400
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DrawerContent, { children: [
7401
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DrawerHeader, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DrawerTitle, { children: "Rename session" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DrawerDescription, { children: "Update the display name shown in the sidebar." })] }),
7402
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7403
- className: "px-4 pb-2",
7404
- children: renameInput
7405
- }),
7406
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DrawerFooter, {
7407
- className: "border-t border-border/70",
7408
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
7409
- variant: "outline",
7410
- onClick: () => onOpenChange(false),
7411
- children: "Cancel"
7412
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
7413
- onClick: onRenameSession,
7414
- children: "Save"
7415
- })]
7416
- })
7417
- ] })
7591
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DrawerContent, {
7592
+ className: "max-h-[90svh] overflow-hidden",
7593
+ children: [
7594
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DrawerHeader, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DrawerTitle, { children: "Rename session" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DrawerDescription, { children: "Update the display name shown in the sidebar." })] }),
7595
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7596
+ className: "flex min-h-0 flex-1 flex-col overflow-hidden px-4 pb-4",
7597
+ children: body
7598
+ }),
7599
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DrawerFooter, {
7600
+ className: "border-t border-border/70",
7601
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
7602
+ variant: "outline",
7603
+ onClick: () => onOpenChange(false),
7604
+ children: "Cancel"
7605
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
7606
+ onClick: onRenameSession,
7607
+ children: "Save"
7608
+ })]
7609
+ })
7610
+ ]
7611
+ })
7418
7612
  });
7419
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dialog$1, {
7613
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandDialog, {
7420
7614
  open,
7421
7615
  onOpenChange,
7422
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogContent, { children: [
7423
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogHeader, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogTitle, { children: "Rename session" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogDescription, { children: "Update the display name shown in the sidebar." })] }),
7424
- renameInput,
7425
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogFooter, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
7426
- variant: "outline",
7427
- onClick: () => onOpenChange(false),
7428
- children: "Cancel"
7429
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
7430
- onClick: onRenameSession,
7431
- children: "Save"
7432
- })] })
7433
- ] })
7616
+ title: "Rename session",
7617
+ description: "Update the display name shown in the sidebar.",
7618
+ className: "sm:max-w-md",
7619
+ initialFocus: true,
7620
+ children: body
7434
7621
  });
7435
7622
  }
7436
7623
  function RenameSessionDialogController({ ref, openStateRef, onRenameSession }) {
@@ -7480,35 +7667,138 @@ function RenameSessionDialogController({ ref, openStateRef, onRenameSession }) {
7480
7667
  }
7481
7668
  });
7482
7669
  }
7483
- function DeleteSessionsDialog({ open, onOpenChange, title, description, onDeleteSession }) {
7484
- if (useIsMobile()) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Drawer$1, {
7670
+ function DeleteSessionsDialog({ open, onOpenChange, title, description, targets, onDeleteSession }) {
7671
+ const isMobile = useIsMobile();
7672
+ const deletePanelRef = import_react.useRef(null);
7673
+ import_react.useEffect(() => {
7674
+ if (!open || isMobile) return;
7675
+ const frame = window.requestAnimationFrame(() => {
7676
+ deletePanelRef.current?.focus();
7677
+ });
7678
+ return () => {
7679
+ window.cancelAnimationFrame(frame);
7680
+ };
7681
+ }, [isMobile, open]);
7682
+ import_react.useEffect(() => {
7683
+ if (!open || isMobile) return;
7684
+ const handleDeleteKeyDown = (event) => {
7685
+ if (event.key === "Escape") {
7686
+ event.preventDefault();
7687
+ event.stopPropagation();
7688
+ onOpenChange(false);
7689
+ return;
7690
+ }
7691
+ if (event.key !== "Enter" || event.isComposing) return;
7692
+ event.preventDefault();
7693
+ event.stopPropagation();
7694
+ onDeleteSession();
7695
+ };
7696
+ window.addEventListener("keydown", handleDeleteKeyDown, true);
7697
+ return () => {
7698
+ window.removeEventListener("keydown", handleDeleteKeyDown, true);
7699
+ };
7700
+ }, [
7701
+ isMobile,
7702
+ onDeleteSession,
7703
+ onOpenChange,
7704
+ open
7705
+ ]);
7706
+ const previewTargets = targets.slice(0, 8);
7707
+ const remainingTargetCount = Math.max(0, targets.length - previewTargets.length);
7708
+ const body = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
7709
+ ref: deletePanelRef,
7710
+ role: "presentation",
7711
+ tabIndex: -1,
7712
+ className: "flex min-h-0 flex-1 flex-col outline-none",
7713
+ onKeyDown: (event) => {
7714
+ if (event.key === "Escape") {
7715
+ event.preventDefault();
7716
+ event.stopPropagation();
7717
+ onOpenChange(false);
7718
+ return;
7719
+ }
7720
+ if (event.key !== "Enter" || event.nativeEvent.isComposing) return;
7721
+ event.preventDefault();
7722
+ event.stopPropagation();
7723
+ onDeleteSession();
7724
+ },
7725
+ children: [
7726
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
7727
+ className: "border-b border-border/70 px-3 py-2",
7728
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7729
+ className: "truncate text-sm font-medium",
7730
+ children: title
7731
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7732
+ className: "truncate text-xs text-muted-foreground",
7733
+ children: description
7734
+ })]
7735
+ }),
7736
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
7737
+ className: "flex min-h-0 flex-1 flex-col gap-3 p-3",
7738
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
7739
+ className: "text-sm text-muted-foreground",
7740
+ children: "This cannot be undone."
7741
+ }), targets.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
7742
+ className: "max-h-48 space-y-1 overflow-y-auto rounded-lg border bg-muted/30 p-2 text-sm",
7743
+ children: [previewTargets.map((target) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7744
+ className: "truncate",
7745
+ children: target.title || "New session"
7746
+ }, target.path || target.id)), remainingTargetCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
7747
+ className: "text-muted-foreground",
7748
+ children: [
7749
+ "…and ",
7750
+ remainingTargetCount,
7751
+ " more"
7752
+ ]
7753
+ }) : null]
7754
+ }) : null]
7755
+ }),
7756
+ isMobile ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
7757
+ className: "hidden flex-wrap items-center gap-x-3 gap-y-1 border-t border-border/70 px-3 py-2 text-xs text-muted-foreground md:flex",
7758
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
7759
+ className: "inline-flex items-center gap-1",
7760
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FooterKbd, { children: "Enter" }), " Delete"]
7761
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
7762
+ className: "inline-flex items-center gap-1",
7763
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FooterKbd, { children: "Esc" }), " Cancel"]
7764
+ })]
7765
+ })
7766
+ ]
7767
+ });
7768
+ if (isMobile) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Drawer$1, {
7485
7769
  open,
7486
7770
  onOpenChange,
7487
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DrawerContent, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DrawerHeader, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DrawerTitle, { children: title }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DrawerDescription, { children: description })] }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DrawerFooter, {
7488
- className: "border-t border-border/70",
7489
- children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
7490
- variant: "outline",
7491
- onClick: () => onOpenChange(false),
7492
- children: "Cancel"
7493
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
7494
- variant: "destructive",
7495
- onClick: onDeleteSession,
7496
- children: "Delete"
7497
- })]
7498
- })] })
7771
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DrawerContent, {
7772
+ className: "max-h-[90svh] overflow-hidden",
7773
+ children: [
7774
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DrawerHeader, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DrawerTitle, { children: title }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DrawerDescription, { children: description })] }),
7775
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
7776
+ className: "flex min-h-0 flex-1 flex-col overflow-hidden px-4 pb-4",
7777
+ children: body
7778
+ }),
7779
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DrawerFooter, {
7780
+ className: "border-t border-border/70",
7781
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
7782
+ variant: "outline",
7783
+ onClick: () => onOpenChange(false),
7784
+ children: "Cancel"
7785
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
7786
+ variant: "destructive",
7787
+ onClick: onDeleteSession,
7788
+ children: "Delete"
7789
+ })]
7790
+ })
7791
+ ]
7792
+ })
7499
7793
  });
7500
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dialog$1, {
7794
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandDialog, {
7501
7795
  open,
7502
7796
  onOpenChange,
7503
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogContent, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogHeader, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogTitle, { children: title }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogDescription, { children: description })] }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogFooter, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
7504
- variant: "outline",
7505
- onClick: () => onOpenChange(false),
7506
- children: "Cancel"
7507
- }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
7508
- variant: "destructive",
7509
- onClick: onDeleteSession,
7510
- children: "Delete"
7511
- })] })] })
7797
+ title,
7798
+ description,
7799
+ className: "sm:max-w-md",
7800
+ initialFocus: true,
7801
+ children: body
7512
7802
  });
7513
7803
  }
7514
7804
  function DeleteOldDirectorySessionsDialog({ open, onOpenChange, directory, daysValue, preview, previewLoading, deleteLoading, onDaysValueChange, onPreview, onDelete }) {
@@ -7750,6 +8040,7 @@ function DeleteSessionsDialogController({ ref, openStateRef, onDeleteSession })
7750
8040
  onOpenChange: setOpenState,
7751
8041
  title: targets.length === 1 ? "Delete session" : "Delete sessions",
7752
8042
  description: targets.length === 1 ? `Delete "${targets[0]?.title || "New session"}" from disk?` : `Delete ${targets.length} selected sessions from disk?`,
8043
+ targets,
7753
8044
  onDeleteSession: () => {
7754
8045
  submitDelete();
7755
8046
  }
@@ -9671,9 +9962,12 @@ function readQuotedAttribute(tag, name) {
9671
9962
  }
9672
9963
  function normalizeHighlightClassName(value) {
9673
9964
  if (!value) return void 0;
9674
- const classNames = value.split(/\s+/).filter((className) => /^sh__[A-Za-z0-9_-]+$/.test(className));
9965
+ const classNames = value.split(/\s+/).filter((className) => className === "line");
9675
9966
  return classNames.length > 0 ? classNames.join(" ") : void 0;
9676
9967
  }
9968
+ function isSafeCssVariableColor(value) {
9969
+ return /^var\(--[A-Za-z0-9-]+(?:,\s*var\(--[A-Za-z0-9-]+\))?\)$/.test(value);
9970
+ }
9677
9971
  function normalizeHighlightStyle(value) {
9678
9972
  if (!value) return void 0;
9679
9973
  for (const declaration of value.split(";")) {
@@ -9681,7 +9975,7 @@ function normalizeHighlightStyle(value) {
9681
9975
  const property = rawProperty?.trim().toLowerCase();
9682
9976
  const color = rawValueParts.join(":").trim();
9683
9977
  if (property !== "color") continue;
9684
- if (!/^var\(--sh-[A-Za-z0-9-]+\)$/.test(color)) continue;
9978
+ if (!isSafeCssVariableColor(color)) continue;
9685
9979
  return { color };
9686
9980
  }
9687
9981
  }
@@ -9727,7 +10021,7 @@ function renderHighlightedChild(child) {
9727
10021
  }
9728
10022
  function HighlightedCode({ className, html, language }) {
9729
10023
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", {
9730
- className: cn(language && `language-${language}`, className),
10024
+ className: cn("shiki", language && `language-${language}`, className),
9731
10025
  children: parseHighlightedHtml(html).map(renderHighlightedChild)
9732
10026
  });
9733
10027
  }
@@ -10031,6 +10325,78 @@ var MarkdownBlock = import_react.memo(function MarkdownBlock({ streaming = false
10031
10325
  })
10032
10326
  });
10033
10327
  });
10328
+ var PICO_DIFF_THEME_PAIR = {
10329
+ light: PICO_DIFF_SHIKI_THEMES.light,
10330
+ dark: PICO_DIFF_SHIKI_THEMES.dark
10331
+ };
10332
+ var PICO_DIFF_COLOR_CSS = `
10333
+ :host {
10334
+ --diffs-addition-color-override: var(--success);
10335
+ --diffs-deletion-color-override: var(--danger);
10336
+ --diffs-modified-color-override: var(--primary);
10337
+ --diffs-bg-addition-emphasis-override: color-mix(in lab, var(--diffs-bg) 42%, var(--diffs-addition-base));
10338
+ --diffs-bg-deletion-emphasis-override: color-mix(in lab, var(--diffs-bg) 42%, var(--diffs-deletion-base));
10339
+ }
10340
+
10341
+ @media (max-width: 640px) {
10342
+ [data-annotation-content] {
10343
+ inline-size: min(100%, calc(100vw - var(--diffs-column-number-width, 0px) - 1rem));
10344
+ }
10345
+ }
10346
+
10347
+ [data-line-type="change-addition"]:is(
10348
+ [data-gutter-buffer],
10349
+ [data-column-number],
10350
+ [data-line],
10351
+ [data-no-newline]
10352
+ ) {
10353
+ --mix-light: 84%;
10354
+ --mix-dark: 76%;
10355
+ }
10356
+
10357
+ [data-line-type="change-deletion"]:is(
10358
+ [data-gutter-buffer],
10359
+ [data-column-number],
10360
+ [data-line],
10361
+ [data-no-newline]
10362
+ ) {
10363
+ --mix-light: 84%;
10364
+ --mix-dark: 76%;
10365
+ }
10366
+ `;
10367
+ function registerPicoDiffTheme(name, type) {
10368
+ if (RegisteredCustomThemes.has(name)) return;
10369
+ const theme = createCssVariablesTheme({
10370
+ name,
10371
+ variablePrefix: "--diffs-",
10372
+ variableDefaults: { ...PICO_SHIKI_VARIABLE_DEFAULTS },
10373
+ fontStyle: false
10374
+ });
10375
+ registerCustomTheme(name, () => Promise.resolve({
10376
+ ...theme,
10377
+ type
10378
+ }));
10379
+ }
10380
+ function ensurePicoDiffThemes() {
10381
+ registerPicoDiffTheme(PICO_DIFF_SHIKI_THEMES.light, "light");
10382
+ registerPicoDiffTheme(PICO_DIFF_SHIKI_THEMES.dark, "dark");
10383
+ }
10384
+ function resolvePicoDiffThemeType({ resolvedTheme, systemTheme, theme }) {
10385
+ return appliedThemeClassColorMode(theme) ?? appliedThemeClassColorMode(resolvedTheme) ?? (resolvedTheme === "dark" || systemTheme === "dark" ? "dark" : "light");
10386
+ }
10387
+ ensurePicoDiffThemes();
10388
+ function usePicoDiffThemeOptions() {
10389
+ const { resolvedTheme, systemTheme, theme } = z();
10390
+ return {
10391
+ theme: PICO_DIFF_THEME_PAIR,
10392
+ themeType: resolvePicoDiffThemeType({
10393
+ resolvedTheme,
10394
+ systemTheme,
10395
+ theme
10396
+ }),
10397
+ unsafeCSS: PICO_DIFF_COLOR_CSS
10398
+ };
10399
+ }
10034
10400
  function Collapsible$1({ ...props }) {
10035
10401
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CollapsibleRoot, {
10036
10402
  "data-slot": "collapsible",
@@ -11051,6 +11417,7 @@ function EditDiffStatCountsView({ stats }) {
11051
11417
  });
11052
11418
  }
11053
11419
  function EditDiffBlock({ isBorderless = false, patch }) {
11420
+ const themeOptions = usePicoDiffThemeOptions();
11054
11421
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
11055
11422
  className: cn("overflow-hidden text-xs", !isBorderless && "rounded-md border bg-background"),
11056
11423
  style: { "--diffs-font-family": "var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace)" },
@@ -11058,6 +11425,7 @@ function EditDiffBlock({ isBorderless = false, patch }) {
11058
11425
  patch,
11059
11426
  disableWorkerPool: true,
11060
11427
  options: {
11428
+ ...themeOptions,
11061
11429
  diffStyle: "unified",
11062
11430
  disableFileHeader: true,
11063
11431
  lineDiffType: "word-alt",
@@ -11228,11 +11596,11 @@ function ToolBlockCardBody({ block }) {
11228
11596
  const isSelfContainedWriteTool = block.name === "write" && !block.isError && getWriteToolPayload(block)?.content !== void 0;
11229
11597
  const hasSelfContainedToolOutput = isSuccessfulEditTool || isSelfContainedWriteTool;
11230
11598
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
11231
- className: "border-t pt-3",
11599
+ className: cn("border-t", !isSuccessfulEditTool && "pt-3"),
11232
11600
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
11233
11601
  ref: block.name === "bash" ? autoScroll.ref : void 0,
11234
11602
  onScroll: block.name === "bash" ? autoScroll.onScroll : void 0,
11235
- className: cn(isSelfContainedWriteTool ? "overflow-hidden rounded-lg" : "max-h-96 overflow-auto", hasSelfContainedToolOutput ? "rounded-lg" : "rounded-lg border bg-background/80 p-3"),
11603
+ className: cn(isSelfContainedWriteTool ? "overflow-hidden rounded-lg" : "max-h-96 overflow-auto", isSuccessfulEditTool ? "rounded-t-none rounded-b-xl" : hasSelfContainedToolOutput ? "rounded-lg" : "rounded-lg border bg-background/80 p-3"),
11236
11604
  children: block.name === "bash" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("pre", {
11237
11605
  className: cn("overflow-x-auto font-mono text-xs leading-5 break-words whitespace-pre-wrap", block.isError && "text-destructive"),
11238
11606
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnsiText, { text: shellBodyText })
@@ -11286,6 +11654,7 @@ var ToolBlockCard = import_react.memo(function ToolBlockCard({ blockKey, store }
11286
11654
  function ToolBlockCardContent({ blockKey, header, store }) {
11287
11655
  const [isOpen, setIsOpen] = useRememberedToolCollapsibleOpen(header.openStateKey);
11288
11656
  const bodyBlock = useAssistantToolBlockBody(store, blockKey, isOpen);
11657
+ const isSuccessfulEditTool = header.name === "edit" && !header.running && !header.isError;
11289
11658
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Collapsible$1, {
11290
11659
  open: isOpen,
11291
11660
  onOpenChange: setIsOpen,
@@ -11311,7 +11680,7 @@ function ToolBlockCardContent({ blockKey, header, store }) {
11311
11680
  }), isOpen && bodyBlock ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CollapsibleContent, {
11312
11681
  className: "overflow-hidden text-sm data-open:animate-accordion-down data-closed:animate-accordion-up",
11313
11682
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
11314
- className: "h-(--collapsible-panel-height) px-3 pt-0 pb-3 data-ending-style:h-0 data-starting-style:h-0",
11683
+ className: cn("h-(--collapsible-panel-height) data-ending-style:h-0 data-starting-style:h-0", !isSuccessfulEditTool && "px-3 pt-0 pb-3"),
11315
11684
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToolBlockCardBody, { block: bodyBlock })
11316
11685
  })
11317
11686
  }) : null]
@@ -13943,21 +14312,29 @@ function ConversationScrollRevisionObserver({ conversationItemsStore, disabled,
13943
14312
  }, [conversationRevision, disabled]);
13944
14313
  return null;
13945
14314
  }
13946
- function ConversationPreviousMessageButton({ onClick, scrollStateStore }) {
14315
+ function ConversationPreviousMessageButton({ centerMessages, onClick, scrollStateStore }) {
13947
14316
  const isDisabled = useMessageScrollValue(scrollStateStore, (snapshot) => !snapshot.hasPreviousMessageJumpTarget);
13948
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
14317
+ const button = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
13949
14318
  title: "Jump to previous message",
13950
14319
  kbd: formatShortcutLabel("Control+ArrowLeft"),
13951
14320
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
13952
14321
  variant: "secondary",
13953
14322
  size: "icon-lg",
13954
14323
  disabled: isDisabled,
13955
- className: "absolute right-4 bottom-4 z-10 rounded-full border-0 shadow-[0_10px_24px_rgba(0,0,0,0.28)] disabled:pointer-events-none disabled:opacity-0 md:right-[18px] md:bottom-[18px]",
14324
+ className: cn("rounded-full border-0 shadow-[0_10px_24px_rgba(0,0,0,0.28)] disabled:pointer-events-none disabled:opacity-0", centerMessages ? "pointer-events-auto" : "absolute right-4 bottom-4 z-10 md:right-[18px] md:bottom-[18px]"),
13956
14325
  "aria-label": "Jump to previous message",
13957
14326
  onClick,
13958
14327
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowUpToLine, { className: "size-4" })
13959
14328
  })
13960
14329
  });
14330
+ if (!centerMessages) return button;
14331
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
14332
+ className: "pointer-events-none absolute inset-x-4 bottom-4 z-10 md:bottom-[18px]",
14333
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
14334
+ className: "mx-auto flex w-full max-w-[80ch] justify-end",
14335
+ children: button
14336
+ })
14337
+ });
13961
14338
  }
13962
14339
  var ConversationContentChangeContext = import_react.createContext(null);
13963
14340
  function useAppShellConversationSessionState(store) {
@@ -13969,7 +14346,7 @@ function useAppShellConversationSessionState(store) {
13969
14346
  streaming: sessionState.streaming
13970
14347
  }), { compare: shallowRecordEqual });
13971
14348
  }
13972
- function AppShellConversationFrame({ autoScrollEnabled, children, conversationItemsStore, isSessionViewLoading, ref, sessionState }) {
14349
+ function AppShellConversationFrame({ autoScrollEnabled, children, centerMessages, conversationItemsStore, isSessionViewLoading, ref, sessionState }) {
13973
14350
  const { bottomRef, jumpToNextMessage, jumpToPreviousMessage, messagesContentRef, messagesScrollAreaRef, scrollConversationToBottom, scrollConversationToTop, scrollStateStore, syncAfterConversationChange } = useAppShellMessageScroll({
13974
14351
  autoScrollEnabled,
13975
14352
  isSessionViewLoading,
@@ -14017,6 +14394,7 @@ function AppShellConversationFrame({ autoScrollEnabled, children, conversationIt
14017
14394
  onClick: scrollConversationToBottom,
14018
14395
  scrollStateStore
14019
14396
  }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConversationPreviousMessageButton, {
14397
+ centerMessages,
14020
14398
  onClick: jumpToPreviousMessage,
14021
14399
  scrollStateStore
14022
14400
  })] }) : null]
@@ -14232,6 +14610,7 @@ var AppShellSessionConversation = import_react.memo(function AppShellSessionConv
14232
14610
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(AppShellConversationFrame, {
14233
14611
  ref: conversationFrameRef,
14234
14612
  autoScrollEnabled,
14613
+ centerMessages,
14235
14614
  conversationItemsStore,
14236
14615
  isSessionViewLoading,
14237
14616
  sessionState,
@@ -17860,7 +18239,7 @@ function ReviewDiffPendingLineComment({ comment }) {
17860
18239
  comment.onSubmit(normalizedText);
17861
18240
  };
17862
18241
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", {
17863
- className: "m-2 max-w-[min(38rem,calc(100%-1rem))] rounded-lg border border-border/70 bg-background p-2 shadow-sm",
18242
+ className: "m-2 w-[min(38rem,calc(100vw_-_5rem))] max-w-[calc(100%_-_1rem)] rounded-lg border border-border/70 bg-background p-2 shadow-sm",
17864
18243
  onPointerDown: (event) => event.stopPropagation(),
17865
18244
  onSubmit: (event) => {
17866
18245
  event.preventDefault();
@@ -17908,7 +18287,7 @@ function ReviewDiffPendingLineComment({ comment }) {
17908
18287
  }
17909
18288
  }),
17910
18289
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
17911
- className: "mt-2 flex justify-end gap-2",
18290
+ className: "mt-2 flex flex-wrap justify-end gap-2",
17912
18291
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
17913
18292
  type: "button",
17914
18293
  variant: "ghost",
@@ -17928,7 +18307,7 @@ function ReviewDiffLineAnnotation({ annotation }) {
17928
18307
  if (!comment) return null;
17929
18308
  if (comment.kind === "pending") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ReviewDiffPendingLineComment, { comment });
17930
18309
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
17931
- className: "my-1 ml-2 inline-flex max-w-[min(32rem,90%)] items-center gap-1 rounded-full border border-amber-500/20 bg-amber-500/10 px-2 py-1 text-[11px] text-amber-800 dark:text-amber-200",
18310
+ className: "my-1 ml-2 inline-flex max-w-[min(32rem,calc(100vw_-_5rem),90%)] items-center gap-1 rounded-full border border-amber-500/20 bg-amber-500/10 px-2 py-1 text-[11px] text-amber-800 dark:text-amber-200",
17932
18311
  children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
17933
18312
  className: "shrink-0",
17934
18313
  children: "💬"
@@ -18419,6 +18798,7 @@ function ReviewFileAccordionItem({ viewerContextId, cwd, active, diffLineComment
18419
18798
  enableGutterUtility: true,
18420
18799
  onGutterUtilityClick: startLineComment
18421
18800
  } : {};
18801
+ const themeOptions = usePicoDiffThemeOptions();
18422
18802
  const [indexStatus, worktreeStatus] = gitFileStatusCharacters(file.status);
18423
18803
  const canStage = worktreeStatus !== " " || indexStatus === "?";
18424
18804
  const invalidateChangedFileQueries = async () => {
@@ -18596,6 +18976,7 @@ function ReviewFileAccordionItem({ viewerContextId, cwd, active, diffLineComment
18596
18976
  lineAnnotations,
18597
18977
  renderAnnotation: (annotation) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ReviewDiffLineAnnotation, { annotation }),
18598
18978
  options: {
18979
+ ...themeOptions,
18599
18980
  diffStyle,
18600
18981
  disableFileHeader: true,
18601
18982
  ...commentableOptions,
@@ -18626,6 +19007,7 @@ function ReviewFileAccordionItem({ viewerContextId, cwd, active, diffLineComment
18626
19007
  lineAnnotations,
18627
19008
  renderAnnotation: (annotation) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ReviewDiffLineAnnotation, { annotation }),
18628
19009
  options: {
19010
+ ...themeOptions,
18629
19011
  diffStyle,
18630
19012
  disableFileHeader: true,
18631
19013
  ...commentableOptions,
@@ -18781,7 +19163,7 @@ function assignClassName(element, className) {
18781
19163
  }
18782
19164
  function renderPendingCommitDiffLineComment(pendingComment) {
18783
19165
  const form = document.createElement("form");
18784
- assignClassName(form, "m-2 max-w-[min(38rem,calc(100%-1rem))] rounded-lg border border-border/70 bg-background p-2 shadow-sm");
19166
+ assignClassName(form, "m-2 w-[min(38rem,calc(100vw_-_5rem))] max-w-[calc(100%_-_1rem)] rounded-lg border border-border/70 bg-background p-2 shadow-sm");
18785
19167
  const header = document.createElement("div");
18786
19168
  assignClassName(header, "mb-2 flex min-w-0 items-center justify-between gap-2 text-xs text-muted-foreground");
18787
19169
  const label = document.createElement("span");
@@ -18809,7 +19191,7 @@ function renderPendingCommitDiffLineComment(pendingComment) {
18809
19191
  }
18810
19192
  });
18811
19193
  const footer = document.createElement("div");
18812
- assignClassName(footer, "mt-2 flex justify-end gap-2");
19194
+ assignClassName(footer, "mt-2 flex flex-wrap justify-end gap-2");
18813
19195
  const secondaryCancelButton = document.createElement("button");
18814
19196
  secondaryCancelButton.type = "button";
18815
19197
  secondaryCancelButton.textContent = "Cancel";
@@ -18844,7 +19226,7 @@ function renderCommitDiffLineAnnotation(annotation) {
18844
19226
  if (comment.kind === "pending") return renderPendingCommitDiffLineComment(comment);
18845
19227
  const savedComment = comment;
18846
19228
  const wrapper = document.createElement("div");
18847
- assignClassName(wrapper, "my-1 ml-2 inline-flex max-w-[min(32rem,90%)] items-center gap-1 rounded-full border border-amber-500/20 bg-amber-500/10 px-2 py-1 text-[11px] text-amber-800 dark:text-amber-200");
19229
+ assignClassName(wrapper, "my-1 ml-2 inline-flex max-w-[min(32rem,calc(100vw_-_5rem),90%)] items-center gap-1 rounded-full border border-amber-500/20 bg-amber-500/10 px-2 py-1 text-[11px] text-amber-800 dark:text-amber-200");
18848
19230
  const icon = document.createElement("span");
18849
19231
  icon.textContent = "💬";
18850
19232
  assignClassName(icon, "shrink-0");
@@ -18862,6 +19244,7 @@ function CommitDiffFileRenderer({ comments, diffStyle, disableFileHeader = false
18862
19244
  pendingComment
18863
19245
  });
18864
19246
  const options = {
19247
+ ...usePicoDiffThemeOptions(),
18865
19248
  diffStyle,
18866
19249
  disableFileHeader,
18867
19250
  enableGutterUtility: true,
@@ -20500,10 +20883,11 @@ function SidebarSessionItem({ entryKey, directorySessionsStore, activeSessionSto
20500
20883
  const pinnedDirectoryLabel = isPinned ? formatDisplayPath$1(entry.cwd?.trim() || entry.path?.trim() || "") : "";
20501
20884
  const exactTimestamp = hasTimestamp && timestamp ? new Date(timestamp).toLocaleString() : void 0;
20502
20885
  const showUnread = Boolean(entry.unread) && !entry.streaming;
20886
+ const isOptimisticSession = Boolean(entry.optimistic || entry.id?.startsWith("optimistic:") && !entry.path);
20503
20887
  const availableMoveTargetDirectories = moveTargetDirectories.filter((directory) => directory && directory !== entry.cwd);
20504
20888
  const canMoveAnyDirectory = Boolean(entry.path && onMoveSessionAnyDirectory);
20505
20889
  const hasMoveActions = Boolean(entry.path && onMoveSession) && availableMoveTargetDirectories.length > 0 || canMoveAnyDirectory;
20506
- const hasSessionActions = Boolean(onTogglePinnedSession || entry.path && (onRenameSession || onDeleteSession || onSetSessionUnread) || hasMoveActions) && !overlay;
20890
+ const hasSessionActions = Boolean(!isOptimisticSession && onTogglePinnedSession || entry.path && (onRenameSession || onDeleteSession || onSetSessionUnread) || hasMoveActions) && !overlay;
20507
20891
  const sessionButton = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(SidebarMenuButton, {
20508
20892
  type: "button",
20509
20893
  "data-sidebar-session-item": true,
@@ -20576,7 +20960,7 @@ function SidebarSessionItem({ entryKey, directorySessionsStore, activeSessionSto
20576
20960
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SidebarMenuItem, { children: hasSessionActions ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ContextMenu$1, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenuTrigger, { render: sessionRow }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ContextMenuContent, {
20577
20961
  className: "w-44",
20578
20962
  children: [
20579
- onTogglePinnedSession ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenuItem, {
20963
+ onTogglePinnedSession && !isOptimisticSession ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenuItem, {
20580
20964
  onClick: () => onTogglePinnedSession(entry),
20581
20965
  children: isPinned ? "Unpin" : "Pin to sidebar"
20582
20966
  }) : null,
@@ -20612,7 +20996,7 @@ function SidebarSessionItem({ entryKey, directorySessionsStore, activeSessionSto
20612
20996
  function sameDirectorySessionEntry(left, right) {
20613
20997
  if (left === right) return true;
20614
20998
  if (!left || !right) return false;
20615
- return left.path === right.path && left.id === right.id && left.cwd === right.cwd && left.name === right.name && left.title === right.title && left.modified === right.modified && left.lastUserMessageAt === right.lastUserMessageAt && left.lastMessageAt === right.lastMessageAt && left.lastMessagePreview === right.lastMessagePreview && left.messageCount === right.messageCount && JSON.stringify(left.contextUsage ?? null) === JSON.stringify(right.contextUsage ?? null) && Boolean(left.streaming) === Boolean(right.streaming) && Boolean(left.unread) === Boolean(right.unread);
20999
+ return left.path === right.path && left.id === right.id && left.cwd === right.cwd && left.name === right.name && left.title === right.title && left.modified === right.modified && left.lastUserMessageAt === right.lastUserMessageAt && left.lastMessageAt === right.lastMessageAt && left.lastMessagePreview === right.lastMessagePreview && left.messageCount === right.messageCount && JSON.stringify(left.contextUsage ?? null) === JSON.stringify(right.contextUsage ?? null) && Boolean(left.streaming) === Boolean(right.streaming) && Boolean(left.unread) === Boolean(right.unread) && Boolean(left.optimistic) === Boolean(right.optimistic);
20616
21000
  }
20617
21001
  function buildDirectorySessionEntryMap(sessionsByDirectory) {
20618
21002
  const entriesByKey = /* @__PURE__ */ new Map();
@@ -20670,7 +21054,7 @@ function useDirectorySessions(store, directory) {
20670
21054
  function useDirectorySessionEntry(store, entryKey) {
20671
21055
  return useSelector(store, (state) => state.entriesByKey.get(entryKey), { compare: sameDirectorySessionEntry });
20672
21056
  }
20673
- var DirectorySessionGroup = import_react.memo(function DirectorySessionGroup({ directory, directorySessionsStore, collapsedDirectoryStore, searchActive, directoryOrderingEnabled, moveTargetDirectories, activeSessionStore, selectedSessionKeyStore, pinnedSessionKeys, isMobile, setOpenMobile, isDragging, isSessionDropTarget, overlay = false, attributes, listeners, onSessionClick, onRenameSession, onDeleteSession, onSetSessionUnread, onMoveSession, onMoveSessionAnyDirectory, onTogglePinnedSession, onCreateSessionInDirectory, onDeleteOldSessionsInDirectory, onRemoveDirectory }) {
21057
+ var DirectorySessionGroup = import_react.memo(function DirectorySessionGroup({ directory, directorySessionsStore, collapsedDirectoryStore, searchActive, moveTargetDirectories, activeSessionStore, selectedSessionKeyStore, pinnedSessionKeys, isMobile, setOpenMobile, isDragging, isSessionDropTarget, overlay = false, attributes, listeners, onSessionClick, onRenameSession, onDeleteSession, onSetSessionUnread, onMoveSession, onMoveSessionAnyDirectory, onTogglePinnedSession, onCreateSessionInDirectory, onDeleteOldSessionsInDirectory, onRemoveDirectory }) {
20674
21058
  const [renderCount, setRenderCount] = import_react.useState(5);
20675
21059
  const { isLoadingSessions, sessionKeys } = useDirectorySessions(directorySessionsStore, directory);
20676
21060
  const collapsed = useDirectoryCollapsed(collapsedDirectoryStore, directory, searchActive);
@@ -20688,7 +21072,7 @@ var DirectorySessionGroup = import_react.memo(function DirectorySessionGroup({ d
20688
21072
  children: [
20689
21073
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CollapsibleTrigger, {
20690
21074
  type: "button",
20691
- className: cn("group/directory-label flex min-w-0 flex-1 items-center gap-2 text-left text-sm text-sidebar-foreground", directoryOrderingEnabled && !overlay && "cursor-grab active:cursor-grabbing", searchActive && "cursor-default"),
21075
+ className: cn("group/directory-label flex min-w-0 flex-1 cursor-default items-center gap-2 text-left text-sm text-sidebar-foreground"),
20692
21076
  disabled: searchActive || overlay,
20693
21077
  ...attributes ?? {},
20694
21078
  ...listeners ?? {},
@@ -21135,7 +21519,6 @@ function useAppSidebarView({ sessionSearch, onOpenSessionsDialog, visibleDirecto
21135
21519
  directorySessionsStore,
21136
21520
  collapsedDirectoryStore,
21137
21521
  searchActive,
21138
- directoryOrderingEnabled,
21139
21522
  moveTargetDirectories: visibleDirectories,
21140
21523
  activeSessionStore,
21141
21524
  selectedSessionKeyStore,
@@ -21167,7 +21550,6 @@ function useAppSidebarView({ sessionSearch, onOpenSessionsDialog, visibleDirecto
21167
21550
  directorySessionsStore,
21168
21551
  collapsedDirectoryStore,
21169
21552
  searchActive,
21170
- directoryOrderingEnabled,
21171
21553
  moveTargetDirectories: visibleDirectories,
21172
21554
  activeSessionStore,
21173
21555
  selectedSessionKeyStore,
@@ -21415,7 +21797,7 @@ function useAppShellSidebarControllerView({ viewerContextId, sidebarStore, sessi
21415
21797
  return indexData ? [[directory, indexData]] : [];
21416
21798
  }));
21417
21799
  sidebarStore.setSidebarState((current) => {
21418
- const nextDirectoryIndexDataByPath = Object.keys(activeDirectoryIndexes).length > 0 ? mergeDirectoryIndexData(current.directoryIndexDataByPath, activeDirectoryIndexes) : current.directoryIndexDataByPath;
21800
+ const nextDirectoryIndexDataByPath = Object.keys(activeDirectoryIndexes).length > 0 ? mergeDirectoryIndexDataPreservingOptimistic(current.directoryIndexDataByPath, activeDirectoryIndexes) : current.directoryIndexDataByPath;
21419
21801
  const nextDirectoryIndexLoading = updateDirectoryIndexLoadingState(current.directoryIndexLoading, activeDirectories, false);
21420
21802
  if (nextDirectoryIndexDataByPath === current.directoryIndexDataByPath && nextDirectoryIndexLoading === current.directoryIndexLoading) return current;
21421
21803
  return {
@@ -21505,7 +21887,7 @@ function useAppShellSidebarControllerView({ viewerContextId, sidebarStore, sessi
21505
21887
  return indexData ? [[directory, indexData]] : [];
21506
21888
  }));
21507
21889
  sidebarStore.setSidebarState((current) => {
21508
- const nextDirectoryIndexDataByPath = Object.keys(activeDirectoryIndexes).length > 0 ? mergeDirectoryIndexData(current.directoryIndexDataByPath, activeDirectoryIndexes) : current.directoryIndexDataByPath;
21890
+ const nextDirectoryIndexDataByPath = Object.keys(activeDirectoryIndexes).length > 0 ? mergeDirectoryIndexDataPreservingOptimistic(current.directoryIndexDataByPath, activeDirectoryIndexes) : current.directoryIndexDataByPath;
21509
21891
  const nextDirectoryIndexLoading = updateDirectoryIndexLoadingState(current.directoryIndexLoading, activeDirectories, false);
21510
21892
  if (nextDirectoryIndexDataByPath === current.directoryIndexDataByPath && nextDirectoryIndexLoading === current.directoryIndexLoading) return current;
21511
21893
  return {
@@ -21596,7 +21978,7 @@ function useAppShellSidebarControllerView({ viewerContextId, sidebarStore, sessi
21596
21978
  return;
21597
21979
  }
21598
21980
  setSidebarSelection([key], key);
21599
- if (entry.id) sessionWorkspaceRef.current?.selectSession(entry.id, { sessionPath: entry.path });
21981
+ if (entry.id && !isOptimisticSidebarSessionEntry(entry)) sessionWorkspaceRef.current?.selectSession(entry.id, { sessionPath: entry.path });
21600
21982
  };
21601
21983
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AppSidebar, {
21602
21984
  sessionSearch,
@@ -22200,11 +22582,10 @@ function createLocalPendingId() {
22200
22582
  }
22201
22583
  function buildCurrentSessionRequestUrl(path, { contextId, sessionState, fallbackSessionId }) {
22202
22584
  const sessionKey = sessionState.sessionKey && !sessionState.sessionKey.startsWith("optimistic:") ? sessionState.sessionKey : void 0;
22203
- const hasFallbackSession = Boolean(fallbackSessionId && fallbackSessionId !== sessionState.sessionId);
22204
- const shouldUseSessionKey = Boolean(sessionKey && !hasFallbackSession && (sessionState.draft || !sessionState.sessionId));
22585
+ const shouldUseSessionKey = Boolean(sessionKey && (sessionState.draft || !sessionState.sessionId));
22205
22586
  return buildRequestUrl(path, {
22206
22587
  contextId,
22207
- sessionId: shouldUseSessionKey ? void 0 : sessionState.sessionId ?? fallbackSessionId,
22588
+ sessionId: shouldUseSessionKey || sessionState.draft ? void 0 : sessionState.sessionId ?? fallbackSessionId,
22208
22589
  searchParams: shouldUseSessionKey ? { sessionKey } : void 0
22209
22590
  });
22210
22591
  }
@@ -22257,7 +22638,7 @@ function movePendingComposerMessage(messages, pendingId, direction) {
22257
22638
  next.splice(targetIndex, 0, movedItem);
22258
22639
  return next;
22259
22640
  }
22260
- function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultNewSessionDirectory, sessionStore, sessionStateRef, draftSessionLoadingOwnerKey, pendingDraftPrompt, pendingDraftFollowUps, awaitingFirstTurn, pendingMessages, composerDiffLineCommentsRef, composerImagesRef, composerTextRef, composerSkillRef, replaceComposerDraft, lastSyncedEditorTextRef, rememberRecentDirectory, prefetchDirectorySessionsIndex, addOptimisticUserMessage, removeOptimisticUserMessage, setSidebarDirectories, setStoredDraftDirectory, setDraftSessionLoadingOwnerKey, setPendingDraftPrompt, setPendingDraftFollowUps, setPendingMessages, setAwaitingFirstTurn, setIsSubmitting, setComposerDiffLineComments, setComposerImages }) {
22641
+ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultNewSessionDirectory, sessionStore, sessionStateRef, draftSessionLoadingOwnerKey, pendingDraftPrompt, pendingDraftFollowUps, awaitingFirstTurn, pendingMessages, composerDiffLineCommentsRef, composerImagesRef, composerTextRef, composerSkillRef, replaceComposerDraft, lastSyncedEditorTextRef, rememberRecentDirectory, prefetchDirectorySessionsIndex, addOptimisticUserMessage, removeOptimisticUserMessage, addOptimisticSidebarSession, removeOptimisticSidebarSession, setSidebarDirectories, setStoredDraftDirectory, setDraftSessionLoadingOwnerKey, setPendingDraftPrompt, setPendingDraftFollowUps, setPendingMessages, setAwaitingFirstTurn, setIsSubmitting, setComposerDiffLineComments, setComposerImages }) {
22261
22642
  const queryClient = useQueryClient();
22262
22643
  const draftSessionLoadingOwnerKeyRef = import_react.useRef(draftSessionLoadingOwnerKey);
22263
22644
  const pendingDraftPromptRef = import_react.useRef(pendingDraftPrompt);
@@ -22337,6 +22718,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22337
22718
  const nextPrompt = pendingDraftPromptRef.current;
22338
22719
  if (!nextPrompt || nextPrompt.ownerKey !== ownerKey) return false;
22339
22720
  removeOptimisticUserMessage(nextPrompt.optimisticId);
22721
+ removeOptimisticSidebarSession(nextPrompt.optimisticSidebarSessionId);
22340
22722
  for (const followUp of pendingDraftFollowUpsRef.current) removeOptimisticUserMessage(followUp.optimisticId);
22341
22723
  pendingDraftPromptRef.current = null;
22342
22724
  pendingDraftFollowUpsRef.current = [];
@@ -22348,6 +22730,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22348
22730
  return applyPendingDraftPromptToComposer(nextPrompt);
22349
22731
  }, [
22350
22732
  applyPendingDraftPromptToComposer,
22733
+ removeOptimisticSidebarSession,
22351
22734
  removeOptimisticUserMessage,
22352
22735
  setAwaitingFirstTurn,
22353
22736
  setPendingDraftFollowUps,
@@ -22380,15 +22763,20 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22380
22763
  ]);
22381
22764
  const createSessionRequest = import_react.useCallback(async ({ cwd }) => {
22382
22765
  if (!viewerContextId) throw new Error("Viewer context unavailable");
22383
- return await fetchJson(buildRequestUrl("/api/session/new", {
22766
+ return await fetchJson(buildCurrentSessionRequestUrl("/api/session/new", {
22384
22767
  contextId: viewerContextId,
22385
- sessionId: activeSessionId
22768
+ sessionState: sessionStateRef.current,
22769
+ fallbackSessionId: activeSessionId
22386
22770
  }), {
22387
22771
  method: "POST",
22388
22772
  headers: { "content-type": "application/json" },
22389
22773
  body: JSON.stringify({ cwd })
22390
22774
  });
22391
- }, [activeSessionId, viewerContextId]);
22775
+ }, [
22776
+ activeSessionId,
22777
+ sessionStateRef,
22778
+ viewerContextId
22779
+ ]);
22392
22780
  const createSession = import_react.useCallback(async (cwdOverride) => {
22393
22781
  if (!viewerContextId) return false;
22394
22782
  const nextCwd = resolveNewSessionCwd({
@@ -22443,7 +22831,8 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22443
22831
  message,
22444
22832
  images,
22445
22833
  queued: false
22446
- })
22834
+ }),
22835
+ optimisticSidebarSessionId: addOptimisticSidebarSession()
22447
22836
  };
22448
22837
  pendingDraftPromptRef.current = nextPrompt;
22449
22838
  setPendingDraftPrompt(nextPrompt);
@@ -22468,6 +22857,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22468
22857
  lastSyncedEditorTextRef.current = "";
22469
22858
  return true;
22470
22859
  }, [
22860
+ addOptimisticSidebarSession,
22471
22861
  addOptimisticUserMessage,
22472
22862
  composerDiffLineCommentsRef,
22473
22863
  composerImagesRef,
@@ -22531,6 +22921,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22531
22921
  images: submittedImages,
22532
22922
  queued: false
22533
22923
  }));
22924
+ const optimisticSidebarSessionId = options?.optimisticSidebarSessionId ?? (!treatAsQueuedPrompt && sessionStateRef.current.draft ? addOptimisticSidebarSession() : void 0);
22534
22925
  if (queuedPendingId && normalizedStreamingBehavior) addOptimisticPendingMessage({
22535
22926
  pendingId: queuedPendingId,
22536
22927
  text: message,
@@ -22555,6 +22946,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22555
22946
  } catch (error) {
22556
22947
  if (queuedPendingId) removeOptimisticPendingMessage(queuedPendingId);
22557
22948
  removeOptimisticUserMessage(optimisticId);
22949
+ removeOptimisticSidebarSession(optimisticSidebarSessionId);
22558
22950
  if (!treatAsQueuedPrompt) {
22559
22951
  awaitingFirstTurnAssistantOutputSignatureRef.current = null;
22560
22952
  awaitingFirstTurnRef.current = false;
@@ -22575,6 +22967,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22575
22967
  }
22576
22968
  }, [
22577
22969
  addOptimisticPendingMessage,
22970
+ addOptimisticSidebarSession,
22578
22971
  addOptimisticUserMessage,
22579
22972
  composerDiffLineCommentsRef,
22580
22973
  composerImagesRef,
@@ -22585,6 +22978,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22585
22978
  queuePendingDraftPrompt,
22586
22979
  sessionStateRef,
22587
22980
  removeOptimisticPendingMessage,
22981
+ removeOptimisticSidebarSession,
22588
22982
  removeOptimisticUserMessage,
22589
22983
  replaceComposerDraft,
22590
22984
  setAwaitingFirstTurn,
@@ -22645,8 +23039,10 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22645
23039
  applyPendingDraftPromptToComposer(nextPrompt);
22646
23040
  if (!await submitPrompt(nextPrompt.streamingBehavior, {
22647
23041
  forceFirstPrompt: true,
22648
- optimisticId: nextPrompt.optimisticId
23042
+ optimisticId: nextPrompt.optimisticId,
23043
+ optimisticSidebarSessionId: nextPrompt.optimisticSidebarSessionId
22649
23044
  })) {
23045
+ removeOptimisticSidebarSession(nextPrompt.optimisticSidebarSessionId);
22650
23046
  for (const followUp of pendingDraftFollowUpsRef.current) removeOptimisticUserMessage(followUp.optimisticId);
22651
23047
  pendingDraftFollowUpsRef.current = [];
22652
23048
  setPendingDraftFollowUps([]);
@@ -22657,6 +23053,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22657
23053
  }, [
22658
23054
  applyPendingDraftPromptToComposer,
22659
23055
  flushPendingDraftFollowUps,
23056
+ removeOptimisticSidebarSession,
22660
23057
  removeOptimisticUserMessage,
22661
23058
  setPendingDraftFollowUps,
22662
23059
  setPendingDraftPrompt,
@@ -22834,20 +23231,33 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22834
23231
  }
22835
23232
  function usePicoTheme() {
22836
23233
  const { setTheme, systemTheme } = z();
22837
- const [themeFamily, setThemeFamilyState] = import_react.useState(() => readStoredTheme());
22838
- const [colorMode, setColorModeState] = import_react.useState(() => readStoredThemeColorMode());
23234
+ const initialThemeRef = import_react.useRef(void 0);
23235
+ const initialTheme = initialThemeRef.current ?? readStoredTheme();
23236
+ initialThemeRef.current = initialTheme;
23237
+ const [themeFamily, setThemeFamilyState] = import_react.useState(initialTheme);
23238
+ const [colorMode, setColorModeState] = import_react.useState(() => themeFamilyFixedMode(initialTheme) ?? readStoredThemeColorMode());
22839
23239
  const appliedTheme = appliedThemeClass(themeFamily, colorMode, systemTheme);
22840
23240
  import_react.useEffect(() => {
22841
23241
  setTheme(appliedTheme);
22842
23242
  safeLocalStorageSetItem(APPLIED_THEME_STORAGE_KEY, appliedTheme);
23243
+ const appliedThemeMode = appliedThemeClassColorMode(appliedTheme);
23244
+ if (appliedThemeMode) document.documentElement.dataset.picoThemeMode = appliedThemeMode;
22843
23245
  }, [appliedTheme, setTheme]);
22844
- const previewThemeFamily = (value) => {
22845
- setThemeFamilyState(normalizeThemeFamily(value));
23246
+ const previewThemeFamily = (value, nextColorMode) => {
23247
+ const nextTheme = normalizeThemeFamily(value);
23248
+ const fixedMode = themeFamilyFixedMode(nextTheme);
23249
+ setThemeFamilyState(nextTheme);
23250
+ if (nextColorMode || fixedMode) setColorModeState(normalizeThemeColorMode(nextColorMode ?? fixedMode));
22846
23251
  };
22847
23252
  const setThemeFamily = (value) => {
22848
23253
  const nextTheme = normalizeThemeFamily(value);
23254
+ const fixedMode = themeFamilyFixedMode(nextTheme);
22849
23255
  setThemeFamilyState(nextTheme);
22850
23256
  safeLocalStorageSetItem(THEME_STORAGE_KEY, nextTheme);
23257
+ if (fixedMode) {
23258
+ setColorModeState(fixedMode);
23259
+ safeLocalStorageSetItem(THEME_COLOR_MODE_STORAGE_KEY, fixedMode);
23260
+ }
22851
23261
  };
22852
23262
  const setColorMode = (value) => {
22853
23263
  const nextMode = normalizeThemeColorMode(value);
@@ -23560,6 +23970,7 @@ function sameSessionListEntries(left = [], right = []) {
23560
23970
  if (!sameContextUsage(leftEntry.contextUsage, rightEntry.contextUsage)) return false;
23561
23971
  if (Boolean(leftEntry.streaming) !== Boolean(rightEntry.streaming)) return false;
23562
23972
  if (Boolean(leftEntry.unread) !== Boolean(rightEntry.unread)) return false;
23973
+ if (Boolean(leftEntry.optimistic) !== Boolean(rightEntry.optimistic)) return false;
23563
23974
  }
23564
23975
  return true;
23565
23976
  }
@@ -24136,13 +24547,12 @@ function useAppShellShortcuts({ addDirectoryOpenRef, commandPaletteOpenRef, comp
24136
24547
  event.preventDefault();
24137
24548
  sessionButtons[nextIndex]?.focus();
24138
24549
  };
24139
- const handleSidebarDelete = (event) => {
24550
+ const handleSidebarBackspaceDelete = (event) => {
24140
24551
  const context = getShortcutContext(event);
24141
24552
  if (context.modalOpen || isEditableTarget(event.target) && !context.targetIsSessionSearch) return;
24142
- const targetsToDelete = context.selectedSidebarSessions.length > 0 ? context.selectedSidebarSessions : context.focusedSidebarSession?.path ? [context.focusedSidebarSession] : [];
24143
- if (targetsToDelete.length === 0) return;
24553
+ if (context.selectedSidebarSessions.length <= 1) return;
24144
24554
  event.preventDefault();
24145
- shortcutActionsRef.current.openDeleteDialog(targetsToDelete);
24555
+ shortcutActionsRef.current.openDeleteDialog(context.selectedSidebarSessions);
24146
24556
  };
24147
24557
  const handleFocusPrompt = (event) => {
24148
24558
  const context = getShortcutContext(event);
@@ -24314,11 +24724,11 @@ function useAppShellShortcuts({ addDirectoryOpenRef, commandPaletteOpenRef, comp
24314
24724
  } }
24315
24725
  })),
24316
24726
  {
24317
- hotkey: "Delete",
24318
- callback: handleSidebarDelete,
24727
+ hotkey: "Backspace",
24728
+ callback: handleSidebarBackspaceDelete,
24319
24729
  options: { meta: {
24320
24730
  name: "Delete selected sidebar sessions",
24321
- description: "Open the delete dialog for focused or selected sessions."
24731
+ description: "Open the delete dialog for multiple selected sidebar sessions."
24322
24732
  } }
24323
24733
  },
24324
24734
  {
@@ -25475,6 +25885,64 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
25475
25885
  });
25476
25886
  };
25477
25887
  const prefetchDirectorySessionsIndex = import_react.useCallback((_directory) => {}, []);
25888
+ const addOptimisticSidebarSession = import_react.useCallback((options) => {
25889
+ const currentState = sessionStateRef.current;
25890
+ const optimisticId = (options?.id || currentState.sessionKey || `optimistic:${promptDraftKey(currentState)}`).trim();
25891
+ const cwd = (options?.cwd || currentState.cwd || defaultNewSessionDirectory).trim();
25892
+ if (!optimisticId || !cwd) return void 0;
25893
+ const modified = (/* @__PURE__ */ new Date()).toISOString();
25894
+ const entry = {
25895
+ id: optimisticId,
25896
+ cwd,
25897
+ title: "New session",
25898
+ modified,
25899
+ lastUserMessageAt: modified,
25900
+ streaming: true,
25901
+ unread: false,
25902
+ optimistic: true
25903
+ };
25904
+ const entryKey = sessionListEntryKey(entry);
25905
+ sidebarStore.setSidebarDirectories((current) => {
25906
+ const normalizedCurrent = normalizeStoredDirectoryList(current);
25907
+ if (normalizedCurrent.includes(cwd)) return current;
25908
+ const nextDirectories = normalizeStoredDirectoryList([cwd, ...normalizedCurrent]);
25909
+ safeLocalStorageSetItem(SIDEBAR_DIRECTORIES_STORAGE_KEY, JSON.stringify(nextDirectories));
25910
+ return nextDirectories;
25911
+ });
25912
+ const optimisticEntry = {
25913
+ ...entry,
25914
+ id: optimisticId,
25915
+ cwd
25916
+ };
25917
+ sidebarStore.setDirectoryIndexDataByPath((current) => upsertOptimisticSidebarSessionEntry(current, optimisticEntry));
25918
+ sidebarStore.setSessionsEvent((current) => current ? {
25919
+ ...current,
25920
+ directoryIndexes: upsertOptimisticSidebarSessionEntry(current.directoryIndexes || {}, optimisticEntry)
25921
+ } : current);
25922
+ if (entryKey) {
25923
+ sidebarStore.setSelectedSidebarSessionKeys((current) => sameStringArray$3(current, [entryKey]) ? current : [entryKey]);
25924
+ sidebarStore.setSidebarSessionSelectionAnchor((current) => current === entryKey ? current : entryKey);
25925
+ }
25926
+ return optimisticId;
25927
+ }, [
25928
+ defaultNewSessionDirectory,
25929
+ sessionStateRef,
25930
+ sidebarStore
25931
+ ]);
25932
+ const removeOptimisticSidebarSession = import_react.useCallback((optimisticId) => {
25933
+ const targetId = optimisticId?.trim() || "";
25934
+ if (!targetId) return;
25935
+ const entryKey = sessionListEntryKey({ id: targetId });
25936
+ sidebarStore.setDirectoryIndexDataByPath((current) => removeOptimisticSidebarSessionEntry(current, targetId));
25937
+ sidebarStore.setSessionsEvent((current) => current?.directoryIndexes ? {
25938
+ ...current,
25939
+ directoryIndexes: removeOptimisticSidebarSessionEntry(current.directoryIndexes, targetId)
25940
+ } : current);
25941
+ if (entryKey) {
25942
+ sidebarStore.setSelectedSidebarSessionKeys((current) => current.filter((key) => key !== entryKey));
25943
+ sidebarStore.setSidebarSessionSelectionAnchor((current) => current === entryKey ? "" : current);
25944
+ }
25945
+ }, [sidebarStore]);
25478
25946
  const clearSelectedSidebarSelection = import_react.useCallback(() => {
25479
25947
  sidebarStore.setSelectedSidebarSessionKeys((current) => current.length === 0 ? current : []);
25480
25948
  sidebarStore.setSidebarSessionSelectionAnchor((current) => current ? "" : current);
@@ -25505,6 +25973,8 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
25505
25973
  prefetchDirectorySessionsIndex,
25506
25974
  addOptimisticUserMessage,
25507
25975
  removeOptimisticUserMessage,
25976
+ addOptimisticSidebarSession,
25977
+ removeOptimisticSidebarSession,
25508
25978
  setSidebarDirectories: sidebarStore.setSidebarDirectories,
25509
25979
  setStoredDraftDirectory,
25510
25980
  setDraftSessionLoadingOwnerKey,
@@ -25558,6 +26028,7 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
25558
26028
  const ownerKey = promptDraftKey({ cwd: nextCwd });
25559
26029
  const optimisticSessionKey = `optimistic:${ownerKey}`;
25560
26030
  const shouldCloseMobileSidebar = Boolean(options?.closeMobileSidebar) && isMobile && openMobile;
26031
+ const createSessionPromise = requestCreateSession(nextCwd);
25561
26032
  handleSelectSession(void 0);
25562
26033
  clearSelectedSidebarSelection();
25563
26034
  if (shouldCloseMobileSidebar) {
@@ -25574,7 +26045,7 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
25574
26045
  sessionStateRef.current = nextState;
25575
26046
  conversationItemsStore.setItems(nextState.items);
25576
26047
  setSessionState(nextState);
25577
- if (await requestCreateSession(nextCwd)) return;
26048
+ if (await createSessionPromise) return;
25578
26049
  if (sessionStateRef.current.sessionKey !== optimisticSessionKey) return;
25579
26050
  sessionStateRef.current = previousState;
25580
26051
  conversationItemsStore.setItems(previousState.items);
@@ -25910,8 +26381,8 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
25910
26381
  const handleThemeChange = (value) => {
25911
26382
  setThemeFamily(value);
25912
26383
  };
25913
- const handleThemePreviewChange = (value) => {
25914
- previewThemeFamily(value);
26384
+ const handleThemePreviewChange = (value, colorMode) => {
26385
+ previewThemeFamily(value, colorMode);
25915
26386
  };
25916
26387
  const handleThemeColorModeChange = (value) => {
25917
26388
  setColorMode(value);