summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdam <[email protected]>2025-12-09 14:49:00 -0600
committerAdam <[email protected]>2025-12-09 15:21:47 -0600
commitb9fa7d91630fdaddf1744ba73b6dfcc8821e0b28 (patch)
tree10eaa287374cb90dd5541f50ab5df72051060aef
parentf736751ab275f52701d40ca0488b75081ed851ec (diff)
downloadopencode-b9fa7d91630fdaddf1744ba73b6dfcc8821e0b28.tar.gz
opencode-b9fa7d91630fdaddf1744ba73b6dfcc8821e0b28.zip
wip(desktop): progress
-rw-r--r--packages/desktop/src/context/layout.tsx33
-rw-r--r--packages/desktop/src/pages/layout.tsx43
-rw-r--r--packages/enterprise/src/core/share.ts2
-rw-r--r--packages/enterprise/src/routes/share/[shareID].tsx2
-rw-r--r--packages/ui/src/components/message-nav.tsx2
-rw-r--r--packages/ui/src/components/message-part.tsx2
-rw-r--r--packages/ui/src/components/message-progress.tsx2
-rw-r--r--packages/ui/src/components/session-message-rail.tsx2
-rw-r--r--packages/ui/src/components/session-review.tsx2
-rw-r--r--packages/ui/src/components/session-turn.tsx2
-rw-r--r--packages/ui/src/context/data.tsx2
-rw-r--r--packages/util/src/sanitize.ts2
12 files changed, 57 insertions, 39 deletions
diff --git a/packages/desktop/src/context/layout.tsx b/packages/desktop/src/context/layout.tsx
index 58d947af4..b7d1fabb5 100644
--- a/packages/desktop/src/context/layout.tsx
+++ b/packages/desktop/src/context/layout.tsx
@@ -12,7 +12,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
const globalSync = useGlobalSync()
const [store, setStore] = makePersisted(
createStore({
- projects: [] as { directory: string; expanded: boolean }[],
+ projects: [] as { worktree: string; expanded: boolean }[],
sidebar: {
opened: false,
width: 280,
@@ -26,7 +26,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
},
}),
{
- name: "default-layout.v4",
+ name: "default-layout.v6",
},
)
@@ -43,32 +43,43 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
onMount(() => {
Promise.all(
- store.projects.map(({ directory }) => {
- return loadProjectSessions(directory)
+ store.projects.map(({ worktree }) => {
+ return loadProjectSessions(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),
+ list: createMemo(() => store.projects.flatMap(enrich)),
open(directory: string) {
- if (store.projects.find((x) => x.directory === directory)) return
+ if (store.projects.find((x) => x.worktree === directory)) return
loadProjectSessions(directory)
- setStore("projects", (x) => [...x, { directory, expanded: true }])
+ setStore("projects", (x) => [...x, { worktree: directory, expanded: true }])
},
close(directory: string) {
- setStore("projects", (x) => x.filter((x) => x.directory !== directory))
+ setStore("projects", (x) => x.filter((x) => x.worktree !== directory))
},
expand(directory: string) {
- setStore("projects", (x) => x.map((x) => (x.directory === directory ? { ...x, expanded: true } : x)))
+ setStore("projects", (x) => x.map((x) => (x.worktree === directory ? { ...x, expanded: true } : x)))
},
collapse(directory: string) {
- setStore("projects", (x) => x.map((x) => (x.directory === directory ? { ...x, expanded: false } : x)))
+ setStore("projects", (x) => x.map((x) => (x.worktree === directory ? { ...x, expanded: false } : x)))
},
move(directory: string, toIndex: number) {
setStore("projects", (projects) => {
- const fromIndex = projects.findIndex((x) => x.directory === directory)
+ const fromIndex = projects.findIndex((x) => x.worktree === directory)
if (fromIndex === -1 || fromIndex === toIndex) return projects
const result = [...projects]
const [item] = result.splice(fromIndex, 1)
diff --git a/packages/desktop/src/pages/layout.tsx b/packages/desktop/src/pages/layout.tsx
index 4d3f6a268..c2755b9dc 100644
--- a/packages/desktop/src/pages/layout.tsx
+++ b/packages/desktop/src/pages/layout.tsx
@@ -16,7 +16,7 @@ import { DiffChanges } from "@opencode-ai/ui/diff-changes"
import { getFilename } from "@opencode-ai/util/path"
import { Select } from "@opencode-ai/ui/select"
import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
-import { Session } from "@opencode-ai/sdk/v2/client"
+import { Session, Project } from "@opencode-ai/sdk/v2/client"
import { usePlatform } from "@/context/platform"
import { createStore } from "solid-js/store"
import {
@@ -106,8 +106,8 @@ export default function Layout(props: ParentProps) {
const { draggable, droppable } = event
if (draggable && droppable) {
const projects = layout.projects.list()
- const fromIndex = projects.findIndex((p) => p.directory === draggable.id.toString())
- const toIndex = projects.findIndex((p) => p.directory === droppable.id.toString())
+ const fromIndex = projects.findIndex((p) => p.worktree === draggable.id.toString())
+ const toIndex = projects.findIndex((p) => p.worktree === droppable.id.toString())
if (fromIndex !== toIndex && toIndex !== -1) {
layout.projects.move(draggable.id.toString(), toIndex)
}
@@ -176,11 +176,11 @@ export default function Layout(props: ParentProps) {
)
}
- const SortableProject = (props: { project: { directory: string; expanded: boolean } }): JSX.Element => {
- const sortable = createSortable(props.project.directory)
- const [projectStore] = globalSync.child(props.project.directory)
- const slug = createMemo(() => base64Encode(props.project.directory))
- const name = createMemo(() => getFilename(props.project.directory))
+ const SortableProject = (props: { project: Project & { expanded: boolean } }): JSX.Element => {
+ const sortable = createSortable(props.project.worktree)
+ const [projectStore] = globalSync.child(props.project.worktree)
+ const slug = createMemo(() => base64Encode(props.project.worktree))
+ const name = createMemo(() => getFilename(props.project.worktree))
return (
// @ts-ignore
<div use:sortable classList={{ "opacity-30": sortable.isActiveDraggable }}>
@@ -194,11 +194,18 @@ export default function Layout(props: ParentProps) {
>
<Collapsible.Trigger class="group/trigger flex items-center gap-3 p-0 text-left min-w-0 grow border-none">
<div class="size-6 shrink-0">
- <Avatar
- fallback={name()}
- background="var(--surface-info-base)"
- class="size-full group-hover/session:hidden"
- />
+ <Switch>
+ <Match when={props.project.icon?.url}>
+ {(url) => <img src={url()} class="size-full group-hover/session:hidden" />}
+ </Match>
+ <Match when={true}>
+ <Avatar
+ fallback={name()}
+ background={props.project.icon?.color ?? "var(--surface-info-base)"}
+ class="size-full group-hover/session:hidden"
+ />
+ </Match>
+ </Switch>
<Icon
name="chevron-right"
size="large"
@@ -212,7 +219,7 @@ export default function Layout(props: ParentProps) {
<DropdownMenu.Trigger as={IconButton} icon="dot-grid" variant="ghost" />
<DropdownMenu.Portal>
<DropdownMenu.Content>
- <DropdownMenu.Item onSelect={() => closeProject(props.project.directory)}>
+ <DropdownMenu.Item onSelect={() => closeProject(props.project.worktree)}>
<DropdownMenu.ItemLabel>Close Project</DropdownMenu.ItemLabel>
</DropdownMenu.Item>
</DropdownMenu.Content>
@@ -274,8 +281,8 @@ export default function Layout(props: ParentProps) {
</Collapsible>
</Match>
<Match when={true}>
- <Tooltip placement="right" value={props.project.directory}>
- <ProjectVisual directory={props.project.directory} />
+ <Tooltip placement="right" value={props.project.worktree}>
+ <ProjectVisual directory={props.project.worktree} />
</Tooltip>
</Match>
</Switch>
@@ -315,7 +322,7 @@ export default function Layout(props: ParentProps) {
<div class="flex items-center gap-3">
<div class="flex items-center gap-2">
<Select
- options={layout.projects.list().map((project) => project.directory)}
+ options={layout.projects.list().map((project) => project.worktree)}
current={currentDirectory()}
label={(x) => getFilename(x)}
onSelect={(x) => (x ? navigateToProject(x) : undefined)}
@@ -443,7 +450,7 @@ export default function Layout(props: ParentProps) {
<DragDropSensors />
<ConstrainDragXAxis />
<div class="w-full min-w-8 flex flex-col gap-2 min-h-0 overflow-y-auto no-scrollbar">
- <SortableProvider ids={layout.projects.list().map((p) => p.directory)}>
+ <SortableProvider ids={layout.projects.list().map((p) => p.worktree)}>
<For each={layout.projects.list()}>{(project) => <SortableProject project={project} />}</For>
</SortableProvider>
</div>
diff --git a/packages/enterprise/src/core/share.ts b/packages/enterprise/src/core/share.ts
index a85994c31..d7f5c8b8d 100644
--- a/packages/enterprise/src/core/share.ts
+++ b/packages/enterprise/src/core/share.ts
@@ -1,4 +1,4 @@
-import { FileDiff, Message, Model, Part, Session, SessionStatus } from "@opencode-ai/sdk"
+import { FileDiff, Message, Model, Part, Session } from "@opencode-ai/sdk/v2"
import { fn } from "@opencode-ai/util/fn"
import { iife } from "@opencode-ai/util/iife"
import { Identifier } from "@opencode-ai/util/identifier"
diff --git a/packages/enterprise/src/routes/share/[shareID].tsx b/packages/enterprise/src/routes/share/[shareID].tsx
index a8b0ecf69..1c66624b1 100644
--- a/packages/enterprise/src/routes/share/[shareID].tsx
+++ b/packages/enterprise/src/routes/share/[shareID].tsx
@@ -1,4 +1,4 @@
-import { FileDiff, Message, Model, Part, Session, SessionStatus, UserMessage } from "@opencode-ai/sdk"
+import { FileDiff, Message, Model, Part, Session, SessionStatus, UserMessage } from "@opencode-ai/sdk/v2"
import { SessionTurn } from "@opencode-ai/ui/session-turn"
import { SessionReview } from "@opencode-ai/ui/session-review"
import { DataProvider } from "@opencode-ai/ui/context"
diff --git a/packages/ui/src/components/message-nav.tsx b/packages/ui/src/components/message-nav.tsx
index 1a1d2a1b5..29b465c8c 100644
--- a/packages/ui/src/components/message-nav.tsx
+++ b/packages/ui/src/components/message-nav.tsx
@@ -1,4 +1,4 @@
-import { UserMessage } from "@opencode-ai/sdk"
+import { UserMessage } from "@opencode-ai/sdk/v2"
import { ComponentProps, createMemo, For, Match, Show, splitProps, Switch } from "solid-js"
import { DiffChanges } from "./diff-changes"
import { Spinner } from "./spinner"
diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx
index 2da4387fd..a28e36aa8 100644
--- a/packages/ui/src/components/message-part.tsx
+++ b/packages/ui/src/components/message-part.tsx
@@ -7,7 +7,7 @@ import {
TextPart,
ToolPart,
UserMessage,
-} from "@opencode-ai/sdk"
+} from "@opencode-ai/sdk/v2"
import { useDiffComponent } from "../context/diff"
import { BasicTool } from "./basic-tool"
import { GenericTool } from "./basic-tool"
diff --git a/packages/ui/src/components/message-progress.tsx b/packages/ui/src/components/message-progress.tsx
index bbcdd3096..ef3548ab3 100644
--- a/packages/ui/src/components/message-progress.tsx
+++ b/packages/ui/src/components/message-progress.tsx
@@ -2,7 +2,7 @@ import { For, JSXElement, Match, Show, Switch, createEffect, createMemo, createS
import { Part } from "./message-part"
import { Spinner } from "./spinner"
import { useData } from "../context/data"
-import type { AssistantMessage as AssistantMessageType, ToolPart } from "@opencode-ai/sdk"
+import type { AssistantMessage as AssistantMessageType, ToolPart } from "@opencode-ai/sdk/v2"
export interface MessageProgressProps {
assistantMessages: () => AssistantMessageType[]
diff --git a/packages/ui/src/components/session-message-rail.tsx b/packages/ui/src/components/session-message-rail.tsx
index 29d9ac81e..132b813d2 100644
--- a/packages/ui/src/components/session-message-rail.tsx
+++ b/packages/ui/src/components/session-message-rail.tsx
@@ -1,4 +1,4 @@
-import { UserMessage } from "@opencode-ai/sdk"
+import { UserMessage } from "@opencode-ai/sdk/v2"
import { ComponentProps, Show, splitProps } from "solid-js"
import { MessageNav } from "./message-nav"
import "./session-message-rail.css"
diff --git a/packages/ui/src/components/session-review.tsx b/packages/ui/src/components/session-review.tsx
index cc82dcbd4..8009091b7 100644
--- a/packages/ui/src/components/session-review.tsx
+++ b/packages/ui/src/components/session-review.tsx
@@ -8,7 +8,7 @@ import { useDiffComponent } from "../context/diff"
import { getDirectory, getFilename } from "@opencode-ai/util/path"
import { For, Match, Show, Switch, type JSX } from "solid-js"
import { createStore } from "solid-js/store"
-import { type FileDiff } from "@opencode-ai/sdk"
+import { type FileDiff } from "@opencode-ai/sdk/v2"
import { PreloadMultiFileDiffResult } from "@pierre/precision-diffs/ssr"
import { Dynamic } from "solid-js/web"
import { checksum } from "@opencode-ai/util/encode"
diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx
index 5ca50a5cc..14ba77e26 100644
--- a/packages/ui/src/components/session-turn.tsx
+++ b/packages/ui/src/components/session-turn.tsx
@@ -1,4 +1,4 @@
-import { AssistantMessage } from "@opencode-ai/sdk"
+import { AssistantMessage } from "@opencode-ai/sdk/v2"
import { useData } from "../context"
import { useDiffComponent } from "../context/diff"
import { getDirectory, getFilename } from "@opencode-ai/util/path"
diff --git a/packages/ui/src/context/data.tsx b/packages/ui/src/context/data.tsx
index 728202a09..265178e10 100644
--- a/packages/ui/src/context/data.tsx
+++ b/packages/ui/src/context/data.tsx
@@ -1,4 +1,4 @@
-import type { Message, Session, Part, FileDiff, SessionStatus } from "@opencode-ai/sdk"
+import type { Message, Session, Part, FileDiff, SessionStatus } from "@opencode-ai/sdk/v2"
import { createSimpleContext } from "./helper"
import { PreloadMultiFileDiffResult } from "@pierre/precision-diffs/ssr"
diff --git a/packages/util/src/sanitize.ts b/packages/util/src/sanitize.ts
index 38ad2b290..4bb762393 100644
--- a/packages/util/src/sanitize.ts
+++ b/packages/util/src/sanitize.ts
@@ -1,4 +1,4 @@
-import type { Part } from "@opencode-ai/sdk/client"
+import type { Part } from "@opencode-ai/sdk/v2/client"
export const sanitize = (text: string | undefined, remove?: RegExp) => (remove ? text?.replace(remove, "") : text) ?? ""