Skip to content

Commit 157eb6e

Browse files
committed
Merge branch 'shuvcode-dev' into integration
Sync upstream v1.0.221 and desktop improvements: - Better model selector UI - Desktop auto-accept improvements - LSP workspace/didChangeWatchedFiles support - Various fixes and refactoring Closes #232
2 parents fc158ca + 3905520 commit 157eb6e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+578
-735
lines changed

.github/last-synced-tag

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v1.0.220
1+
v1.0.221

bun.lock

Lines changed: 27 additions & 362 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@opencode-ai/app",
3-
"version": "1.0.220",
3+
"version": "1.0.221",
44
"description": "",
55
"type": "module",
66
"exports": {

packages/app/src/app.tsx

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { Diff } from "@opencode-ai/ui/diff"
1010
import { Code } from "@opencode-ai/ui/code"
1111
import { ThemeProvider } from "@opencode-ai/ui/theme"
1212
import { GlobalSyncProvider } from "@/context/global-sync"
13+
import { PermissionProvider } from "@/context/permission"
1314
import { LayoutProvider } from "@/context/layout"
1415
import { GlobalSDKProvider } from "@/context/global-sdk"
1516
import { ServerProvider, useServer } from "@/context/server"
@@ -75,34 +76,36 @@ export function App() {
7576
<ServerKey>
7677
<GlobalSDKProvider>
7778
<GlobalSyncProvider>
78-
<LayoutProvider>
79-
<NotificationProvider>
80-
<Router
81-
root={(props) => (
82-
<CommandProvider>
83-
<Layout>{props.children}</Layout>
84-
</CommandProvider>
79+
<Router
80+
root={(props) => (
81+
<PermissionProvider>
82+
<LayoutProvider>
83+
<NotificationProvider>
84+
<CommandProvider>
85+
<Layout>{props.children}</Layout>
86+
</CommandProvider>
87+
</NotificationProvider>
88+
</LayoutProvider>
89+
</PermissionProvider>
90+
)}
91+
>
92+
<Route path="/" component={Home} />
93+
<Route path="/:dir" component={DirectoryLayout}>
94+
<Route path="/" component={() => <Navigate href="session" />} />
95+
<Route
96+
path="/session/:id?"
97+
component={(p) => (
98+
<Show when={p.params.id ?? "new"} keyed>
99+
<TerminalProvider>
100+
<PromptProvider>
101+
<Session />
102+
</PromptProvider>
103+
</TerminalProvider>
104+
</Show>
85105
)}
86-
>
87-
<Route path="/" component={Home} />
88-
<Route path="/:dir" component={DirectoryLayout}>
89-
<Route path="/" component={() => <Navigate href="session" />} />
90-
<Route
91-
path="/session/:id?"
92-
component={(p) => (
93-
<Show when={p.params.id ?? "new"} keyed>
94-
<TerminalProvider>
95-
<PromptProvider>
96-
<Session />
97-
</PromptProvider>
98-
</TerminalProvider>
99-
</Show>
100-
)}
101-
/>
102-
</Route>
103-
</Router>
104-
</NotificationProvider>
105-
</LayoutProvider>
106+
/>
107+
</Route>
108+
</Router>
106109
</GlobalSyncProvider>
107110
</GlobalSDKProvider>
108111
</ServerKey>

packages/app/src/components/dialog-select-model.tsx

Lines changed: 72 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { Component, createMemo, Show } from "solid-js"
1+
import { Popover as Kobalte } from "@kobalte/core/popover"
2+
import { Component, createMemo, createSignal, JSX, Show } from "solid-js"
23
import { useLocal } from "@/context/local"
34
import { useDialog } from "@opencode-ai/ui/context/dialog"
45
import { popularProviders } from "@/hooks/use-providers"
@@ -9,9 +10,12 @@ import { List } from "@opencode-ai/ui/list"
910
import { DialogSelectProvider } from "./dialog-select-provider"
1011
import { DialogManageModels } from "./dialog-manage-models"
1112

12-
export const DialogSelectModel: Component<{ provider?: string }> = (props) => {
13+
const ModelList: Component<{
14+
provider?: string
15+
class?: string
16+
onSelect: () => void
17+
}> = (props) => {
1318
const local = useLocal()
14-
const dialog = useDialog()
1519

1620
const models = createMemo(() =>
1721
local.model
@@ -20,6 +24,70 @@ export const DialogSelectModel: Component<{ provider?: string }> = (props) => {
2024
.filter((m) => (props.provider ? m.provider.id === props.provider : true)),
2125
)
2226

27+
return (
28+
<List
29+
class={`flex-1 min-h-0 [&_[data-slot=list-scroll]]:flex-1 [&_[data-slot=list-scroll]]:min-h-0 ${props.class ?? ""}`}
30+
search={{ placeholder: "Search models", autofocus: true }}
31+
emptyMessage="No model results"
32+
key={(x) => `${x.provider.id}:${x.id}`}
33+
items={models}
34+
current={local.model.current()}
35+
filterKeys={["provider.name", "name", "id"]}
36+
sortBy={(a, b) => a.name.localeCompare(b.name)}
37+
groupBy={(x) => x.provider.name}
38+
sortGroupsBy={(a, b) => {
39+
if (a.category === "Recent" && b.category !== "Recent") return -1
40+
if (b.category === "Recent" && a.category !== "Recent") return 1
41+
const aProvider = a.items[0].provider.id
42+
const bProvider = b.items[0].provider.id
43+
if (popularProviders.includes(aProvider) && !popularProviders.includes(bProvider)) return -1
44+
if (!popularProviders.includes(aProvider) && popularProviders.includes(bProvider)) return 1
45+
return popularProviders.indexOf(aProvider) - popularProviders.indexOf(bProvider)
46+
}}
47+
onSelect={(x) => {
48+
local.model.set(x ? { modelID: x.id, providerID: x.provider.id } : undefined, {
49+
recent: true,
50+
})
51+
props.onSelect()
52+
}}
53+
>
54+
{(i) => (
55+
<div class="w-full flex items-center gap-x-2 text-13-regular">
56+
<span class="truncate">{i.name}</span>
57+
<Show when={i.provider.id === "opencode" && (!i.cost || i.cost?.input === 0)}>
58+
<Tag>Free</Tag>
59+
</Show>
60+
<Show when={i.latest}>
61+
<Tag>Latest</Tag>
62+
</Show>
63+
</div>
64+
)}
65+
</List>
66+
)
67+
}
68+
69+
export const ModelSelectorPopover: Component<{
70+
provider?: string
71+
children: JSX.Element
72+
}> = (props) => {
73+
const [open, setOpen] = createSignal(false)
74+
75+
return (
76+
<Kobalte open={open()} onOpenChange={setOpen} placement="top-start" gutter={8}>
77+
<Kobalte.Trigger as="div">{props.children}</Kobalte.Trigger>
78+
<Kobalte.Portal>
79+
<Kobalte.Content class="w-72 h-80 flex flex-col rounded-md border border-border-base bg-surface-raised-stronger-non-alpha shadow-md z-50 outline-none">
80+
<Kobalte.Title class="sr-only">Select model</Kobalte.Title>
81+
<ModelList provider={props.provider} onSelect={() => setOpen(false)} class="p-1" />
82+
</Kobalte.Content>
83+
</Kobalte.Portal>
84+
</Kobalte>
85+
)
86+
}
87+
88+
export const DialogSelectModel: Component<{ provider?: string }> = (props) => {
89+
const dialog = useDialog()
90+
2391
return (
2492
<Dialog
2593
title="Select model"
@@ -34,43 +102,7 @@ export const DialogSelectModel: Component<{ provider?: string }> = (props) => {
34102
</Button>
35103
}
36104
>
37-
<List
38-
search={{ placeholder: "Search models", autofocus: true }}
39-
emptyMessage="No model results"
40-
key={(x) => `${x.provider.id}:${x.id}`}
41-
items={models}
42-
current={local.model.current()}
43-
filterKeys={["provider.name", "name", "id"]}
44-
sortBy={(a, b) => a.name.localeCompare(b.name)}
45-
groupBy={(x) => x.provider.name}
46-
sortGroupsBy={(a, b) => {
47-
if (a.category === "Recent" && b.category !== "Recent") return -1
48-
if (b.category === "Recent" && a.category !== "Recent") return 1
49-
const aProvider = a.items[0].provider.id
50-
const bProvider = b.items[0].provider.id
51-
if (popularProviders.includes(aProvider) && !popularProviders.includes(bProvider)) return -1
52-
if (!popularProviders.includes(aProvider) && popularProviders.includes(bProvider)) return 1
53-
return popularProviders.indexOf(aProvider) - popularProviders.indexOf(bProvider)
54-
}}
55-
onSelect={(x) => {
56-
local.model.set(x ? { modelID: x.id, providerID: x.provider.id } : undefined, {
57-
recent: true,
58-
})
59-
dialog.close()
60-
}}
61-
>
62-
{(i) => (
63-
<div class="w-full flex items-center gap-x-3">
64-
<span>{i.name}</span>
65-
<Show when={i.provider.id === "opencode" && (!i.cost || i.cost?.input === 0)}>
66-
<Tag>Free</Tag>
67-
</Show>
68-
<Show when={i.latest}>
69-
<Tag>Latest</Tag>
70-
</Show>
71-
</div>
72-
)}
73-
</List>
105+
<ModelList provider={props.provider} onSelect={() => dialog.close()} />
74106
<Button
75107
variant="ghost"
76108
class="ml-3 mt-5 mb-6 text-text-base self-start"

0 commit comments

Comments
 (0)