From e0e4259acf5a7325554e96ae5945289f5397b085 Mon Sep 17 00:00:00 2001
From: Adam Dalloul <47503782+Adam-Dalloul@users.noreply.github.com>
Date: Sat, 15 Aug 2026 19:01:16 -0700
Subject: [PATCH 1/2] feat(chat): setting to keep the agent plan overlay
collapsed
---
.../chat/agent-plan-overlay.test.tsx | 37 +++++++++++++++++-
src/components/chat/agent-plan-overlay.tsx | 3 ++
.../settings/appearance-settings.tsx | 29 +++++++++++++-
src/hooks/use-plan-overlay-auto-expand.ts | 38 +++++++++++++++++++
src/i18n/messages/ar.json | 5 +++
src/i18n/messages/de.json | 5 +++
src/i18n/messages/en.json | 5 +++
src/i18n/messages/es.json | 5 +++
src/i18n/messages/fr.json | 5 +++
src/i18n/messages/ja.json | 5 +++
src/i18n/messages/ko.json | 5 +++
src/i18n/messages/pt.json | 5 +++
src/i18n/messages/zh-CN.json | 5 +++
src/i18n/messages/zh-TW.json | 5 +++
src/lib/plan-overlay-prefs.test.ts | 26 +++++++++++++
src/lib/plan-overlay-prefs.ts | 38 +++++++++++++++++++
16 files changed, 219 insertions(+), 2 deletions(-)
create mode 100644 src/hooks/use-plan-overlay-auto-expand.ts
create mode 100644 src/lib/plan-overlay-prefs.test.ts
create mode 100644 src/lib/plan-overlay-prefs.ts
diff --git a/src/components/chat/agent-plan-overlay.test.tsx b/src/components/chat/agent-plan-overlay.test.tsx
index e55e689c4..edc4aec4a 100644
--- a/src/components/chat/agent-plan-overlay.test.tsx
+++ b/src/components/chat/agent-plan-overlay.test.tsx
@@ -1,6 +1,6 @@
import { fireEvent, render, screen } from "@testing-library/react"
import { NextIntlClientProvider } from "next-intl"
-import { describe, expect, it } from "vitest"
+import { afterEach, describe, expect, it } from "vitest"
import { AgentPlanOverlay } from "./agent-plan-overlay"
import enMessages from "@/i18n/messages/en.json"
@@ -22,6 +22,10 @@ const sampleEntries: PlanEntryInfo[] = [
]
describe("AgentPlanOverlay", () => {
+ afterEach(() => {
+ window.localStorage.removeItem("codeg-plan-overlay-auto-expand")
+ })
+
it("renders nothing when entries are empty", () => {
const { container } = renderWithIntl(
@@ -117,6 +121,37 @@ describe("AgentPlanOverlay", () => {
expect(screen.getByText("Done A")).toBeInTheDocument()
})
+ it("stays collapsed when auto-expand is turned off", () => {
+ window.localStorage.setItem("codeg-plan-overlay-auto-expand", "0")
+ const noPlan = {
+ id: "live-off",
+ content: [{ type: "text", text: "working" }],
+ } as unknown as LiveMessage
+ const withPlan = {
+ id: "live-off",
+ content: [
+ { type: "text", text: "working" },
+ {
+ type: "plan",
+ entries: [
+ { content: "Build step", priority: "high", status: "in_progress" },
+ ],
+ },
+ ],
+ } as unknown as LiveMessage
+
+ const { rerender } = renderWithIntl(
+
+ )
+ rerender(
+
+
+
+ )
+ expect(screen.getByText("Plan 0/1")).toBeInTheDocument()
+ expect(screen.queryByText("Build step")).not.toBeInTheDocument()
+ })
+
it("auto-expands once when a plan is created live while streaming", () => {
// Streaming starts with no plan, then a plan_update lands. The overlay
// should pop open by itself the first time the plan appears.
diff --git a/src/components/chat/agent-plan-overlay.tsx b/src/components/chat/agent-plan-overlay.tsx
index 6a778dab0..fc62167b7 100644
--- a/src/components/chat/agent-plan-overlay.tsx
+++ b/src/components/chat/agent-plan-overlay.tsx
@@ -13,6 +13,7 @@ import { Button } from "@/components/ui/button"
import type { LiveMessage } from "@/contexts/acp-connections-context"
import type { PlanEntryInfo } from "@/lib/types"
import { cn } from "@/lib/utils"
+import { usePlanOverlayAutoExpand } from "@/hooks/use-plan-overlay-auto-expand"
import {
CheckCircle2Icon,
ChevronDownIcon,
@@ -70,6 +71,7 @@ export const AgentPlanOverlay = memo(function AgentPlanOverlay({
isStreaming = false,
}: AgentPlanOverlayProps) {
const t = useTranslations("Folder.chat.agentPlanOverlay")
+ const { autoExpand } = usePlanOverlayAutoExpand()
const liveEntries = useMemo(
() => getLatestPlanEntries(message ?? null),
[message]
@@ -114,6 +116,7 @@ export const AgentPlanOverlay = memo(function AgentPlanOverlay({
const [autoExpanded, setAutoExpanded] = useState(false)
if (prevLiveHadPlan !== liveHasPlan) {
const planCreatedLive =
+ autoExpand &&
prevLiveHadPlan === false &&
liveHasPlan &&
isStreaming &&
diff --git a/src/components/settings/appearance-settings.tsx b/src/components/settings/appearance-settings.tsx
index f09e69636..7abe1c57f 100644
--- a/src/components/settings/appearance-settings.tsx
+++ b/src/components/settings/appearance-settings.tsx
@@ -1,6 +1,6 @@
"use client"
-import { LayoutGrid, Monitor, Moon, Sun, Type } from "lucide-react"
+import { LayoutGrid, ListTodo, Monitor, Moon, Sun, Type } from "lucide-react"
import { useTranslations } from "next-intl"
import { useTheme } from "next-themes"
import { ScrollArea } from "@/components/ui/scroll-area"
@@ -30,6 +30,7 @@ import { PetManagerSection } from "./pet-manager-section"
import { FontSettingsSection } from "./font-settings-section"
import { WorkspaceBackgroundSection } from "./workspace-background-section"
import { CustomStyleSection } from "./custom-style-section"
+import { usePlanOverlayAutoExpand } from "@/hooks/use-plan-overlay-auto-expand"
type ThemeMode = "system" | "light" | "dark"
@@ -40,6 +41,8 @@ export function AppearanceSettings() {
const { zoomLevel, setZoomLevel } = useZoomLevel()
const { showWelcomeQuickActions, setShowWelcomeQuickActions } =
useWelcomeQuickActions()
+ const { autoExpand: autoExpandPlan, setAutoExpand: setAutoExpandPlan } =
+ usePlanOverlayAutoExpand()
const resolvedThemeLabel =
resolvedTheme === "dark"
@@ -238,6 +241,30 @@ export function AppearanceSettings() {
+ {/* ===== Conversation overlays ===== */}
+
+
+
+
+ {t("planOverlay.sectionTitle")}
+
+
+
+
+ {t("planOverlay.sectionDescription")}
+
+
+
+
+
{/* ===== Desktop Pet ===== */}
diff --git a/src/hooks/use-plan-overlay-auto-expand.ts b/src/hooks/use-plan-overlay-auto-expand.ts
new file mode 100644
index 000000000..7cd0dfbc8
--- /dev/null
+++ b/src/hooks/use-plan-overlay-auto-expand.ts
@@ -0,0 +1,38 @@
+"use client"
+
+import { useCallback, useEffect, useState } from "react"
+
+import {
+ PLAN_OVERLAY_AUTO_EXPAND_EVENT,
+ STORAGE_KEY_PLAN_OVERLAY_AUTO_EXPAND,
+ readPlanOverlayAutoExpand,
+ writePlanOverlayAutoExpand,
+} from "@/lib/plan-overlay-prefs"
+
+export function usePlanOverlayAutoExpand(): {
+ autoExpand: boolean
+ setAutoExpand: (on: boolean) => void
+} {
+ const [autoExpand, setAutoExpandState] = useState(readPlanOverlayAutoExpand)
+
+ useEffect(() => {
+ const sync = () => setAutoExpandState(readPlanOverlayAutoExpand())
+ const onStorage = (event: StorageEvent) => {
+ if (event.key && event.key !== STORAGE_KEY_PLAN_OVERLAY_AUTO_EXPAND) return
+ sync()
+ }
+ window.addEventListener("storage", onStorage)
+ window.addEventListener(PLAN_OVERLAY_AUTO_EXPAND_EVENT, sync)
+ return () => {
+ window.removeEventListener("storage", onStorage)
+ window.removeEventListener(PLAN_OVERLAY_AUTO_EXPAND_EVENT, sync)
+ }
+ }, [])
+
+ const setAutoExpand = useCallback((on: boolean) => {
+ setAutoExpandState(on)
+ writePlanOverlayAutoExpand(on)
+ }, [])
+
+ return { autoExpand, setAutoExpand }
+}
diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json
index bdf81590d..0d065964a 100644
--- a/src/i18n/messages/ar.json
+++ b/src/i18n/messages/ar.json
@@ -173,6 +173,11 @@
"sectionDescription": "بطاقات الاختصار «تطوير الكود / الأعمال المكتبية» التي تظهر أعلى مربع الإدخال في صفحة المحادثة الجديدة.",
"showQuickActions": "العرض في صفحة المحادثة الجديدة"
},
+ "planOverlay": {
+ "sectionTitle": "Agent plan",
+ "sectionDescription": "The floating plan card that appears on the left of a conversation when an agent writes a to-do list. You can always open it from the small chip.",
+ "autoExpand": "Open the plan card when an agent starts a plan"
+ },
"workspaceBackground": {
"sectionTitle": "خلفية مساحة العمل",
"sectionDescription": "عرض صورة خلف مساحة العمل بالكامل. يصبح الشريط الجانبي واللوحات شبه شفافة ومصنفرة لتظهر الصورة من خلالها، ويحافظ القناع على وضوح النص.",
diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json
index 0c40db5d3..424197d0d 100644
--- a/src/i18n/messages/de.json
+++ b/src/i18n/messages/de.json
@@ -173,6 +173,11 @@
"sectionDescription": "Die Shortcut-Karten „Code-Entwicklung / Büroarbeit“ über dem Eingabefeld auf der Seite für eine neue Konversation.",
"showQuickActions": "Auf der Seite für neue Konversationen anzeigen"
},
+ "planOverlay": {
+ "sectionTitle": "Agent plan",
+ "sectionDescription": "The floating plan card that appears on the left of a conversation when an agent writes a to-do list. You can always open it from the small chip.",
+ "autoExpand": "Open the plan card when an agent starts a plan"
+ },
"workspaceBackground": {
"sectionTitle": "Arbeitsbereich-Hintergrund",
"sectionDescription": "Zeigt ein Bild hinter dem gesamten Arbeitsbereich. Seitenleiste und Panels werden durchscheinend und mattiert, sodass das Bild durchscheint, und eine Maske sorgt für lesbaren Text.",
diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json
index 273af3aa0..2e8d75eb2 100644
--- a/src/i18n/messages/en.json
+++ b/src/i18n/messages/en.json
@@ -173,6 +173,11 @@
"sectionDescription": "The Code Development / Office Work shortcut cards shown above the composer on the new conversation page.",
"showQuickActions": "Show on the new conversation page"
},
+ "planOverlay": {
+ "sectionTitle": "Agent plan",
+ "sectionDescription": "The floating plan card that appears on the left of a conversation when an agent writes a to-do list. You can always open it from the small chip.",
+ "autoExpand": "Open the plan card when an agent starts a plan"
+ },
"workspaceBackground": {
"sectionTitle": "Workspace background",
"sectionDescription": "Show a picture behind the whole workspace. Sidebar and panels turn translucent and frosted so the image shows through, and a mask keeps text readable.",
diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json
index 9948070a4..35a482790 100644
--- a/src/i18n/messages/es.json
+++ b/src/i18n/messages/es.json
@@ -173,6 +173,11 @@
"sectionDescription": "Las tarjetas de acceso rápido «Desarrollo de código / Ofimática» que se muestran sobre el editor en la página de nueva conversación.",
"showQuickActions": "Mostrar en la página de nueva conversación"
},
+ "planOverlay": {
+ "sectionTitle": "Agent plan",
+ "sectionDescription": "The floating plan card that appears on the left of a conversation when an agent writes a to-do list. You can always open it from the small chip.",
+ "autoExpand": "Open the plan card when an agent starts a plan"
+ },
"workspaceBackground": {
"sectionTitle": "Fondo del espacio de trabajo",
"sectionDescription": "Muestra una imagen detrás de todo el espacio de trabajo. La barra lateral y los paneles se vuelven translúcidos y esmerilados para dejar ver la imagen, y una máscara mantiene el texto legible.",
diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json
index 9638508d6..577e63cf3 100644
--- a/src/i18n/messages/fr.json
+++ b/src/i18n/messages/fr.json
@@ -173,6 +173,11 @@
"sectionDescription": "Les cartes de raccourci « Développement / Bureautique » affichées au-dessus du champ de saisie sur la page de nouvelle conversation.",
"showQuickActions": "Afficher sur la page de nouvelle conversation"
},
+ "planOverlay": {
+ "sectionTitle": "Agent plan",
+ "sectionDescription": "The floating plan card that appears on the left of a conversation when an agent writes a to-do list. You can always open it from the small chip.",
+ "autoExpand": "Open the plan card when an agent starts a plan"
+ },
"workspaceBackground": {
"sectionTitle": "Arrière-plan de l'espace de travail",
"sectionDescription": "Affiche une image derrière tout l'espace de travail. La barre latérale et les panneaux deviennent translucides et dépolis pour laisser transparaître l'image, et un masque préserve la lisibilité du texte.",
diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json
index f44e8c88d..a93a3a5ee 100644
--- a/src/i18n/messages/ja.json
+++ b/src/i18n/messages/ja.json
@@ -173,6 +173,11 @@
"sectionDescription": "新しい会話ページで入力欄の上に表示される「コード開発 / 日常業務」のショートカットカードです。",
"showQuickActions": "新しい会話ページに表示する"
},
+ "planOverlay": {
+ "sectionTitle": "Agent plan",
+ "sectionDescription": "The floating plan card that appears on the left of a conversation when an agent writes a to-do list. You can always open it from the small chip.",
+ "autoExpand": "Open the plan card when an agent starts a plan"
+ },
"workspaceBackground": {
"sectionTitle": "ワークスペースの背景",
"sectionDescription": "ワークスペース全体の背後に画像を表示します。サイドバーやパネルは半透明のすりガラスになり画像が透けて見えます。マスクで文字の可読性を保ちます。",
diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json
index d8c404715..cad149bf9 100644
--- a/src/i18n/messages/ko.json
+++ b/src/i18n/messages/ko.json
@@ -173,6 +173,11 @@
"sectionDescription": "새 대화 페이지에서 입력창 위에 표시되는 '코드 개발 / 일상 업무' 바로가기 카드입니다.",
"showQuickActions": "새 대화 페이지에 표시"
},
+ "planOverlay": {
+ "sectionTitle": "Agent plan",
+ "sectionDescription": "The floating plan card that appears on the left of a conversation when an agent writes a to-do list. You can always open it from the small chip.",
+ "autoExpand": "Open the plan card when an agent starts a plan"
+ },
"workspaceBackground": {
"sectionTitle": "작업 공간 배경",
"sectionDescription": "작업 공간 전체 뒤에 이미지를 표시합니다. 사이드바와 패널이 반투명 유리 효과로 바뀌어 이미지가 비쳐 보이며, 마스크가 텍스트 가독성을 유지합니다.",
diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json
index 5b31f9ead..01638e6dd 100644
--- a/src/i18n/messages/pt.json
+++ b/src/i18n/messages/pt.json
@@ -173,6 +173,11 @@
"sectionDescription": "Os cartões de atalho «Desenvolvimento / Escritório» exibidos acima do campo de entrada na página de nova conversa.",
"showQuickActions": "Mostrar na página de nova conversa"
},
+ "planOverlay": {
+ "sectionTitle": "Agent plan",
+ "sectionDescription": "The floating plan card that appears on the left of a conversation when an agent writes a to-do list. You can always open it from the small chip.",
+ "autoExpand": "Open the plan card when an agent starts a plan"
+ },
"workspaceBackground": {
"sectionTitle": "Plano de fundo da área de trabalho",
"sectionDescription": "Mostra uma imagem atrás de toda a área de trabalho. A barra lateral e os painéis ficam translúcidos e foscos para deixar a imagem transparecer, e uma máscara mantém o texto legível.",
diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json
index f6a2638c1..eb3637e69 100644
--- a/src/i18n/messages/zh-CN.json
+++ b/src/i18n/messages/zh-CN.json
@@ -173,6 +173,11 @@
"sectionDescription": "新会话页面输入框上方显示的「代码开发 / 日常办公」快捷卡片区域。",
"showQuickActions": "在新会话页面显示"
},
+ "planOverlay": {
+ "sectionTitle": "Agent plan",
+ "sectionDescription": "The floating plan card that appears on the left of a conversation when an agent writes a to-do list. You can always open it from the small chip.",
+ "autoExpand": "Open the plan card when an agent starts a plan"
+ },
"workspaceBackground": {
"sectionTitle": "工作区背景",
"sectionDescription": "在整个工作区背后显示一张图片。侧栏与面板会变半透明并磨砂让图片透出,遮罩保证文字可读。",
diff --git a/src/i18n/messages/zh-TW.json b/src/i18n/messages/zh-TW.json
index 13e7b6eae..01e1bb3e5 100644
--- a/src/i18n/messages/zh-TW.json
+++ b/src/i18n/messages/zh-TW.json
@@ -173,6 +173,11 @@
"sectionDescription": "新會話頁面輸入框上方顯示的「程式開發 / 日常辦公」快捷卡片區域。",
"showQuickActions": "在新會話頁面顯示"
},
+ "planOverlay": {
+ "sectionTitle": "Agent plan",
+ "sectionDescription": "The floating plan card that appears on the left of a conversation when an agent writes a to-do list. You can always open it from the small chip.",
+ "autoExpand": "Open the plan card when an agent starts a plan"
+ },
"workspaceBackground": {
"sectionTitle": "工作區背景",
"sectionDescription": "在整個工作區背後顯示一張圖片。側邊欄與面板會變半透明並磨砂讓圖片透出,遮罩確保文字可讀。",
diff --git a/src/lib/plan-overlay-prefs.test.ts b/src/lib/plan-overlay-prefs.test.ts
new file mode 100644
index 000000000..e0695358f
--- /dev/null
+++ b/src/lib/plan-overlay-prefs.test.ts
@@ -0,0 +1,26 @@
+import { afterEach, describe, expect, it } from "vitest"
+
+import {
+ DEFAULT_PLAN_OVERLAY_AUTO_EXPAND,
+ STORAGE_KEY_PLAN_OVERLAY_AUTO_EXPAND,
+ readPlanOverlayAutoExpand,
+ writePlanOverlayAutoExpand,
+} from "./plan-overlay-prefs"
+
+describe("plan overlay auto-expand preference", () => {
+ afterEach(() => {
+ window.localStorage.removeItem(STORAGE_KEY_PLAN_OVERLAY_AUTO_EXPAND)
+ })
+
+ it("defaults to auto-expand (historical behavior)", () => {
+ expect(readPlanOverlayAutoExpand()).toBe(DEFAULT_PLAN_OVERLAY_AUTO_EXPAND)
+ expect(readPlanOverlayAutoExpand()).toBe(true)
+ })
+
+ it("round-trips off and on", () => {
+ writePlanOverlayAutoExpand(false)
+ expect(readPlanOverlayAutoExpand()).toBe(false)
+ writePlanOverlayAutoExpand(true)
+ expect(readPlanOverlayAutoExpand()).toBe(true)
+ })
+})
diff --git a/src/lib/plan-overlay-prefs.ts b/src/lib/plan-overlay-prefs.ts
new file mode 100644
index 000000000..b6c0ddff2
--- /dev/null
+++ b/src/lib/plan-overlay-prefs.ts
@@ -0,0 +1,38 @@
+/**
+ * Per-device preference for the floating Agent Plan overlay.
+ *
+ * When a plan is created mid-turn, the overlay auto-expands into the full
+ * card. That is useful the first few times and noisy once you already know
+ * the chip is there. Default stays the historical auto-expand.
+ */
+
+export const STORAGE_KEY_PLAN_OVERLAY_AUTO_EXPAND =
+ "codeg-plan-overlay-auto-expand"
+export const PLAN_OVERLAY_AUTO_EXPAND_EVENT =
+ "codeg:plan-overlay-auto-expand"
+export const DEFAULT_PLAN_OVERLAY_AUTO_EXPAND = true
+
+export function readPlanOverlayAutoExpand(): boolean {
+ if (typeof window === "undefined") return DEFAULT_PLAN_OVERLAY_AUTO_EXPAND
+ try {
+ const raw = window.localStorage.getItem(STORAGE_KEY_PLAN_OVERLAY_AUTO_EXPAND)
+ if (raw === "0") return false
+ if (raw === "1") return true
+ return DEFAULT_PLAN_OVERLAY_AUTO_EXPAND
+ } catch {
+ return DEFAULT_PLAN_OVERLAY_AUTO_EXPAND
+ }
+}
+
+export function writePlanOverlayAutoExpand(on: boolean): void {
+ if (typeof window === "undefined") return
+ try {
+ window.localStorage.setItem(
+ STORAGE_KEY_PLAN_OVERLAY_AUTO_EXPAND,
+ on ? "1" : "0"
+ )
+ window.dispatchEvent(new Event(PLAN_OVERLAY_AUTO_EXPAND_EVENT))
+ } catch {
+ // Privacy mode / locked storage: the in-memory hook still updates.
+ }
+}
From 341245e24d98bda78fcf627bb959291e234506cf Mon Sep 17 00:00:00 2001
From: Adam Dalloul <47503782+Adam-Dalloul@users.noreply.github.com>
Date: Sun, 16 Aug 2026 10:03:11 -0700
Subject: [PATCH 2/2] chore: format after rebase onto main
---
src/hooks/use-plan-overlay-auto-expand.ts | 3 ++-
src/lib/plan-overlay-prefs.ts | 7 ++++---
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/hooks/use-plan-overlay-auto-expand.ts b/src/hooks/use-plan-overlay-auto-expand.ts
index 7cd0dfbc8..69dc1c3fc 100644
--- a/src/hooks/use-plan-overlay-auto-expand.ts
+++ b/src/hooks/use-plan-overlay-auto-expand.ts
@@ -18,7 +18,8 @@ export function usePlanOverlayAutoExpand(): {
useEffect(() => {
const sync = () => setAutoExpandState(readPlanOverlayAutoExpand())
const onStorage = (event: StorageEvent) => {
- if (event.key && event.key !== STORAGE_KEY_PLAN_OVERLAY_AUTO_EXPAND) return
+ if (event.key && event.key !== STORAGE_KEY_PLAN_OVERLAY_AUTO_EXPAND)
+ return
sync()
}
window.addEventListener("storage", onStorage)
diff --git a/src/lib/plan-overlay-prefs.ts b/src/lib/plan-overlay-prefs.ts
index b6c0ddff2..387f59aa0 100644
--- a/src/lib/plan-overlay-prefs.ts
+++ b/src/lib/plan-overlay-prefs.ts
@@ -8,14 +8,15 @@
export const STORAGE_KEY_PLAN_OVERLAY_AUTO_EXPAND =
"codeg-plan-overlay-auto-expand"
-export const PLAN_OVERLAY_AUTO_EXPAND_EVENT =
- "codeg:plan-overlay-auto-expand"
+export const PLAN_OVERLAY_AUTO_EXPAND_EVENT = "codeg:plan-overlay-auto-expand"
export const DEFAULT_PLAN_OVERLAY_AUTO_EXPAND = true
export function readPlanOverlayAutoExpand(): boolean {
if (typeof window === "undefined") return DEFAULT_PLAN_OVERLAY_AUTO_EXPAND
try {
- const raw = window.localStorage.getItem(STORAGE_KEY_PLAN_OVERLAY_AUTO_EXPAND)
+ const raw = window.localStorage.getItem(
+ STORAGE_KEY_PLAN_OVERLAY_AUTO_EXPAND
+ )
if (raw === "0") return false
if (raw === "1") return true
return DEFAULT_PLAN_OVERLAY_AUTO_EXPAND