From 8176bafc555e562ade48a675dffa3f38751ed8c9 Mon Sep 17 00:00:00 2001
From: Adam <2363879+adamdotdevin@users.noreply.github.com>
Date: Mon, 2 Mar 2026 10:50:50 -0600
Subject: chore(app): solidjs refactoring (#13399)

---
 packages/app/src/context/layout.tsx | 82 ++++++++++++++++++++++++++++++++++---
 1 file changed, 77 insertions(+), 5 deletions(-)

(limited to 'packages/app/src/context/layout.tsx')

diff --git a/packages/app/src/context/layout.tsx b/packages/app/src/context/layout.tsx
index 71f0294e7..5199e5a26 100644
--- a/packages/app/src/context/layout.tsx
+++ b/packages/app/src/context/layout.tsx
@@ -7,8 +7,10 @@ import { useServer } from "./server"
 import { usePlatform } from "./platform"
 import { Project } from "@opencode-ai/sdk/v2"
 import { Persist, persisted, removePersisted } from "@/utils/persist"
+import { decode64 } from "@/utils/base64"
 import { same } from "@/utils/same"
 import { createScrollPersistence, type SessionScroll } from "./layout-scroll"
+import { createPathHelpers } from "./file/path"
 
 const AVATAR_COLOR_KEYS = ["pink", "mint", "orange", "purple", "cyan", "lime"] as const
 const DEFAULT_PANEL_WIDTH = 344
@@ -96,6 +98,38 @@ function nextSessionTabsForOpen(current: SessionTabs | undefined, tab: string):
   return { all, active: tab }
 }
 
+const sessionPath = (key: string) => {
+  const dir = key.split("/")[0]
+  if (!dir) return
+  const root = decode64(dir)
+  if (!root) return
+  return createPathHelpers(() => root)
+}
+
+const normalizeSessionTab = (path: ReturnType<typeof createPathHelpers> | undefined, tab: string) => {
+  if (!tab.startsWith("file://")) return tab
+  if (!path) return tab
+  return path.tab(tab)
+}
+
+const normalizeSessionTabList = (path: ReturnType<typeof createPathHelpers> | undefined, all: string[]) => {
+  const seen = new Set<string>()
+  return all.flatMap((tab) => {
+    const value = normalizeSessionTab(path, tab)
+    if (seen.has(value)) return []
+    seen.add(value)
+    return [value]
+  })
+}
+
+const normalizeStoredSessionTabs = (key: string, tabs: SessionTabs) => {
+  const path = sessionPath(key)
+  return {
+    all: normalizeSessionTabList(path, tabs.all),
+    active: tabs.active ? normalizeSessionTab(path, tabs.active) : tabs.active,
+  }
+}
+
 export const { use: useLayout, provider: LayoutProvider } = createSimpleContext({
   name: "Layout",
   init: () => {
@@ -147,12 +181,46 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
         }
       })()
 
-      if (migratedSidebar === sidebar && migratedReview === review && migratedFileTree === fileTree) return value
+      const sessionTabs = value.sessionTabs
+      const migratedSessionTabs = (() => {
+        if (!isRecord(sessionTabs)) return sessionTabs
+
+        let changed = false
+        const next = Object.fromEntries(
+          Object.entries(sessionTabs).map(([key, tabs]) => {
+            if (!isRecord(tabs) || !Array.isArray(tabs.all)) return [key, tabs]
+
+            const current = {
+              all: tabs.all.filter((tab): tab is string => typeof tab === "string"),
+              active: typeof tabs.active === "string" ? tabs.active : undefined,
+            }
+            const normalized = normalizeStoredSessionTabs(key, current)
+            if (current.all.length !== tabs.all.length) changed = true
+            if (!same(current.all, normalized.all) || current.active !== normalized.active) changed = true
+            if (tabs.active !== undefined && typeof tabs.active !== "string") changed = true
+            return [key, normalized]
+          }),
+        )
+
+        if (!changed) return sessionTabs
+        return next
+      })()
+
+      if (
+        migratedSidebar === sidebar &&
+        migratedReview === review &&
+        migratedFileTree === fileTree &&
+        migratedSessionTabs === sessionTabs
+      ) {
+        return value
+      }
+
       return {
         ...value,
         sidebar: migratedSidebar,
         review: migratedReview,
         fileTree: migratedFileTree,
+        sessionTabs: migratedSessionTabs,
       }
     }
 
@@ -745,22 +813,26 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
       },
       tabs(sessionKey: string | Accessor<string>) {
         const key = createSessionKeyReader(sessionKey, ensureKey)
+        const path = createMemo(() => sessionPath(key()))
         const tabs = createMemo(() => store.sessionTabs[key()] ?? { all: [] })
+        const normalize = (tab: string) => normalizeSessionTab(path(), tab)
+        const normalizeAll = (all: string[]) => normalizeSessionTabList(path(), all)
         return {
           tabs,
           active: createMemo(() => tabs().active),
           all: createMemo(() => tabs().all.filter((tab) => tab !== "review")),
           setActive(tab: string | undefined) {
             const session = key()
+            const next = tab ? normalize(tab) : tab
             if (!store.sessionTabs[session]) {
-              setStore("sessionTabs", session, { all: [], active: tab })
+              setStore("sessionTabs", session, { all: [], active: next })
             } else {
-              setStore("sessionTabs", session, "active", tab)
+              setStore("sessionTabs", session, "active", next)
             }
           },
           setAll(all: string[]) {
             const session = key()
-            const next = all.filter((tab) => tab !== "review")
+            const next = normalizeAll(all).filter((tab) => tab !== "review")
             if (!store.sessionTabs[session]) {
               setStore("sessionTabs", session, { all: next, active: undefined })
             } else {
@@ -769,7 +841,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
           },
           async open(tab: string) {
             const session = key()
-            const next = nextSessionTabsForOpen(store.sessionTabs[session], tab)
+            const next = nextSessionTabsForOpen(store.sessionTabs[session], normalize(tab))
             setStore("sessionTabs", session, next)
           },
           close(tab: string) {
-- 
cgit v1.2.3

