Skip to content

Commit b15dced

Browse files
committed
Bump version to 0.1.13
- Remove TodoSidebar and right sidebar layout (simplify to single sidebar) - Improve reasoning view: auto-expand while thinking, auto-scroll - Improve tool labels: dynamic verbs (Reading/Read, Editing/Edited, Running/Ran) - Show file path context for Read tool calls - Update shadcn/ui component library (40+ new/updated components) - Update deps: @opencode-ai/sdk 1.2.17, lucide-react 0.577, electron 40.7 - Add new deps: @base-ui/react, react-hook-form, recharts, sonner, vaul, zod - Clean up dead useSessionTodos export
1 parent e2062b1 commit b15dced

63 files changed

Lines changed: 5719 additions & 673 deletions

Some content is hidden

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

biome.json

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,21 @@
1515
"linter": {
1616
"enabled": true,
1717
"rules": {
18-
"recommended": true
18+
"recommended": true,
19+
"a11y": {
20+
"useFocusableInteractive": "warn",
21+
"useSemanticElements": "warn",
22+
"noRedundantRoles": "warn",
23+
"useAriaPropsForRole": "warn",
24+
"useKeyWithClickEvents": "warn"
25+
},
26+
"suspicious": {
27+
"noArrayIndexKey": "warn",
28+
"noDocumentCookie": "warn"
29+
},
30+
"security": {
31+
"noDangerouslySetInnerHtml": "warn"
32+
}
1933
}
2034
},
2135
"javascript": {

bun.lock

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

package.json

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "opengui",
3-
"version": "0.1.12",
3+
"version": "0.1.13",
44
"description": "OpenGUI - A graphical interface for OpenCode",
55
"author": {
66
"name": "Emmanuel",
@@ -64,25 +64,37 @@
6464
"npmRebuild": false
6565
},
6666
"dependencies": {
67-
"@opencode-ai/sdk": "^1.2.15",
67+
"@base-ui/react": "^1.2.0",
68+
"@hookform/resolvers": "^5.2.2",
69+
"@opencode-ai/sdk": "^1.2.17",
6870
"@radix-ui/react-label": "^2.1.8",
6971
"@radix-ui/react-select": "^2.2.6",
70-
7172
"@radix-ui/react-tabs": "^1.1.13",
72-
7373
"class-variance-authority": "^0.7.1",
7474
"clsx": "^2.1.1",
75+
"cmdk": "^1.1.1",
76+
"date-fns": "^4.1.0",
77+
"embla-carousel-react": "^8.6.0",
78+
"input-otp": "^1.4.2",
7579
"katex": "^0.16.33",
76-
"lucide-react": "^0.564.0",
80+
"lucide-react": "^0.577.0",
81+
"next-themes": "^0.4.6",
7782
"radix-ui": "^1.4.3",
7883
"react": "^19.2.4",
84+
"react-day-picker": "^9.14.0",
7985
"react-dom": "^19.2.4",
86+
"react-hook-form": "^7.71.2",
8087
"react-markdown": "^10.1.0",
88+
"react-resizable-panels": "^4.7.1",
89+
"recharts": "2.15.4",
8190
"rehype-katex": "^7.0.1",
8291
"remark-gfm": "^4.0.1",
8392
"remark-math": "^6.0.0",
8493
"shiki": "^3.23.0",
85-
"tailwind-merge": "^3.5.0"
94+
"sonner": "^2.0.7",
95+
"tailwind-merge": "^3.5.0",
96+
"vaul": "^1.1.2",
97+
"zod": "^4.3.6"
8698
},
8799
"devDependencies": {
88100
"@biomejs/biome": "2.3.15",
@@ -91,7 +103,7 @@
91103
"@types/react": "^19.2.14",
92104
"@types/react-dom": "^19.2.3",
93105
"concurrently": "^9.2.1",
94-
"electron": "^40.6.1",
106+
"electron": "^40.7.0",
95107
"electron-builder": "^26.8.1",
96108
"tailwindcss": "^4.2.1",
97109
"tw-animate-css": "^1.4.0",

src/App.tsx

Lines changed: 94 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import { AlertCircle, X } from "lucide-react";
22
import { useCallback, useEffect, useMemo } from "react";
33
import { QueueList } from "@/components/QueueList";
4-
import { TodoSidebar } from "@/components/TodoSidebar";
54
import { UpdateDialog } from "@/components/UpdateDialog";
65
import { Button } from "@/components/ui/button";
76
import {
8-
RightSidebarProvider,
97
SidebarInset,
108
SidebarProvider,
9+
useSidebar,
1110
} from "@/components/ui/sidebar";
1211
import { Spinner } from "@/components/ui/spinner";
1312
import {
@@ -20,7 +19,6 @@ import {
2019
useSessionState,
2120
} from "@/hooks/use-opencode";
2221
import { useUpdateCheck } from "@/hooks/use-update-check";
23-
import { useSessionTodos } from "@/lib/todos";
2422
import { computeTokenTotal } from "@/lib/utils";
2523
import { AppSidebar } from "./components/AppSidebar";
2624
import { MessageList } from "./components/MessageList";
@@ -29,6 +27,7 @@ import { TitleBar } from "./components/TitleBar";
2927
import "./index.css";
3028

3129
function AppContent() {
30+
const leftSidebar = useSidebar();
3231
const {
3332
sendPrompt,
3433
abortSession,
@@ -185,128 +184,119 @@ function AppContent() {
185184
);
186185
}, [activeSessionId, messages, providers, selectedModel, providerDefaults]);
187186

188-
// Extract the latest todo snapshot from the current session's messages
189-
const sessionTodos = useSessionTodos(messages);
190-
191187
// Check for app updates on startup
192188
const updateCheck = useUpdateCheck();
193189

194190
return (
195-
<SidebarProvider>
191+
<>
196192
<AppSidebar />
197-
<SidebarInset>
198-
<RightSidebarProvider className="flex-col">
193+
<SidebarInset className="overflow-hidden">
194+
<div className="flex flex-col h-full">
199195
{/* Title bar spans full width */}
200-
<TitleBar todos={sessionTodos} />
196+
<TitleBar onToggleLeftSidebar={leftSidebar.toggleSidebar} />
201197

202-
{/* Below title bar: content column + right sidebar in a row */}
203-
<div className="flex flex-1 min-h-0 min-w-0">
204-
<div className="flex-1 flex flex-col min-w-0 select-none">
205-
{/* Startup banner */}
206-
{isBooting && (
207-
<div className="flex items-center gap-2 px-4 py-2 border-b border-border text-sm text-muted-foreground bg-muted/30">
208-
<Spinner className="size-4 shrink-0" />
209-
<span>
210-
{bootState === "checking-server"
211-
? "Checking local OpenCode server..."
212-
: "Starting local OpenCode server..."}
213-
</span>
214-
</div>
215-
)}
198+
<div className="flex-1 flex flex-col min-w-0 min-h-0 select-none">
199+
{/* Startup banner */}
200+
{isBooting && (
201+
<div className="flex items-center gap-2 px-4 py-2 border-b border-border text-sm text-muted-foreground bg-muted/30">
202+
<Spinner className="size-4 shrink-0" />
203+
<span>
204+
{bootState === "checking-server"
205+
? "Checking local OpenCode server..."
206+
: "Starting local OpenCode server..."}
207+
</span>
208+
</div>
209+
)}
216210

217-
{/* Error banner */}
218-
{!isBooting && (bootState === "error" || lastError) && (
219-
<div className="flex items-center gap-2 px-4 py-2 bg-destructive/10 border-b border-destructive/20 text-sm text-destructive">
220-
<AlertCircle className="size-4 shrink-0" />
221-
<span className="flex-1 truncate">
222-
{bootState === "error" ? bootError : lastError}
223-
</span>
224-
<Button variant="ghost" size="icon-xs" onClick={clearError}>
225-
<X className="size-3" />
226-
</Button>
227-
</div>
228-
)}
211+
{/* Error banner */}
212+
{!isBooting && (bootState === "error" || lastError) && (
213+
<div className="flex items-center gap-2 px-4 py-2 bg-destructive/10 border-b border-destructive/20 text-sm text-destructive">
214+
<AlertCircle className="size-4 shrink-0" />
215+
<span className="flex-1 truncate">
216+
{bootState === "error" ? bootError : lastError}
217+
</span>
218+
<Button variant="ghost" size="icon-xs" onClick={clearError}>
219+
<X className="size-3" />
220+
</Button>
221+
</div>
222+
)}
229223

230-
{/* Chat area */}
231-
<MessageList />
224+
{/* Chat area */}
225+
<MessageList />
232226

233-
{/* Queue list + Prompt input */}
234-
<div className="shrink-0">
235-
<div className="max-w-2xl mx-auto">
236-
{queuedPrompts.length > 0 && (
237-
<div className="mb-1.5">
238-
<QueueList
239-
items={queuedPrompts}
240-
onRemove={(id) => {
241-
if (!activeSessionId) return;
242-
removeFromQueue(activeSessionId, id);
243-
}}
244-
onMoveUp={(index) => {
245-
if (!activeSessionId) return;
246-
reorderQueue(activeSessionId, index, index - 1);
247-
}}
248-
onMoveDown={(index) => {
249-
if (!activeSessionId) return;
250-
reorderQueue(activeSessionId, index, index + 1);
251-
}}
252-
onMoveToTop={(index) => {
253-
if (!activeSessionId) return;
254-
reorderQueue(activeSessionId, index, 0);
255-
}}
256-
onMoveToBottom={(index) => {
257-
if (!activeSessionId) return;
258-
reorderQueue(
259-
activeSessionId,
260-
index,
261-
queuedPrompts.length - 1,
262-
);
263-
}}
264-
onEdit={(id, newText) => {
265-
if (!activeSessionId) return;
266-
updateQueuedPrompt(activeSessionId, id, newText);
267-
}}
268-
onSendNow={(id) => {
269-
if (!activeSessionId) return;
270-
void sendQueuedNow(activeSessionId, id);
271-
}}
272-
/>
273-
</div>
274-
)}
275-
<PromptBox
276-
autoFocus
277-
disabled={
278-
isBooting ||
279-
!isConnected ||
280-
isLoadingMessages ||
281-
(!activeSessionId && !draftSessionDirectory)
282-
}
283-
isLoading={isBusy}
284-
contextPercent={contextPercent}
285-
onSubmit={(message, images) => {
286-
sendPrompt(message, images);
287-
}}
288-
onStop={() => abortSession()}
289-
/>
290-
</div>
227+
{/* Queue list + Prompt input */}
228+
<div className="shrink-0">
229+
<div className="max-w-2xl mx-auto">
230+
{queuedPrompts.length > 0 && (
231+
<div className="mb-1.5">
232+
<QueueList
233+
items={queuedPrompts}
234+
onRemove={(id) => {
235+
if (!activeSessionId) return;
236+
removeFromQueue(activeSessionId, id);
237+
}}
238+
onMoveUp={(index) => {
239+
if (!activeSessionId) return;
240+
reorderQueue(activeSessionId, index, index - 1);
241+
}}
242+
onMoveDown={(index) => {
243+
if (!activeSessionId) return;
244+
reorderQueue(activeSessionId, index, index + 1);
245+
}}
246+
onMoveToTop={(index) => {
247+
if (!activeSessionId) return;
248+
reorderQueue(activeSessionId, index, 0);
249+
}}
250+
onMoveToBottom={(index) => {
251+
if (!activeSessionId) return;
252+
reorderQueue(
253+
activeSessionId,
254+
index,
255+
queuedPrompts.length - 1,
256+
);
257+
}}
258+
onEdit={(id, newText) => {
259+
if (!activeSessionId) return;
260+
updateQueuedPrompt(activeSessionId, id, newText);
261+
}}
262+
onSendNow={(id) => {
263+
if (!activeSessionId) return;
264+
void sendQueuedNow(activeSessionId, id);
265+
}}
266+
/>
267+
</div>
268+
)}
269+
<PromptBox
270+
autoFocus
271+
disabled={
272+
isBooting ||
273+
!isConnected ||
274+
isLoadingMessages ||
275+
(!activeSessionId && !draftSessionDirectory)
276+
}
277+
isLoading={isBusy}
278+
contextPercent={contextPercent}
279+
onSubmit={(message, images) => {
280+
sendPrompt(message, images);
281+
}}
282+
onStop={() => abortSession()}
283+
/>
291284
</div>
292285
</div>
293-
294-
{/* Right sidebar: task list */}
295-
<TodoSidebar todos={sessionTodos} />
296286
</div>
297-
</RightSidebarProvider>
287+
</div>
298288
</SidebarInset>
299-
300-
{/* Update-available popup */}
301289
<UpdateDialog update={updateCheck} />
302-
</SidebarProvider>
290+
</>
303291
);
304292
}
305293

306294
export function App() {
307295
return (
308296
<OpenCodeProvider>
309-
<AppContent />
297+
<SidebarProvider className="!h-dvh">
298+
<AppContent />
299+
</SidebarProvider>
310300
</OpenCodeProvider>
311301
);
312302
}

0 commit comments

Comments
 (0)