@alivault/pico 0.10.1 → 0.10.3

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-DMdIR42g.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-Ia1sMc23.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);
@@ -22267,6 +22648,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22267
22648
  const awaitingFirstTurnAssistantOutputSignatureRef = import_react.useRef(null);
22268
22649
  const sessionSnapshot = usePromptMutationSessionSnapshot(sessionStore);
22269
22650
  const sessionStreamingRef = import_react.useRef(sessionSnapshot.streaming);
22651
+ const flushPendingDraftPromptRef = import_react.useRef(async () => false);
22270
22652
  import_react.useEffect(() => {
22271
22653
  draftSessionLoadingOwnerKeyRef.current = draftSessionLoadingOwnerKey;
22272
22654
  }, [draftSessionLoadingOwnerKey]);
@@ -22337,6 +22719,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22337
22719
  const nextPrompt = pendingDraftPromptRef.current;
22338
22720
  if (!nextPrompt || nextPrompt.ownerKey !== ownerKey) return false;
22339
22721
  removeOptimisticUserMessage(nextPrompt.optimisticId);
22722
+ removeOptimisticSidebarSession(nextPrompt.optimisticSidebarSessionId);
22340
22723
  for (const followUp of pendingDraftFollowUpsRef.current) removeOptimisticUserMessage(followUp.optimisticId);
22341
22724
  pendingDraftPromptRef.current = null;
22342
22725
  pendingDraftFollowUpsRef.current = [];
@@ -22348,6 +22731,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22348
22731
  return applyPendingDraftPromptToComposer(nextPrompt);
22349
22732
  }, [
22350
22733
  applyPendingDraftPromptToComposer,
22734
+ removeOptimisticSidebarSession,
22351
22735
  removeOptimisticUserMessage,
22352
22736
  setAwaitingFirstTurn,
22353
22737
  setPendingDraftFollowUps,
@@ -22380,15 +22764,20 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22380
22764
  ]);
22381
22765
  const createSessionRequest = import_react.useCallback(async ({ cwd }) => {
22382
22766
  if (!viewerContextId) throw new Error("Viewer context unavailable");
22383
- return await fetchJson(buildRequestUrl("/api/session/new", {
22767
+ return await fetchJson(buildCurrentSessionRequestUrl("/api/session/new", {
22384
22768
  contextId: viewerContextId,
22385
- sessionId: activeSessionId
22769
+ sessionState: sessionStateRef.current,
22770
+ fallbackSessionId: activeSessionId
22386
22771
  }), {
22387
22772
  method: "POST",
22388
22773
  headers: { "content-type": "application/json" },
22389
22774
  body: JSON.stringify({ cwd })
22390
22775
  });
22391
- }, [activeSessionId, viewerContextId]);
22776
+ }, [
22777
+ activeSessionId,
22778
+ sessionStateRef,
22779
+ viewerContextId
22780
+ ]);
22392
22781
  const createSession = import_react.useCallback(async (cwdOverride) => {
22393
22782
  if (!viewerContextId) return false;
22394
22783
  const nextCwd = resolveNewSessionCwd({
@@ -22406,6 +22795,11 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22406
22795
  setDraftSessionLoadingOwnerKey(ownerKey);
22407
22796
  try {
22408
22797
  await createSessionRequest({ cwd: nextCwd });
22798
+ if (draftSessionLoadingOwnerKeyRef.current === ownerKey) {
22799
+ draftSessionLoadingOwnerKeyRef.current = null;
22800
+ setDraftSessionLoadingOwnerKey((current) => current === ownerKey ? null : current);
22801
+ }
22802
+ if (pendingDraftPromptRef.current?.ownerKey === ownerKey) flushPendingDraftPromptRef.current(ownerKey);
22409
22803
  return true;
22410
22804
  } catch (error) {
22411
22805
  if (draftSessionLoadingOwnerKeyRef.current === ownerKey) draftSessionLoadingOwnerKeyRef.current = null;
@@ -22443,7 +22837,8 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22443
22837
  message,
22444
22838
  images,
22445
22839
  queued: false
22446
- })
22840
+ }),
22841
+ optimisticSidebarSessionId: addOptimisticSidebarSession()
22447
22842
  };
22448
22843
  pendingDraftPromptRef.current = nextPrompt;
22449
22844
  setPendingDraftPrompt(nextPrompt);
@@ -22468,6 +22863,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22468
22863
  lastSyncedEditorTextRef.current = "";
22469
22864
  return true;
22470
22865
  }, [
22866
+ addOptimisticSidebarSession,
22471
22867
  addOptimisticUserMessage,
22472
22868
  composerDiffLineCommentsRef,
22473
22869
  composerImagesRef,
@@ -22531,6 +22927,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22531
22927
  images: submittedImages,
22532
22928
  queued: false
22533
22929
  }));
22930
+ const optimisticSidebarSessionId = options?.optimisticSidebarSessionId ?? (!treatAsQueuedPrompt && sessionStateRef.current.draft ? addOptimisticSidebarSession() : void 0);
22534
22931
  if (queuedPendingId && normalizedStreamingBehavior) addOptimisticPendingMessage({
22535
22932
  pendingId: queuedPendingId,
22536
22933
  text: message,
@@ -22555,6 +22952,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22555
22952
  } catch (error) {
22556
22953
  if (queuedPendingId) removeOptimisticPendingMessage(queuedPendingId);
22557
22954
  removeOptimisticUserMessage(optimisticId);
22955
+ removeOptimisticSidebarSession(optimisticSidebarSessionId);
22558
22956
  if (!treatAsQueuedPrompt) {
22559
22957
  awaitingFirstTurnAssistantOutputSignatureRef.current = null;
22560
22958
  awaitingFirstTurnRef.current = false;
@@ -22575,6 +22973,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22575
22973
  }
22576
22974
  }, [
22577
22975
  addOptimisticPendingMessage,
22976
+ addOptimisticSidebarSession,
22578
22977
  addOptimisticUserMessage,
22579
22978
  composerDiffLineCommentsRef,
22580
22979
  composerImagesRef,
@@ -22585,6 +22984,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22585
22984
  queuePendingDraftPrompt,
22586
22985
  sessionStateRef,
22587
22986
  removeOptimisticPendingMessage,
22987
+ removeOptimisticSidebarSession,
22588
22988
  removeOptimisticUserMessage,
22589
22989
  replaceComposerDraft,
22590
22990
  setAwaitingFirstTurn,
@@ -22645,8 +23045,10 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22645
23045
  applyPendingDraftPromptToComposer(nextPrompt);
22646
23046
  if (!await submitPrompt(nextPrompt.streamingBehavior, {
22647
23047
  forceFirstPrompt: true,
22648
- optimisticId: nextPrompt.optimisticId
23048
+ optimisticId: nextPrompt.optimisticId,
23049
+ optimisticSidebarSessionId: nextPrompt.optimisticSidebarSessionId
22649
23050
  })) {
23051
+ removeOptimisticSidebarSession(nextPrompt.optimisticSidebarSessionId);
22650
23052
  for (const followUp of pendingDraftFollowUpsRef.current) removeOptimisticUserMessage(followUp.optimisticId);
22651
23053
  pendingDraftFollowUpsRef.current = [];
22652
23054
  setPendingDraftFollowUps([]);
@@ -22657,11 +23059,13 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22657
23059
  }, [
22658
23060
  applyPendingDraftPromptToComposer,
22659
23061
  flushPendingDraftFollowUps,
23062
+ removeOptimisticSidebarSession,
22660
23063
  removeOptimisticUserMessage,
22661
23064
  setPendingDraftFollowUps,
22662
23065
  setPendingDraftPrompt,
22663
23066
  submitPrompt
22664
23067
  ]);
23068
+ flushPendingDraftPromptRef.current = flushPendingDraftPrompt;
22665
23069
  import_react.useEffect(() => {
22666
23070
  if (!draftSessionLoadingOwnerKey) return;
22667
23071
  const currentSessionState = sessionStateRef.current;
@@ -22834,20 +23238,33 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
22834
23238
  }
22835
23239
  function usePicoTheme() {
22836
23240
  const { setTheme, systemTheme } = z();
22837
- const [themeFamily, setThemeFamilyState] = import_react.useState(() => readStoredTheme());
22838
- const [colorMode, setColorModeState] = import_react.useState(() => readStoredThemeColorMode());
23241
+ const initialThemeRef = import_react.useRef(void 0);
23242
+ const initialTheme = initialThemeRef.current ?? readStoredTheme();
23243
+ initialThemeRef.current = initialTheme;
23244
+ const [themeFamily, setThemeFamilyState] = import_react.useState(initialTheme);
23245
+ const [colorMode, setColorModeState] = import_react.useState(() => themeFamilyFixedMode(initialTheme) ?? readStoredThemeColorMode());
22839
23246
  const appliedTheme = appliedThemeClass(themeFamily, colorMode, systemTheme);
22840
23247
  import_react.useEffect(() => {
22841
23248
  setTheme(appliedTheme);
22842
23249
  safeLocalStorageSetItem(APPLIED_THEME_STORAGE_KEY, appliedTheme);
23250
+ const appliedThemeMode = appliedThemeClassColorMode(appliedTheme);
23251
+ if (appliedThemeMode) document.documentElement.dataset.picoThemeMode = appliedThemeMode;
22843
23252
  }, [appliedTheme, setTheme]);
22844
- const previewThemeFamily = (value) => {
22845
- setThemeFamilyState(normalizeThemeFamily(value));
23253
+ const previewThemeFamily = (value, nextColorMode) => {
23254
+ const nextTheme = normalizeThemeFamily(value);
23255
+ const fixedMode = themeFamilyFixedMode(nextTheme);
23256
+ setThemeFamilyState(nextTheme);
23257
+ if (nextColorMode || fixedMode) setColorModeState(normalizeThemeColorMode(nextColorMode ?? fixedMode));
22846
23258
  };
22847
23259
  const setThemeFamily = (value) => {
22848
23260
  const nextTheme = normalizeThemeFamily(value);
23261
+ const fixedMode = themeFamilyFixedMode(nextTheme);
22849
23262
  setThemeFamilyState(nextTheme);
22850
23263
  safeLocalStorageSetItem(THEME_STORAGE_KEY, nextTheme);
23264
+ if (fixedMode) {
23265
+ setColorModeState(fixedMode);
23266
+ safeLocalStorageSetItem(THEME_COLOR_MODE_STORAGE_KEY, fixedMode);
23267
+ }
22851
23268
  };
22852
23269
  const setColorMode = (value) => {
22853
23270
  const nextMode = normalizeThemeColorMode(value);
@@ -23560,6 +23977,7 @@ function sameSessionListEntries(left = [], right = []) {
23560
23977
  if (!sameContextUsage(leftEntry.contextUsage, rightEntry.contextUsage)) return false;
23561
23978
  if (Boolean(leftEntry.streaming) !== Boolean(rightEntry.streaming)) return false;
23562
23979
  if (Boolean(leftEntry.unread) !== Boolean(rightEntry.unread)) return false;
23980
+ if (Boolean(leftEntry.optimistic) !== Boolean(rightEntry.optimistic)) return false;
23563
23981
  }
23564
23982
  return true;
23565
23983
  }
@@ -24136,13 +24554,12 @@ function useAppShellShortcuts({ addDirectoryOpenRef, commandPaletteOpenRef, comp
24136
24554
  event.preventDefault();
24137
24555
  sessionButtons[nextIndex]?.focus();
24138
24556
  };
24139
- const handleSidebarDelete = (event) => {
24557
+ const handleSidebarBackspaceDelete = (event) => {
24140
24558
  const context = getShortcutContext(event);
24141
24559
  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;
24560
+ if (context.selectedSidebarSessions.length <= 1) return;
24144
24561
  event.preventDefault();
24145
- shortcutActionsRef.current.openDeleteDialog(targetsToDelete);
24562
+ shortcutActionsRef.current.openDeleteDialog(context.selectedSidebarSessions);
24146
24563
  };
24147
24564
  const handleFocusPrompt = (event) => {
24148
24565
  const context = getShortcutContext(event);
@@ -24314,11 +24731,11 @@ function useAppShellShortcuts({ addDirectoryOpenRef, commandPaletteOpenRef, comp
24314
24731
  } }
24315
24732
  })),
24316
24733
  {
24317
- hotkey: "Delete",
24318
- callback: handleSidebarDelete,
24734
+ hotkey: "Backspace",
24735
+ callback: handleSidebarBackspaceDelete,
24319
24736
  options: { meta: {
24320
24737
  name: "Delete selected sidebar sessions",
24321
- description: "Open the delete dialog for focused or selected sessions."
24738
+ description: "Open the delete dialog for multiple selected sidebar sessions."
24322
24739
  } }
24323
24740
  },
24324
24741
  {
@@ -25475,6 +25892,64 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
25475
25892
  });
25476
25893
  };
25477
25894
  const prefetchDirectorySessionsIndex = import_react.useCallback((_directory) => {}, []);
25895
+ const addOptimisticSidebarSession = import_react.useCallback((options) => {
25896
+ const currentState = sessionStateRef.current;
25897
+ const optimisticId = (options?.id || currentState.sessionKey || `optimistic:${promptDraftKey(currentState)}`).trim();
25898
+ const cwd = (options?.cwd || currentState.cwd || defaultNewSessionDirectory).trim();
25899
+ if (!optimisticId || !cwd) return void 0;
25900
+ const modified = (/* @__PURE__ */ new Date()).toISOString();
25901
+ const entry = {
25902
+ id: optimisticId,
25903
+ cwd,
25904
+ title: "New session",
25905
+ modified,
25906
+ lastUserMessageAt: modified,
25907
+ streaming: true,
25908
+ unread: false,
25909
+ optimistic: true
25910
+ };
25911
+ const entryKey = sessionListEntryKey(entry);
25912
+ sidebarStore.setSidebarDirectories((current) => {
25913
+ const normalizedCurrent = normalizeStoredDirectoryList(current);
25914
+ if (normalizedCurrent.includes(cwd)) return current;
25915
+ const nextDirectories = normalizeStoredDirectoryList([cwd, ...normalizedCurrent]);
25916
+ safeLocalStorageSetItem(SIDEBAR_DIRECTORIES_STORAGE_KEY, JSON.stringify(nextDirectories));
25917
+ return nextDirectories;
25918
+ });
25919
+ const optimisticEntry = {
25920
+ ...entry,
25921
+ id: optimisticId,
25922
+ cwd
25923
+ };
25924
+ sidebarStore.setDirectoryIndexDataByPath((current) => upsertOptimisticSidebarSessionEntry(current, optimisticEntry));
25925
+ sidebarStore.setSessionsEvent((current) => current ? {
25926
+ ...current,
25927
+ directoryIndexes: upsertOptimisticSidebarSessionEntry(current.directoryIndexes || {}, optimisticEntry)
25928
+ } : current);
25929
+ if (entryKey) {
25930
+ sidebarStore.setSelectedSidebarSessionKeys((current) => sameStringArray$3(current, [entryKey]) ? current : [entryKey]);
25931
+ sidebarStore.setSidebarSessionSelectionAnchor((current) => current === entryKey ? current : entryKey);
25932
+ }
25933
+ return optimisticId;
25934
+ }, [
25935
+ defaultNewSessionDirectory,
25936
+ sessionStateRef,
25937
+ sidebarStore
25938
+ ]);
25939
+ const removeOptimisticSidebarSession = import_react.useCallback((optimisticId) => {
25940
+ const targetId = optimisticId?.trim() || "";
25941
+ if (!targetId) return;
25942
+ const entryKey = sessionListEntryKey({ id: targetId });
25943
+ sidebarStore.setDirectoryIndexDataByPath((current) => removeOptimisticSidebarSessionEntry(current, targetId));
25944
+ sidebarStore.setSessionsEvent((current) => current?.directoryIndexes ? {
25945
+ ...current,
25946
+ directoryIndexes: removeOptimisticSidebarSessionEntry(current.directoryIndexes, targetId)
25947
+ } : current);
25948
+ if (entryKey) {
25949
+ sidebarStore.setSelectedSidebarSessionKeys((current) => current.filter((key) => key !== entryKey));
25950
+ sidebarStore.setSidebarSessionSelectionAnchor((current) => current === entryKey ? "" : current);
25951
+ }
25952
+ }, [sidebarStore]);
25478
25953
  const clearSelectedSidebarSelection = import_react.useCallback(() => {
25479
25954
  sidebarStore.setSelectedSidebarSessionKeys((current) => current.length === 0 ? current : []);
25480
25955
  sidebarStore.setSidebarSessionSelectionAnchor((current) => current ? "" : current);
@@ -25505,6 +25980,8 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
25505
25980
  prefetchDirectorySessionsIndex,
25506
25981
  addOptimisticUserMessage,
25507
25982
  removeOptimisticUserMessage,
25983
+ addOptimisticSidebarSession,
25984
+ removeOptimisticSidebarSession,
25508
25985
  setSidebarDirectories: sidebarStore.setSidebarDirectories,
25509
25986
  setStoredDraftDirectory,
25510
25987
  setDraftSessionLoadingOwnerKey,
@@ -25558,6 +26035,7 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
25558
26035
  const ownerKey = promptDraftKey({ cwd: nextCwd });
25559
26036
  const optimisticSessionKey = `optimistic:${ownerKey}`;
25560
26037
  const shouldCloseMobileSidebar = Boolean(options?.closeMobileSidebar) && isMobile && openMobile;
26038
+ const createSessionPromise = requestCreateSession(nextCwd);
25561
26039
  handleSelectSession(void 0);
25562
26040
  clearSelectedSidebarSelection();
25563
26041
  if (shouldCloseMobileSidebar) {
@@ -25574,7 +26052,7 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
25574
26052
  sessionStateRef.current = nextState;
25575
26053
  conversationItemsStore.setItems(nextState.items);
25576
26054
  setSessionState(nextState);
25577
- if (await requestCreateSession(nextCwd)) return;
26055
+ if (await createSessionPromise) return;
25578
26056
  if (sessionStateRef.current.sessionKey !== optimisticSessionKey) return;
25579
26057
  sessionStateRef.current = previousState;
25580
26058
  conversationItemsStore.setItems(previousState.items);
@@ -25910,8 +26388,8 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
25910
26388
  const handleThemeChange = (value) => {
25911
26389
  setThemeFamily(value);
25912
26390
  };
25913
- const handleThemePreviewChange = (value) => {
25914
- previewThemeFamily(value);
26391
+ const handleThemePreviewChange = (value, colorMode) => {
26392
+ previewThemeFamily(value, colorMode);
25915
26393
  };
25916
26394
  const handleThemeColorModeChange = (value) => {
25917
26395
  setColorMode(value);