From 67a95c3cc8de5dc8e71f8af8efbaca4e7efdb4d6 Mon Sep 17 00:00:00 2001
From: Adam <2363879+adamdotdevin@users.noreply.github.com>
Date: Wed, 10 Dec 2025 03:05:27 -0600
Subject: wip(desktop): progress

---
 packages/desktop/src/context/layout.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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

diff --git a/packages/desktop/src/context/layout.tsx b/packages/desktop/src/context/layout.tsx
index b7d1fabb5..05a47c4eb 100644
--- a/packages/desktop/src/context/layout.tsx
+++ b/packages/desktop/src/context/layout.tsx
@@ -66,7 +66,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
         open(directory: string) {
           if (store.projects.find((x) => x.worktree === directory)) return
           loadProjectSessions(directory)
-          setStore("projects", (x) => [...x, { worktree: directory, expanded: true }])
+          setStore("projects", (x) => [{ worktree: directory, expanded: true }, ...x])
         },
         close(directory: string) {
           setStore("projects", (x) => x.filter((x) => x.worktree !== directory))
-- 
cgit v1.2.3


From 91d743ef9a5c346fe17bb857db68dca92a6e9ba1 Mon Sep 17 00:00:00 2001
From: Adam <2363879+adamdotdevin@users.noreply.github.com>
Date: Wed, 10 Dec 2025 12:48:08 -0600
Subject: wip(desktop): progress

---
 packages/desktop/src/components/prompt-input.tsx |  5 ++
 packages/desktop/src/context/global-sync.tsx     | 73 +++++++-----------------
 packages/desktop/src/context/layout.tsx          | 67 +++++++++++++++++-----
 packages/desktop/src/pages/layout.tsx            | 38 ++++++++++++
 packages/tauri/src-tauri/Cargo.lock              | 34 +++++------
 packages/tauri/src-tauri/Cargo.toml              |  2 +-
 packages/ui/src/components/avatar.tsx            |  7 ++-
 packages/ui/src/components/button.css            | 18 ++++--
 packages/ui/src/components/select-dialog.css     |  1 -
 packages/ui/src/components/select-dialog.tsx     |  6 +-
 10 files changed, 156 insertions(+), 95 deletions(-)

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

diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx
index 8579647da..97d27ee1e 100644
--- a/packages/desktop/src/components/prompt-input.tsx
+++ b/packages/desktop/src/components/prompt-input.tsx
@@ -483,6 +483,11 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
                   <Icon name="chevron-down" size="small" />
                 </Button>
               }
+              actions={
+                <Button class="h-7 -my-1 text-14-medium" icon="plus-small" tabIndex={-1}>
+                  Connect provider
+                </Button>
+              }
             >
               {(i) => (
                 <div class="w-full flex items-center gap-x-2.5">
diff --git a/packages/desktop/src/context/global-sync.tsx b/packages/desktop/src/context/global-sync.tsx
index 58fc8c9cd..3e2b6bf7d 100644
--- a/packages/desktop/src/context/global-sync.tsx
+++ b/packages/desktop/src/context/global-sync.tsx
@@ -18,41 +18,9 @@ import { Binary } from "@opencode-ai/util/binary"
 import { createSimpleContext } from "@opencode-ai/ui/context"
 import { useGlobalSDK } from "./global-sdk"
 
-const PASTEL_COLORS = [
-  "#FCEAFD", // pastel pink
-  "#FFDFBA", // pastel peach
-  "#FFFFBA", // pastel yellow
-  "#BAFFC9", // pastel green
-  "#EAF6FD", // pastel blue
-  "#EFEAFD", // pastel lavender
-  "#FEC8D8", // pastel rose
-  "#D4F0F0", // pastel cyan
-  "#FDF0EA", // pastel coral
-  "#C1E1C1", // pastel mint
-]
-
-function pickAvailableColor(usedColors: Set<string>) {
-  const available = PASTEL_COLORS.filter((c) => !usedColors.has(c))
-  if (available.length === 0) return PASTEL_COLORS[Math.floor(Math.random() * PASTEL_COLORS.length)]
-  return available[Math.floor(Math.random() * available.length)]
-}
-
-async function ensureProjectColor(
-  project: Project,
-  sdk: ReturnType<typeof useGlobalSDK>,
-  usedColors: Set<string>,
-): Promise<Project> {
-  if (project.icon?.color) return project
-  const color = pickAvailableColor(usedColors)
-  usedColors.add(color)
-  const updated = { ...project, icon: { ...project.icon, color } }
-  sdk.client.project.update({ projectID: project.id, icon: { color } })
-  return updated
-}
-
 type State = {
   ready: boolean
-  provider: Provider[]
+  // provider: Provider[]
   agent: Agent[]
   project: string
   config: Config
@@ -84,10 +52,12 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple
     const [globalStore, setGlobalStore] = createStore<{
       ready: boolean
       projects: Project[]
+      providers: Provider[]
       children: Record<string, State>
     }>({
       ready: false,
       projects: [],
+      providers: [],
       children: {},
     })
 
@@ -100,7 +70,7 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple
           path: { state: "", config: "", worktree: "", directory: "", home: "" },
           ready: false,
           agent: [],
-          provider: [],
+          // provider: [],
           session: [],
           session_status: {},
           session_diff: {},
@@ -124,20 +94,17 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple
       if (directory === "global") {
         switch (event.type) {
           case "project.updated": {
-            const usedColors = new Set(globalStore.projects.map((p) => p.icon?.color).filter(Boolean) as string[])
-            ensureProjectColor(event.properties, sdk, usedColors).then((project) => {
-              const result = Binary.search(globalStore.projects, project.id, (s) => s.id)
-              if (result.found) {
-                setGlobalStore("projects", result.index, reconcile(project))
-                return
-              }
-              setGlobalStore(
-                "projects",
-                produce((draft) => {
-                  draft.splice(result.index, 0, project)
-                }),
-              )
-            })
+            const result = Binary.search(globalStore.projects, event.properties.id, (s) => s.id)
+            if (result.found) {
+              setGlobalStore("projects", result.index, reconcile(event.properties))
+              return
+            }
+            setGlobalStore(
+              "projects",
+              produce((draft) => {
+                draft.splice(result.index, 0, event.properties)
+              }),
+            )
             break
           }
         }
@@ -216,14 +183,16 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple
 
     Promise.all([
       sdk.client.project.list().then(async (x) => {
-        const filtered = x.data!.filter((p) => !p.worktree.includes("opencode-test") && p.vcs)
-        const usedColors = new Set(filtered.map((p) => p.icon?.color).filter(Boolean) as string[])
-        const projects = await Promise.all(filtered.map((p) => ensureProjectColor(p, sdk, usedColors)))
         setGlobalStore(
           "projects",
-          projects.sort((a, b) => a.id.localeCompare(b.id)),
+          x
+            .data!.filter((p) => !p.worktree.includes("opencode-test") && p.vcs)
+            .sort((a, b) => a.id.localeCompare(b.id)),
         )
       }),
+      sdk.client.provider.list().then((x) => {
+        setGlobalStore("providers", x.data ?? [])
+      }),
     ]).then(() => setGlobalStore("ready", true))
 
     return {
diff --git a/packages/desktop/src/context/layout.tsx b/packages/desktop/src/context/layout.tsx
index 05a47c4eb..13c4679d6 100644
--- a/packages/desktop/src/context/layout.tsx
+++ b/packages/desktop/src/context/layout.tsx
@@ -4,6 +4,20 @@ import { createSimpleContext } from "@opencode-ai/ui/context"
 import { makePersisted } from "@solid-primitives/storage"
 import { useGlobalSync } from "./global-sync"
 import { useGlobalSDK } from "./global-sdk"
+import { Project } from "@opencode-ai/sdk/v2"
+
+const PASTEL_COLORS = [
+  "#FCEAFD", // pastel pink
+  "#FFDFBA", // pastel peach
+  "#FFFFBA", // pastel yellow
+  "#BAFFC9", // pastel green
+  "#EAF6FD", // pastel blue
+  "#EFEAFD", // pastel lavender
+  "#FEC8D8", // pastel rose
+  "#D4F0F0", // pastel cyan
+  "#FDF0EA", // pastel coral
+  "#C1E1C1", // pastel mint
+]
 
 export const { use: useLayout, provider: LayoutProvider } = createSimpleContext({
   name: "Layout",
@@ -30,6 +44,42 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
       },
     )
 
+    function pickAvailableColor() {
+      const available = PASTEL_COLORS.filter((c) => !colors().has(c))
+      if (available.length === 0) return PASTEL_COLORS[Math.floor(Math.random() * PASTEL_COLORS.length)]
+      return available[Math.floor(Math.random() * available.length)]
+    }
+
+    function enrich(project: { worktree: string; expanded: boolean }) {
+      const metadata = globalSync.data.projects.find((x) => x.worktree === project.worktree)
+      if (!metadata) return []
+      return [
+        {
+          ...project,
+          ...metadata,
+        },
+      ]
+    }
+
+    function colorize(project: Project & { expanded: boolean }) {
+      if (project.icon?.color) return project
+      const color = pickAvailableColor()
+      project.icon = { ...project.icon, color }
+      globalSdk.client.project.update({ projectID: project.id, icon: { color } })
+      return project
+    }
+
+    const enriched = createMemo(() => store.projects.flatMap(enrich))
+    const list = createMemo(() => enriched().flatMap(colorize))
+    const colors = createMemo(
+      () =>
+        new Set(
+          list()
+            .map((p) => p.icon?.color)
+            .filter(Boolean),
+        ),
+    )
+
     async function loadProjectSessions(directory: string) {
       const [, setStore] = globalSync.child(directory)
       globalSdk.client.session.list({ directory }).then((x) => {
@@ -43,26 +93,15 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
 
     onMount(() => {
       Promise.all(
-        store.projects.map(({ worktree }) => {
-          return loadProjectSessions(worktree)
+        store.projects.map((project) => {
+          return loadProjectSessions(project.worktree)
         }),
       )
     })
 
-    function enrich(project: { worktree: string; expanded: boolean }) {
-      const metadata = globalSync.data.projects.find((x) => x.worktree === project.worktree)
-      if (!metadata) return []
-      return [
-        {
-          ...project,
-          ...metadata,
-        },
-      ]
-    }
-
     return {
       projects: {
-        list: createMemo(() => store.projects.flatMap(enrich)),
+        list,
         open(directory: string) {
           if (store.projects.find((x) => x.worktree === directory)) return
           loadProjectSessions(directory)
diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx
index 4a17d01bd..3e0094756 100644
--- a/packages/desktop/src/pages/layout.tsx
+++ b/packages/desktop/src/pages/layout.tsx
@@ -29,6 +29,8 @@ import {
   useDragDropContext,
 } from "@thisbeyond/solid-dnd"
 import type { DragEvent, Transformer } from "@thisbeyond/solid-dnd"
+import { SelectDialog } from "@opencode-ai/ui/select-dialog"
+import { Tag } from "@opencode-ai/ui/tag"
 
 export default function Layout(props: ParentProps) {
   const [store, setStore] = createStore({
@@ -44,11 +46,16 @@ export default function Layout(props: ParentProps) {
   const currentDirectory = createMemo(() => base64Decode(params.dir ?? ""))
   const sessions = createMemo(() => globalSync.child(currentDirectory())[0].session ?? [])
   const currentSession = createMemo(() => sessions().find((s) => s.id === params.id))
+  const providers = createMemo(() => globalSync.data.providers)
   const hasProviders = createMemo(() => {
     const [projectStore] = globalSync.child(currentDirectory())
     return projectStore.provider.filter((p) => p.id !== "opencode").length > 0
   })
 
+  createEffect(() => {
+    console.log(providers())
+  })
+
   function navigateToProject(directory: string | undefined) {
     if (!directory) return
     const lastSession = store.lastSession[directory]
@@ -550,6 +557,37 @@ export default function Layout(props: ParentProps) {
           </div>
         </div>
         <main class="size-full overflow-x-hidden flex flex-col items-start">{props.children}</main>
+        <Show when={true}>
+          <SelectDialog
+            defaultOpen
+            title="Connect provider"
+            placeholder="Search providers"
+            key={(x) => x?.id}
+            items={providers()}
+            // current={local.model.current()}
+            filterKeys={["provider.name", "name", "id"]}
+            // groupBy={(x) => (local.model.recent().includes(x) ? "Recent" : x.provider.name)}
+            // groupBy={(x) => x.provider.name}
+            onSelect={(x) =>
+              // local.model.set(x ? { modelID: x.id, providerID: x.provider.id } : undefined, { recent: true })
+              {
+                return
+              }
+            }
+          >
+            {(i) => (
+              <div class="w-full flex items-center gap-x-2.5">
+                <span>{i.name}</span>
+                <Show when={!i.cost || i.cost?.input === 0}>
+                  <Tag>Free</Tag>
+                </Show>
+                <Show when={i.latest}>
+                  <Tag>Latest</Tag>
+                </Show>
+              </div>
+            )}
+          </SelectDialog>
+        </Show>
       </div>
     </div>
   )
diff --git a/packages/tauri/src-tauri/Cargo.lock b/packages/tauri/src-tauri/Cargo.lock
index 57d463355..f2e77a1e8 100644
--- a/packages/tauri/src-tauri/Cargo.lock
+++ b/packages/tauri/src-tauri/Cargo.lock
@@ -2,6 +2,23 @@
 # It is not intended for manual editing.
 version = 4
 
+[[package]]
+name = "OpenCode"
+version = "0.0.0"
+dependencies = [
+ "listeners",
+ "serde",
+ "serde_json",
+ "tauri",
+ "tauri-build",
+ "tauri-plugin-dialog",
+ "tauri-plugin-opener",
+ "tauri-plugin-process",
+ "tauri-plugin-shell",
+ "tauri-plugin-updater",
+ "tokio",
+]
+
 [[package]]
 name = "adler2"
 version = "2.0.1"
@@ -2500,23 +2517,6 @@ dependencies = [
  "pathdiff",
 ]
 
-[[package]]
-name = "opencode-desktop"
-version = "0.0.0"
-dependencies = [
- "listeners",
- "serde",
- "serde_json",
- "tauri",
- "tauri-build",
- "tauri-plugin-dialog",
- "tauri-plugin-opener",
- "tauri-plugin-process",
- "tauri-plugin-shell",
- "tauri-plugin-updater",
- "tokio",
-]
-
 [[package]]
 name = "option-ext"
 version = "0.2.0"
diff --git a/packages/tauri/src-tauri/Cargo.toml b/packages/tauri/src-tauri/Cargo.toml
index c6b0e409b..3d7bf654d 100644
--- a/packages/tauri/src-tauri/Cargo.toml
+++ b/packages/tauri/src-tauri/Cargo.toml
@@ -1,5 +1,5 @@
 [package]
-name = "opencode-desktop"
+name = "OpenCode"
 version = "0.0.0"
 description = "A Tauri App"
 authors = ["you"]
diff --git a/packages/ui/src/components/avatar.tsx b/packages/ui/src/components/avatar.tsx
index 1ff3008ee..fb5798b08 100644
--- a/packages/ui/src/components/avatar.tsx
+++ b/packages/ui/src/components/avatar.tsx
@@ -9,22 +9,23 @@ export interface AvatarProps extends ComponentProps<"div"> {
 
 export function Avatar(props: AvatarProps) {
   const [split, rest] = splitProps(props, ["fallback", "src", "background", "size", "class", "classList", "style"])
+  const src = split.src // did this so i can zero it out to test fallback
   return (
     <div
       {...rest}
       data-component="avatar"
       data-size={split.size || "normal"}
-      data-has-image={split.src ? "" : undefined}
+      data-has-image={src ? "" : undefined}
       classList={{
         ...(split.classList ?? {}),
         [split.class ?? ""]: !!split.class,
       }}
       style={{
         ...(typeof split.style === "object" ? split.style : {}),
-        ...(!split.src && split.background ? { "--avatar-bg": split.background } : {}),
+        ...(!src && split.background ? { "--avatar-bg": split.background } : {}),
       }}
     >
-      <Show when={split.src} fallback={split.fallback?.[0]}>
+      <Show when={src} fallback={split.fallback?.[0]}>
         {(src) => <img src={src()} draggable={false} class="size-full object-cover" />}
       </Show>
     </div>
diff --git a/packages/ui/src/components/button.css b/packages/ui/src/components/button.css
index 192c7b60c..f95317028 100644
--- a/packages/ui/src/components/button.css
+++ b/packages/ui/src/components/button.css
@@ -102,12 +102,20 @@
     height: 24px;
     padding: 0 6px;
     &[data-icon] {
-      padding: 0 8px 0 6px;
+      padding: 0 12px 0 4px;
     }
 
     font-size: var(--font-size-small);
     line-height: var(--line-height-large);
     gap: 6px;
+
+    /* text-12-medium */
+    font-family: var(--font-family-sans);
+    font-size: var(--font-size-small);
+    font-style: normal;
+    font-weight: var(--font-weight-medium);
+    line-height: var(--line-height-large); /* 166.667% */
+    letter-spacing: var(--letter-spacing-normal);
   }
 
   &[data-size="large"] {
@@ -115,17 +123,17 @@
     padding: 0 8px;
 
     &[data-icon] {
-      padding: 0 8px 0 6px;
+      padding: 0 12px 0 8px;
     }
 
     gap: 8px;
 
-    /* text-12-medium */
+    /* text-14-medium */
     font-family: var(--font-family-sans);
-    font-size: var(--font-size-small);
+    font-size: 14px;
     font-style: normal;
     font-weight: var(--font-weight-medium);
-    line-height: var(--line-height-large); /* 166.667% */
+    line-height: var(--line-height-large); /* 142.857% */
     letter-spacing: var(--letter-spacing-normal);
   }
 
diff --git a/packages/ui/src/components/select-dialog.css b/packages/ui/src/components/select-dialog.css
index 206eade0d..cc834f795 100644
--- a/packages/ui/src/components/select-dialog.css
+++ b/packages/ui/src/components/select-dialog.css
@@ -75,7 +75,6 @@
     position: relative;
     display: flex;
     flex-direction: column;
-    gap: 4px;
 
     [data-slot="select-dialog-header"] {
       display: flex;
diff --git a/packages/ui/src/components/select-dialog.tsx b/packages/ui/src/components/select-dialog.tsx
index 695791aad..b93993ad4 100644
--- a/packages/ui/src/components/select-dialog.tsx
+++ b/packages/ui/src/components/select-dialog.tsx
@@ -15,6 +15,7 @@ interface SelectDialogProps<T>
   children: (item: T) => JSX.Element
   onSelect?: (value: T | undefined) => void
   onKeyEvent?: (event: KeyboardEvent, item: T | undefined) => void
+  actions?: JSX.Element
 }
 
 export function SelectDialog<T>(props: SelectDialogProps<T>) {
@@ -98,7 +99,8 @@ export function SelectDialog<T>(props: SelectDialogProps<T>) {
     <Dialog modal {...dialog} onOpenChange={handleOpenChange}>
       <Dialog.Header>
         <Dialog.Title>{others.title}</Dialog.Title>
-        <Dialog.CloseButton ref={closeButton} tabIndex={-1} />
+        <Show when={others.actions}>{others.actions}</Show>
+        <Dialog.CloseButton ref={closeButton} tabIndex={-1} style={{ display: others.actions ? "none" : undefined }} />
       </Dialog.Header>
       <div data-slot="select-dialog-content">
         <div data-component="select-dialog-input">
@@ -136,7 +138,7 @@ export function SelectDialog<T>(props: SelectDialogProps<T>) {
             fallback={
               <div data-slot="select-dialog-empty-state">
                 <div data-slot="select-dialog-message">
-                  {props.emptyMessage ?? "No search results"} for{" "}
+                  {props.emptyMessage ?? "No results"} for{" "}
                   <span data-slot="select-dialog-filter">&quot;{filter()}&quot;</span>
                 </div>
               </div>
-- 
cgit v1.2.3


From 190fa4c87aa2b3f954a419f716add1fc29e4011e Mon Sep 17 00:00:00 2001
From: Adam <2363879+adamdotdevin@users.noreply.github.com>
Date: Wed, 10 Dec 2025 14:48:08 -0600
Subject: wip(desktop): progress

---
 packages/desktop/src/components/prompt-input.tsx   | 111 ++++++++++++---------
 packages/desktop/src/context/global-sync.tsx       |  26 ++---
 packages/desktop/src/context/layout.tsx            |  20 +++-
 packages/desktop/src/context/local.tsx             |  38 +++----
 packages/desktop/src/context/session.tsx           |   2 +-
 packages/desktop/src/context/sync.tsx              |   6 +-
 packages/desktop/src/pages/home.tsx                |   4 +-
 packages/desktop/src/pages/layout.tsx              |  90 +++++++++++------
 packages/enterprise/src/routes/share/[shareID].tsx |   2 +-
 packages/ui/src/components/provider-icon.tsx       |   6 +-
 packages/ui/src/components/select-dialog.css       |  12 ++-
 packages/ui/src/components/select-dialog.tsx       |  10 +-
 12 files changed, 201 insertions(+), 126 deletions(-)

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

diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx
index 97d27ee1e..985dbae8e 100644
--- a/packages/desktop/src/components/prompt-input.tsx
+++ b/packages/desktop/src/components/prompt-input.tsx
@@ -16,6 +16,7 @@ import { IconButton } from "@opencode-ai/ui/icon-button"
 import { Select } from "@opencode-ai/ui/select"
 import { Tag } from "@opencode-ai/ui/tag"
 import { getDirectory, getFilename } from "@opencode-ai/util/path"
+import { useLayout } from "@/context/layout"
 
 interface PromptInputProps {
   class?: string
@@ -56,6 +57,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
   const sync = useSync()
   const local = useLocal()
   const session = useSession()
+  const layout = useLayout()
   let editorRef!: HTMLDivElement
 
   const [store, setStore] = createStore<{
@@ -453,54 +455,67 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
               class="capitalize"
               variant="ghost"
             />
-            <SelectDialog
-              title="Select model"
-              placeholder="Search models"
-              emptyMessage="No model results"
-              key={(x) => `${x.provider.id}:${x.id}`}
-              items={local.model.list()}
-              current={local.model.current()}
-              filterKeys={["provider.name", "name", "id"]}
-              // groupBy={(x) => (local.model.recent().includes(x) ? "Recent" : x.provider.name)}
-              groupBy={(x) => x.provider.name}
-              sortGroupsBy={(a, b) => {
-                const order = ["opencode", "anthropic", "github-copilot", "openai", "google", "openrouter", "vercel"]
-                if (a.category === "Recent" && b.category !== "Recent") return -1
-                if (b.category === "Recent" && a.category !== "Recent") return 1
-                const aProvider = a.items[0].provider.id
-                const bProvider = b.items[0].provider.id
-                if (order.includes(aProvider) && !order.includes(bProvider)) return -1
-                if (!order.includes(aProvider) && order.includes(bProvider)) return 1
-                return order.indexOf(aProvider) - order.indexOf(bProvider)
-              }}
-              onSelect={(x) =>
-                local.model.set(x ? { modelID: x.id, providerID: x.provider.id } : undefined, { recent: true })
-              }
-              trigger={
-                <Button as="div" variant="ghost">
-                  {local.model.current()?.name ?? "Select model"}
-                  <span class="ml-0.5 text-text-weak text-12-regular">{local.model.current()?.provider.name}</span>
-                  <Icon name="chevron-down" size="small" />
-                </Button>
-              }
-              actions={
-                <Button class="h-7 -my-1 text-14-medium" icon="plus-small" tabIndex={-1}>
-                  Connect provider
-                </Button>
-              }
-            >
-              {(i) => (
-                <div class="w-full flex items-center gap-x-2.5">
-                  <span>{i.name}</span>
-                  <Show when={!i.cost || i.cost?.input === 0}>
-                    <Tag>Free</Tag>
-                  </Show>
-                  <Show when={i.latest}>
-                    <Tag>Latest</Tag>
-                  </Show>
-                </div>
-              )}
-            </SelectDialog>
+            <Button as="div" variant="ghost" onClick={() => layout.dialog.open("model")}>
+              {local.model.current()?.name ?? "Select model"}
+              <span class="ml-0.5 text-text-weak text-12-regular">{local.model.current()?.provider.name}</span>
+              <Icon name="chevron-down" size="small" />
+            </Button>
+            <Show when={layout.dialog.opened() === "model"}>
+              <SelectDialog
+                defaultOpen
+                onOpenChange={(open) => {
+                  if (open) {
+                    layout.dialog.open("model")
+                  } else {
+                    layout.dialog.close("model")
+                  }
+                }}
+                title="Select model"
+                placeholder="Search models"
+                emptyMessage="No model results"
+                key={(x) => `${x.provider.id}:${x.id}`}
+                items={local.model.list()}
+                current={local.model.current()}
+                filterKeys={["provider.name", "name", "id"]}
+                // groupBy={(x) => (local.model.recent().includes(x) ? "Recent" : x.provider.name)}
+                groupBy={(x) => x.provider.name}
+                sortGroupsBy={(a, b) => {
+                  const order = ["opencode", "anthropic", "github-copilot", "openai", "google", "openrouter", "vercel"]
+                  if (a.category === "Recent" && b.category !== "Recent") return -1
+                  if (b.category === "Recent" && a.category !== "Recent") return 1
+                  const aProvider = a.items[0].provider.id
+                  const bProvider = b.items[0].provider.id
+                  if (order.includes(aProvider) && !order.includes(bProvider)) return -1
+                  if (!order.includes(aProvider) && order.includes(bProvider)) return 1
+                  return order.indexOf(aProvider) - order.indexOf(bProvider)
+                }}
+                onSelect={(x) =>
+                  local.model.set(x ? { modelID: x.id, providerID: x.provider.id } : undefined, { recent: true })
+                }
+                actions={
+                  <Button
+                    class="h-7 -my-1 text-14-medium"
+                    icon="plus-small"
+                    tabIndex={-1}
+                    onClick={() => layout.dialog.open("provider")}
+                  >
+                    Connect provider
+                  </Button>
+                }
+              >
+                {(i) => (
+                  <div class="w-full flex items-center gap-x-2.5">
+                    <span>{i.name}</span>
+                    <Show when={!i.cost || i.cost?.input === 0}>
+                      <Tag>Free</Tag>
+                    </Show>
+                    <Show when={i.latest}>
+                      <Tag>Latest</Tag>
+                    </Show>
+                  </div>
+                )}
+              </SelectDialog>
+            </Show>
           </div>
           <Tooltip
             placement="top"
diff --git a/packages/desktop/src/context/global-sync.tsx b/packages/desktop/src/context/global-sync.tsx
index 3e2b6bf7d..3a6062fb8 100644
--- a/packages/desktop/src/context/global-sync.tsx
+++ b/packages/desktop/src/context/global-sync.tsx
@@ -1,7 +1,6 @@
 import type {
   Message,
   Agent,
-  Provider,
   Session,
   Part,
   Config,
@@ -12,6 +11,7 @@ import type {
   FileDiff,
   Todo,
   SessionStatus,
+  ProviderListResponse,
 } from "@opencode-ai/sdk/v2"
 import { createStore, produce, reconcile } from "solid-js/store"
 import { Binary } from "@opencode-ai/util/binary"
@@ -20,9 +20,9 @@ import { useGlobalSDK } from "./global-sdk"
 
 type State = {
   ready: boolean
-  // provider: Provider[]
   agent: Agent[]
   project: string
+  provider: ProviderListResponse
   config: Config
   path: Path
   session: Session[]
@@ -49,15 +49,16 @@ type State = {
 export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimpleContext({
   name: "GlobalSync",
   init: () => {
+    const sdk = useGlobalSDK()
     const [globalStore, setGlobalStore] = createStore<{
       ready: boolean
-      projects: Project[]
-      providers: Provider[]
+      project: Project[]
+      provider: ProviderListResponse
       children: Record<string, State>
     }>({
       ready: false,
-      projects: [],
-      providers: [],
+      project: [],
+      provider: { all: [], connected: [], default: {} },
       children: {},
     })
 
@@ -66,11 +67,11 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple
       if (!children[directory]) {
         setGlobalStore("children", directory, {
           project: "",
+          provider: { all: [], connected: [], default: {} },
           config: {},
           path: { state: "", config: "", worktree: "", directory: "", home: "" },
           ready: false,
           agent: [],
-          // provider: [],
           session: [],
           session_status: {},
           session_diff: {},
@@ -86,7 +87,6 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple
       return children[directory]
     }
 
-    const sdk = useGlobalSDK()
     sdk.event.listen((e) => {
       const directory = e.name
       const event = e.details
@@ -94,13 +94,13 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple
       if (directory === "global") {
         switch (event.type) {
           case "project.updated": {
-            const result = Binary.search(globalStore.projects, event.properties.id, (s) => s.id)
+            const result = Binary.search(globalStore.project, event.properties.id, (s) => s.id)
             if (result.found) {
-              setGlobalStore("projects", result.index, reconcile(event.properties))
+              setGlobalStore("project", result.index, reconcile(event.properties))
               return
             }
             setGlobalStore(
-              "projects",
+              "project",
               produce((draft) => {
                 draft.splice(result.index, 0, event.properties)
               }),
@@ -184,14 +184,14 @@ export const { use: useGlobalSync, provider: GlobalSyncProvider } = createSimple
     Promise.all([
       sdk.client.project.list().then(async (x) => {
         setGlobalStore(
-          "projects",
+          "project",
           x
             .data!.filter((p) => !p.worktree.includes("opencode-test") && p.vcs)
             .sort((a, b) => a.id.localeCompare(b.id)),
         )
       }),
       sdk.client.provider.list().then((x) => {
-        setGlobalStore("providers", x.data ?? [])
+        setGlobalStore("provider", x.data ?? {})
       }),
     ]).then(() => setGlobalStore("ready", true))
 
diff --git a/packages/desktop/src/context/layout.tsx b/packages/desktop/src/context/layout.tsx
index 13c4679d6..1de8550cb 100644
--- a/packages/desktop/src/context/layout.tsx
+++ b/packages/desktop/src/context/layout.tsx
@@ -40,9 +40,14 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
         },
       }),
       {
-        name: "default-layout.v6",
+        name: "default-layout.v7",
       },
     )
+    const [ephemeral, setEphemeral] = createStore({
+      dialog: {
+        open: undefined as undefined | "provider" | "model",
+      },
+    })
 
     function pickAvailableColor() {
       const available = PASTEL_COLORS.filter((c) => !colors().has(c))
@@ -51,7 +56,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
     }
 
     function enrich(project: { worktree: string; expanded: boolean }) {
-      const metadata = globalSync.data.projects.find((x) => x.worktree === project.worktree)
+      const metadata = globalSync.data.project.find((x) => x.worktree === project.worktree)
       if (!metadata) return []
       return [
         {
@@ -168,6 +173,17 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
           setStore("review", "state", "tab")
         },
       },
+      dialog: {
+        opened: createMemo(() => ephemeral.dialog?.open),
+        open(dialog: "provider" | "model") {
+          setEphemeral("dialog", "open", dialog)
+        },
+        close(dialog: "provider" | "model") {
+          if (ephemeral.dialog?.open === dialog) {
+            setEphemeral("dialog", "open", undefined)
+          }
+        },
+      },
     }
   },
 })
diff --git a/packages/desktop/src/context/local.tsx b/packages/desktop/src/context/local.tsx
index 58a65b0de..74d3ac364 100644
--- a/packages/desktop/src/context/local.tsx
+++ b/packages/desktop/src/context/local.tsx
@@ -39,8 +39,8 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
     const sync = useSync()
 
     function isModelValid(model: ModelKey) {
-      const provider = sync.data.provider.find((x) => x.id === model.providerID)
-      return !!provider?.models[model.modelID]
+      const provider = sync.data.provider?.all.find((x) => x.id === model.providerID)
+      return !!provider?.models[model.modelID] && sync.data.provider?.connected.includes(model.providerID)
     }
 
     function getFirstValidModel(...modelFns: (() => ModelKey | undefined)[]) {
@@ -115,17 +115,16 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
       })
 
       const list = createMemo(() =>
-        sync.data.provider.flatMap((p) =>
-          Object.values(p.models).map(
-            (m) =>
-              ({
-                ...m,
-                name: m.name.replace("(latest)", "").trim(),
-                provider: p,
-                latest: m.name.includes("(latest)"),
-              }) as LocalModel,
+        sync.data.provider.all
+          .filter((p) => sync.data.provider.connected.includes(p.id))
+          .flatMap((p) =>
+            Object.values(p.models).map((m) => ({
+              ...m,
+              name: m.name.replace("(latest)", "").trim(),
+              provider: p,
+              latest: m.name.includes("(latest)"),
+            })),
           ),
-        ),
       )
       const find = (key: ModelKey) => list().find((m) => m.id === key?.modelID && m.provider.id === key.providerID)
 
@@ -145,12 +144,17 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
             return item
           }
         }
-        const provider = sync.data.provider[0]
-        const model = Object.values(provider.models)[0]
-        return {
-          providerID: provider.id,
-          modelID: model.id,
+
+        for (const p of sync.data.provider.connected) {
+          if (p in sync.data.provider.default) {
+            return {
+              providerID: p,
+              modelID: sync.data.provider.default[p],
+            }
+          }
         }
+
+        throw new Error("No default model found")
       })
 
       const currentModel = createMemo(() => {
diff --git a/packages/desktop/src/context/session.tsx b/packages/desktop/src/context/session.tsx
index 31004811b..db2b3af7c 100644
--- a/packages/desktop/src/context/session.tsx
+++ b/packages/desktop/src/context/session.tsx
@@ -94,7 +94,7 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
       () => messages().findLast((x) => x.role === "assistant" && x.tokens.output > 0) as AssistantMessage,
     )
     const model = createMemo(() =>
-      last() ? sync.data.provider.find((x) => x.id === last().providerID)?.models[last().modelID] : undefined,
+      last() ? sync.data.provider.all.find((x) => x.id === last().providerID)?.models[last().modelID] : undefined,
     )
     const diffs = createMemo(() => (params.id ? (sync.data.session_diff[params.id] ?? []) : []))
 
diff --git a/packages/desktop/src/context/sync.tsx b/packages/desktop/src/context/sync.tsx
index 85986c327..1a11cd599 100644
--- a/packages/desktop/src/context/sync.tsx
+++ b/packages/desktop/src/context/sync.tsx
@@ -14,7 +14,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
 
     const load = {
       project: () => sdk.client.project.current().then((x) => setStore("project", x.data!.id)),
-      provider: () => sdk.client.config.providers().then((x) => setStore("provider", x.data!.providers)),
+      provider: () => sdk.client.provider.list().then((x) => setStore("provider", x.data!)),
       path: () => sdk.client.path.get().then((x) => setStore("path", x.data!)),
       agent: () => sdk.client.app.agents().then((x) => setStore("agent", x.data ?? [])),
       session: () =>
@@ -42,8 +42,8 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
         return store.ready
       },
       get project() {
-        const match = Binary.search(globalSync.data.projects, store.project, (p) => p.id)
-        if (match.found) return globalSync.data.projects[match.index]
+        const match = Binary.search(globalSync.data.project, store.project, (p) => p.id)
+        if (match.found) return globalSync.data.project[match.index]
         return undefined
       },
       session: {
diff --git a/packages/desktop/src/pages/home.tsx b/packages/desktop/src/pages/home.tsx
index 4aac241e1..205ffd815 100644
--- a/packages/desktop/src/pages/home.tsx
+++ b/packages/desktop/src/pages/home.tsx
@@ -38,7 +38,7 @@ export default function Home() {
     <div class="mx-auto mt-55">
       <Logo class="w-xl opacity-12" />
       <Switch>
-        <Match when={sync.data.projects.length > 0}>
+        <Match when={sync.data.project.length > 0}>
           <div class="mt-20 w-full flex flex-col gap-4">
             <div class="flex gap-2 items-center justify-between pl-3">
               <div class="text-14-medium text-text-strong">Recent projects</div>
@@ -50,7 +50,7 @@ export default function Home() {
             </div>
             <ul class="flex flex-col gap-2">
               <For
-                each={sync.data.projects
+                each={sync.data.project
                   .toSorted((a, b) => (b.time.updated ?? b.time.created) - (a.time.updated ?? a.time.created))
                   .slice(0, 5)}
               >
diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx
index 3e0094756..2ea6c4ba0 100644
--- a/packages/desktop/src/pages/layout.tsx
+++ b/packages/desktop/src/pages/layout.tsx
@@ -9,6 +9,7 @@ import { Avatar } from "@opencode-ai/ui/avatar"
 import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
 import { Button } from "@opencode-ai/ui/button"
 import { Icon } from "@opencode-ai/ui/icon"
+import { ProviderIcon } from "@opencode-ai/ui/provider-icon"
 import { IconButton } from "@opencode-ai/ui/icon-button"
 import { Tooltip } from "@opencode-ai/ui/tooltip"
 import { Collapsible } from "@opencode-ai/ui/collapsible"
@@ -31,6 +32,9 @@ import {
 import type { DragEvent, Transformer } from "@thisbeyond/solid-dnd"
 import { SelectDialog } from "@opencode-ai/ui/select-dialog"
 import { Tag } from "@opencode-ai/ui/tag"
+import { IconName } from "@opencode-ai/ui/icons/provider"
+
+const popularProviders = ["opencode", "anthropic", "github-copilot", "openai", "google", "openrouter", "vercel"]
 
 export default function Layout(props: ParentProps) {
   const [store, setStore] = createStore({
@@ -46,15 +50,18 @@ export default function Layout(props: ParentProps) {
   const currentDirectory = createMemo(() => base64Decode(params.dir ?? ""))
   const sessions = createMemo(() => globalSync.child(currentDirectory())[0].session ?? [])
   const currentSession = createMemo(() => sessions().find((s) => s.id === params.id))
-  const providers = createMemo(() => globalSync.data.providers)
-  const hasProviders = createMemo(() => {
-    const [projectStore] = globalSync.child(currentDirectory())
-    return projectStore.provider.filter((p) => p.id !== "opencode").length > 0
-  })
-
-  createEffect(() => {
-    console.log(providers())
+  const providers = createMemo(() => {
+    if (currentDirectory()) {
+      const [projectStore] = globalSync.child(currentDirectory())
+      return projectStore.provider
+    }
+    return globalSync.data.provider
   })
+  const connectedProviders = createMemo(() =>
+    providers().all.filter(
+      (p) => providers().connected.includes(p.id) && Object.values(p.models).find((m) => m.cost?.input),
+    ),
+  )
 
   function navigateToProject(directory: string | undefined) {
     if (!directory) return
@@ -93,7 +100,9 @@ export default function Layout(props: ParentProps) {
     }
   }
 
-  async function connectProvider() {}
+  async function connectProvider() {
+    layout.dialog.open("provider")
+  }
 
   createEffect(() => {
     if (!params.dir || !params.id) return
@@ -484,7 +493,7 @@ export default function Layout(props: ParentProps) {
           </div>
           <div class="flex flex-col gap-1.5 self-stretch items-start shrink-0 px-2 py-3">
             <Switch>
-              <Match when={!hasProviders() && layout.sidebar.opened()}>
+              <Match when={!connectedProviders().length && layout.sidebar.opened()}>
                 <div class="rounded-md bg-background-stronger shadow-xs-border-base">
                   <div class="p-3 flex flex-col gap-2">
                     <div class="text-12-medium text-text-strong">Getting started</div>
@@ -493,7 +502,7 @@ export default function Layout(props: ParentProps) {
                   </div>
                   <Tooltip placement="right" value="Connect provider" inactive={layout.sidebar.opened()}>
                     <Button
-                      class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg rounded-t-none shadow-none border-t border-border-weak-base pl-[7px]"
+                      class="flex w-full text-left justify-start text-12-medium text-text-strong stroke-[1.5px] rounded-lg rounded-t-none shadow-none border-t border-border-weak-base pl-2.25 pb-px"
                       size="large"
                       icon="plus-small"
                       onClick={connectProvider}
@@ -506,7 +515,7 @@ export default function Layout(props: ParentProps) {
               <Match when={true}>
                 <Tooltip placement="right" value="Connect provider" inactive={layout.sidebar.opened()}>
                   <Button
-                    class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg"
+                    class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg px-2"
                     variant="ghost"
                     size="large"
                     icon="plus-small"
@@ -520,7 +529,7 @@ export default function Layout(props: ParentProps) {
             <Show when={platform.openDirectoryPickerDialog}>
               <Tooltip placement="right" value="Open project" inactive={layout.sidebar.opened()}>
                 <Button
-                  class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg"
+                  class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg px-2"
                   variant="ghost"
                   size="large"
                   icon="folder-add-left"
@@ -533,7 +542,7 @@ export default function Layout(props: ParentProps) {
             <Tooltip placement="right" value="Settings" inactive={layout.sidebar.opened()}>
               <Button
                 disabled
-                class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg"
+                class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg px-2"
                 variant="ghost"
                 size="large"
                 icon="settings-gear"
@@ -546,7 +555,7 @@ export default function Layout(props: ParentProps) {
                 as={"a"}
                 href="https://opencode.ai/desktop-feedback"
                 target="_blank"
-                class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg"
+                class="flex w-full text-left justify-start text-12-medium text-text-base stroke-[1.5px] rounded-lg px-2"
                 variant="ghost"
                 size="large"
                 icon="bubble-5"
@@ -557,32 +566,53 @@ export default function Layout(props: ParentProps) {
           </div>
         </div>
         <main class="size-full overflow-x-hidden flex flex-col items-start">{props.children}</main>
-        <Show when={true}>
+        <Show when={layout.dialog.opened() === "provider"}>
           <SelectDialog
             defaultOpen
             title="Connect provider"
             placeholder="Search providers"
+            activeIcon="plus-small"
             key={(x) => x?.id}
-            items={providers()}
+            items={providers().all}
             // current={local.model.current()}
-            filterKeys={["provider.name", "name", "id"]}
-            // groupBy={(x) => (local.model.recent().includes(x) ? "Recent" : x.provider.name)}
-            // groupBy={(x) => x.provider.name}
-            onSelect={(x) =>
-              // local.model.set(x ? { modelID: x.id, providerID: x.provider.id } : undefined, { recent: true })
-              {
-                return
+            filterKeys={["id", "name"]}
+            groupBy={(x) => (popularProviders.includes(x.id) ? "Popular" : "Other")}
+            sortBy={(a, b) => {
+              if (popularProviders.includes(a.id) && popularProviders.includes(b.id))
+                return popularProviders.indexOf(a.id) - popularProviders.indexOf(b.id)
+              return a.name.localeCompare(b.name)
+            }}
+            sortGroupsBy={(a, b) => {
+              if (a.category === "Popular" && b.category !== "Popular") return -1
+              if (b.category === "Popular" && a.category !== "Popular") return 1
+              return 0
+            }}
+            // onSelect={(x) => }
+            onOpenChange={(open) => {
+              if (open) {
+                layout.dialog.open("provider")
+              } else {
+                layout.dialog.close("provider")
               }
-            }
+            }}
           >
             {(i) => (
-              <div class="w-full flex items-center gap-x-2.5">
+              <div class="px-1.25 w-full flex items-center gap-x-4">
+                <ProviderIcon
+                  id={i.id as IconName}
+                  // TODO: clean this up after we update icon in models.dev
+                  classList={{
+                    "text-icon-weak-base": true,
+                    "size-4 mx-0.5": i.id === "opencode",
+                    "size-5": i.id !== "opencode",
+                  }}
+                />
                 <span>{i.name}</span>
-                <Show when={!i.cost || i.cost?.input === 0}>
-                  <Tag>Free</Tag>
+                <Show when={i.id === "opencode"}>
+                  <Tag>Recommended</Tag>
                 </Show>
-                <Show when={i.latest}>
-                  <Tag>Latest</Tag>
+                <Show when={i.id === "anthropic"}>
+                  <div class="text-14-regular text-text-weak">Connect with Claude Pro/Max or API key</div>
                 </Show>
               </div>
             )}
diff --git a/packages/enterprise/src/routes/share/[shareID].tsx b/packages/enterprise/src/routes/share/[shareID].tsx
index 15a36b2ff..1c593ca87 100644
--- a/packages/enterprise/src/routes/share/[shareID].tsx
+++ b/packages/enterprise/src/routes/share/[shareID].tsx
@@ -212,7 +212,7 @@ export default function () {
                           <div class="text-12-mono text-text-base">v{info().version}</div>
                         </div>
                         <div class="flex gap-2 items-center">
-                          <ProviderIcon name={provider() as IconName} class="size-3.5 shrink-0 text-icon-strong-base" />
+                          <ProviderIcon id={provider() as IconName} class="size-3.5 shrink-0 text-icon-strong-base" />
                           <div class="text-12-regular text-text-base">{model()?.name ?? modelID()}</div>
                         </div>
                         <div class="text-12-regular text-text-weaker">
diff --git a/packages/ui/src/components/provider-icon.tsx b/packages/ui/src/components/provider-icon.tsx
index 924dcd25c..d653765a5 100644
--- a/packages/ui/src/components/provider-icon.tsx
+++ b/packages/ui/src/components/provider-icon.tsx
@@ -4,11 +4,11 @@ import sprite from "./provider-icons/sprite.svg"
 import type { IconName } from "./provider-icons/types"
 
 export type ProviderIconProps = JSX.SVGElementTags["svg"] & {
-  name: IconName
+  id: IconName
 }
 
 export const ProviderIcon: Component<ProviderIconProps> = (props) => {
-  const [local, rest] = splitProps(props, ["name", "class", "classList"])
+  const [local, rest] = splitProps(props, ["id", "class", "classList"])
   return (
     <svg
       data-component="provider-icon"
@@ -18,7 +18,7 @@ export const ProviderIcon: Component<ProviderIconProps> = (props) => {
         [local.class ?? ""]: !!local.class,
       }}
     >
-      <use href={`${sprite}#${local.name}`} />
+      <use href={`${sprite}#${local.id}`} />
     </svg>
   )
 }
diff --git a/packages/ui/src/components/select-dialog.css b/packages/ui/src/components/select-dialog.css
index cc834f795..f5687ad8e 100644
--- a/packages/ui/src/components/select-dialog.css
+++ b/packages/ui/src/components/select-dialog.css
@@ -11,7 +11,7 @@
   display: flex;
   height: 40px;
   flex-shrink: 0;
-  padding: 4px 10px 4px 6px;
+  padding: 4px 10px 4px 16px;
   align-items: center;
   gap: 12px;
   align-self: stretch;
@@ -121,6 +121,9 @@
         letter-spacing: var(--letter-spacing-normal);
 
         [data-slot="select-dialog-item-selected-icon"] {
+          color: var(--icon-strong-base);
+        }
+        [data-slot="select-dialog-item-active-icon"] {
           display: none;
           color: var(--icon-strong-base);
         }
@@ -128,12 +131,13 @@
         &[data-active="true"] {
           border-radius: var(--radius-md);
           background: var(--surface-raised-base-hover);
-        }
-        &[data-selected="true"] {
-          [data-slot="select-dialog-item-selected-icon"] {
+          [data-slot="select-dialog-item-active-icon"] {
             display: block;
           }
         }
+        &:active {
+          background: var(--surface-raised-base-active);
+        }
       }
     }
   }
diff --git a/packages/ui/src/components/select-dialog.tsx b/packages/ui/src/components/select-dialog.tsx
index b93993ad4..86f723225 100644
--- a/packages/ui/src/components/select-dialog.tsx
+++ b/packages/ui/src/components/select-dialog.tsx
@@ -2,7 +2,7 @@ import { createEffect, Show, For, type JSX, splitProps, createSignal } from "sol
 import { createStore } from "solid-js/store"
 import { FilteredListProps, useFilteredList } from "@opencode-ai/ui/hooks"
 import { Dialog, DialogProps } from "./dialog"
-import { Icon } from "./icon"
+import { Icon, IconProps } from "./icon"
 import { Input } from "./input"
 import { IconButton } from "./icon-button"
 
@@ -16,6 +16,7 @@ interface SelectDialogProps<T>
   onSelect?: (value: T | undefined) => void
   onKeyEvent?: (event: KeyboardEvent, item: T | undefined) => void
   actions?: JSX.Element
+  activeIcon?: IconProps["name"]
 }
 
 export function SelectDialog<T>(props: SelectDialogProps<T>) {
@@ -165,7 +166,12 @@ export function SelectDialog<T>(props: SelectDialogProps<T>) {
                           }}
                         >
                           {others.children(item)}
-                          <Icon data-slot="select-dialog-item-selected-icon" name="check-small" />
+                          <Show when={item === others.current}>
+                            <Icon data-slot="select-dialog-item-selected-icon" name="check-small" />
+                          </Show>
+                          <Show when={others.activeIcon}>
+                            {(icon) => <Icon data-slot="select-dialog-item-active-icon" name={icon()} />}
+                          </Show>
                         </button>
                       )}
                     </For>
-- 
cgit v1.2.3


From 56540f83125d8ec3fd6f26ac7edca7471c2aca3f Mon Sep 17 00:00:00 2001
From: Adam <2363879+adamdotdevin@users.noreply.github.com>
Date: Wed, 10 Dec 2025 17:30:53 -0600
Subject: wip(desktop): progress

---
 packages/desktop/src/components/prompt-input.tsx |  6 ++++++
 packages/desktop/src/context/layout.tsx          | 12 +++---------
 2 files changed, 9 insertions(+), 9 deletions(-)

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

diff --git a/packages/desktop/src/components/prompt-input.tsx b/packages/desktop/src/components/prompt-input.tsx
index 0672dfc85..22f2c1642 100644
--- a/packages/desktop/src/components/prompt-input.tsx
+++ b/packages/desktop/src/components/prompt-input.tsx
@@ -621,6 +621,12 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
                                     </div>
                                   )}
                                 </List>
+                                <Button variant="ghost" class="w-full justify-start">
+                                  <div class="flex items-center gap-2">
+                                    <Icon name="plus-small" />
+                                    <div class="text-text-strong">View all providers</div>
+                                  </div>
+                                </Button>
                               </div>
                             </div>
                           </div>
diff --git a/packages/desktop/src/context/layout.tsx b/packages/desktop/src/context/layout.tsx
index 1de8550cb..5530ad28f 100644
--- a/packages/desktop/src/context/layout.tsx
+++ b/packages/desktop/src/context/layout.tsx
@@ -48,9 +48,10 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
         open: undefined as undefined | "provider" | "model",
       },
     })
+    const usedColors = new Set<string>()
 
     function pickAvailableColor() {
-      const available = PASTEL_COLORS.filter((c) => !colors().has(c))
+      const available = PASTEL_COLORS.filter((c) => !usedColors.has(c))
       if (available.length === 0) return PASTEL_COLORS[Math.floor(Math.random() * PASTEL_COLORS.length)]
       return available[Math.floor(Math.random() * available.length)]
     }
@@ -69,6 +70,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
     function colorize(project: Project & { expanded: boolean }) {
       if (project.icon?.color) return project
       const color = pickAvailableColor()
+      usedColors.add(color)
       project.icon = { ...project.icon, color }
       globalSdk.client.project.update({ projectID: project.id, icon: { color } })
       return project
@@ -76,14 +78,6 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
 
     const enriched = createMemo(() => store.projects.flatMap(enrich))
     const list = createMemo(() => enriched().flatMap(colorize))
-    const colors = createMemo(
-      () =>
-        new Set(
-          list()
-            .map((p) => p.icon?.color)
-            .filter(Boolean),
-        ),
-    )
 
     async function loadProjectSessions(directory: string) {
       const [, setStore] = globalSync.child(directory)
-- 
cgit v1.2.3

