Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/last-synced-tag
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1.0.174
v1.0.176
1 change: 1 addition & 0 deletions STATS.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,4 @@
| 2025-12-17 | 1,151,067 (+30,590) | 1,097,661 (+19,639) | 2,248,728 (+50,229) |
| 2025-12-18 | 1,178,658 (+27,591) | 1,113,418 (+15,757) | 2,292,076 (+43,348) |
| 2025-12-19 | 1,203,485 (+24,827) | 1,129,698 (+16,280) | 2,333,183 (+41,107) |
| 2025-12-20 | 1,223,000 (+19,515) | 1,146,258 (+16,560) | 2,369,258 (+36,075) |
84 changes: 39 additions & 45 deletions bun.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/console/app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-app",
"version": "1.0.174-1",
"version": "1.0.176",
"type": "module",
"scripts": {
"typecheck": "tsgo --noEmit",
Expand Down
8 changes: 8 additions & 0 deletions packages/console/app/src/component/icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,14 @@ export function IconZai(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
)
}

export function IconMiniMax(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
return (
<svg {...props} fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M16.278 2c1.156 0 2.093.927 2.093 2.07v12.501a.74.74 0 00.744.709.74.74 0 00.743-.709V9.099a2.06 2.06 0 012.071-2.049A2.06 2.06 0 0124 9.1v6.561a.649.649 0 01-.652.645.649.649 0 01-.653-.645V9.1a.762.762 0 00-.766-.758.762.762 0 00-.766.758v7.472a2.037 2.037 0 01-2.048 2.026 2.037 2.037 0 01-2.048-2.026v-12.5a.785.785 0 00-.788-.753.785.785 0 00-.789.752l-.001 15.904A2.037 2.037 0 0113.441 22a2.037 2.037 0 01-2.048-2.026V18.04c0-.356.292-.645.652-.645.36 0 .652.289.652.645v1.934c0 .263.142.506.372.638.23.131.514.131.744 0a.734.734 0 00.372-.638V4.07c0-1.143.937-2.07 2.093-2.07zm-5.674 0c1.156 0 2.093.927 2.093 2.07v11.523a.648.648 0 01-.652.645.648.648 0 01-.652-.645V4.07a.785.785 0 00-.789-.78.785.785 0 00-.789.78v14.013a2.06 2.06 0 01-2.07 2.048 2.06 2.06 0 01-2.071-2.048V9.1a.762.762 0 00-.766-.758.762.762 0 00-.766.758v3.8a2.06 2.06 0 01-2.071 2.049A2.06 2.06 0 010 12.9v-1.378c0-.357.292-.646.652-.646.36 0 .653.29.653.646V12.9c0 .418.343.757.766.757s.766-.339.766-.757V9.099a2.06 2.06 0 012.07-2.048 2.06 2.06 0 012.071 2.048v8.984c0 .419.343.758.767.758.423 0 .766-.339.766-.758V4.07c0-1.143.937-2.07 2.093-2.07z" />
</svg>
)
}

export function IconGemini(props: JSX.SvgSVGAttributes<SVGSVGElement>) {
return (
<svg {...props} viewBox="0 0 50 50" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
IconAlibaba,
IconAnthropic,
IconGemini,
IconMiniMax,
IconMoonshotAI,
IconOpenAI,
IconStealth,
Expand All @@ -23,6 +24,7 @@ const getModelLab = (modelId: string) => {
if (modelId.startsWith("kimi")) return "Moonshot AI"
if (modelId.startsWith("glm")) return "Z.ai"
if (modelId.startsWith("qwen")) return "Alibaba"
if (modelId.startsWith("minimax")) return "MiniMax"
if (modelId.startsWith("grok")) return "xAI"
return "Stealth"
}
Expand All @@ -35,7 +37,7 @@ const getModelsInfo = query(async (workspaceID: string) => {
.filter(([id, _model]) => !["claude-3-5-haiku"].includes(id))
.filter(([id, _model]) => !id.startsWith("alpha-"))
.sort(([idA, modelA], [idB, modelB]) => {
const priority = ["big-pickle", "grok", "claude", "gpt", "gemini"]
const priority = ["big-pickle", "minimax", "grok", "claude", "gpt", "gemini"]
const getPriority = (id: string) => {
const index = priority.findIndex((p) => id.startsWith(p))
return index === -1 ? Infinity : index
Expand Down Expand Up @@ -129,6 +131,8 @@ export function ModelSection() {
return <IconAlibaba width={16} height={16} />
case "xAI":
return <IconXai width={16} height={16} />
case "MiniMax":
return <IconMiniMax width={16} height={16} />
default:
return <IconStealth width={16} height={16} />
}
Expand Down
2 changes: 1 addition & 1 deletion packages/console/core/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
"version": "1.0.174-1",
"version": "1.0.176",
"private": true,
"type": "module",
"dependencies": {
Expand Down
2 changes: 1 addition & 1 deletion packages/console/function/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-function",
"version": "1.0.174-1",
"version": "1.0.176",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
Expand Down
2 changes: 1 addition & 1 deletion packages/console/mail/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-mail",
"version": "1.0.174-1",
"version": "1.0.176",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/desktop",
"version": "1.0.174-1",
"version": "1.0.176",
"description": "",
"type": "module",
"exports": {
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/src/context/global-sdk.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const { use: useGlobalSDK, provider: GlobalSDKProvider } = createSimpleCo

const eventSdk = createOpencodeClient({
baseUrl: props.url,
signal: AbortSignal.timeout(1000 * 60 * 10),
// signal: AbortSignal.timeout(1000 * 60 * 10),
fetch: platform.fetch,
throwOnError: true,
})
Expand Down
43 changes: 26 additions & 17 deletions packages/desktop/src/context/global-sync.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from "@opencode-ai/sdk/v2/client"
import { createStore, produce, reconcile } from "solid-js/store"
import { Binary } from "@opencode-ai/util/binary"
import { retry } from "@opencode-ai/util/retry"
import { useGlobalSDK } from "./global-sdk"
import { ErrorPage, type InitError } from "../pages/error"
import { createContext, useContext, onMount, type ParentProps, Switch, Match } from "solid-js"
Expand Down Expand Up @@ -145,7 +146,7 @@ function createGlobalSync() {
changes: () => sdk.file.status().then((x) => setStore("changes", x.data!)),
node: () => sdk.file.list({ path: "/" }).then((x) => setStore("node", x.data!)),
}
await Promise.all(Object.values(load).map((p) => p().catch((e) => setGlobalStore("error", e))))
await Promise.all(Object.values(load).map((p) => retry(p).catch((e) => setGlobalStore("error", e))))
.then(() => setStore("ready", true))
.catch((e) => setGlobalStore("error", e))
}
Expand Down Expand Up @@ -295,22 +296,30 @@ function createGlobalSync() {

async function bootstrap() {
return Promise.all([
globalSDK.client.path.get().then((x) => {
setGlobalStore("path", x.data!)
}),
globalSDK.client.project.list().then(async (x) => {
const data = Array.isArray(x.data) ? x.data : []
setGlobalStore(
"project",
data.filter((p) => !p.worktree.includes("opencode-test")).sort((a, b) => a.id.localeCompare(b.id)),
)
}),
globalSDK.client.provider.list().then((x) => {
setGlobalStore("provider", x.data ?? {})
}),
globalSDK.client.provider.auth().then((x) => {
setGlobalStore("provider_auth", x.data ?? {})
}),
retry(() =>
globalSDK.client.path.get().then((x) => {
setGlobalStore("path", x.data!)
}),
),
retry(() =>
globalSDK.client.project.list().then(async (x) => {
const data = Array.isArray(x.data) ? x.data : []
setGlobalStore(
"project",
data.filter((p) => !p.worktree.includes("opencode-test")).sort((a, b) => a.id.localeCompare(b.id)),
)
}),
),
retry(() =>
globalSDK.client.provider.list().then((x) => {
setGlobalStore("provider", x.data ?? {})
}),
),
retry(() =>
globalSDK.client.provider.auth().then((x) => {
setGlobalStore("provider_auth", x.data ?? {})
}),
),
])
.then(() => setGlobalStore("ready", true))
.catch((e) => setGlobalStore("error", e))
Expand Down
15 changes: 10 additions & 5 deletions packages/desktop/src/context/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ export function getAvatarColors(key?: string) {

type Dialog = "provider" | "model" | "connect"

export type LocalProject = Partial<Project> & { worktree: string; expanded: boolean }

export const { use: useLayout, provider: LayoutProvider } = createSimpleContext({
name: "Layout",
init: () => {
Expand Down Expand Up @@ -81,21 +83,22 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(

function enrich(project: { worktree: string; expanded: boolean }) {
const metadata = globalSync.data.project.find((x) => x.worktree === project.worktree)
if (!metadata) return []
return [
{
...project,
...metadata,
...(metadata ?? {}),
},
]
}

function colorize(project: Project & { expanded: boolean }) {
function colorize(project: LocalProject) {
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 } })
if (project.id) {
globalSdk.client.project.update({ projectID: project.id, icon: { color } })
}
return project
}

Expand Down Expand Up @@ -124,7 +127,9 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
projects: {
list,
open(directory: string) {
if (store.projects.find((x) => x.worktree === directory)) return
if (store.projects.find((x) => x.worktree === directory)) {
return
}
globalSync.project.loadSessions(directory)
setStore("projects", (x) => [{ worktree: directory, expanded: true }, ...x])
},
Expand Down
3 changes: 2 additions & 1 deletion packages/desktop/src/context/local.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
const load = async (path: string) => {
const relativePath = relative(path)
await sdk.client.file.read({ path: relativePath }).then((x) => {
if (!store.node[relativePath]) return
setStore(
"node",
relativePath,
Expand Down Expand Up @@ -425,7 +426,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
init,
expand(path: string) {
setStore("node", path, "expanded", true)
if (store.node[path].loaded) return
if (store.node[path]?.loaded) return
setStore("node", path, "loaded", true)
list(path)
},
Expand Down
9 changes: 5 additions & 4 deletions packages/desktop/src/context/sync.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { produce } from "solid-js/store"
import { createMemo } from "solid-js"
import { Binary } from "@opencode-ai/util/binary"
import { retry } from "@opencode-ai/util/retry"
import { createSimpleContext } from "@opencode-ai/ui/context"
import { useGlobalSync } from "./global-sync"
import { useSDK } from "./sdk"
Expand Down Expand Up @@ -85,10 +86,10 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({
},
async sync(sessionID: string, _isRetry = false) {
const [session, messages, todo, diff] = await Promise.all([
sdk.client.session.get({ sessionID }, { throwOnError: true }),
sdk.client.session.messages({ sessionID, limit: 100 }),
sdk.client.session.todo({ sessionID }),
sdk.client.session.diff({ sessionID }),
retry(() => sdk.client.session.get({ sessionID })),
retry(() => sdk.client.session.messages({ sessionID, limit: 100 })),
retry(() => sdk.client.session.todo({ sessionID })),
retry(() => sdk.client.session.diff({ sessionID })),
])
setStore(
produce((draft) => {
Expand Down
40 changes: 18 additions & 22 deletions packages/desktop/src/pages/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,7 @@
import {
createEffect,
createMemo,
createSignal,
For,
Match,
onCleanup,
onMount,
ParentProps,
Show,
Switch,
type JSX,
} from "solid-js"
import { createEffect, createMemo, For, Match, onCleanup, onMount, ParentProps, Show, Switch, type JSX } from "solid-js"
import { DateTime } from "luxon"
import { A, useNavigate, useParams } from "@solidjs/router"
import { useLayout, getAvatarColors } from "@/context/layout"
import { useLayout, getAvatarColors, LocalProject } from "@/context/layout"
import { useGlobalSync } from "@/context/global-sync"
import { base64Decode, base64Encode } from "@opencode-ai/util/encode"
import { AsciiLogo, AsciiMark } from "@opencode-ai/ui/logo"
Expand All @@ -31,7 +19,7 @@ import { DiffChanges } from "@opencode-ai/ui/diff-changes"
import { Spinner } from "@opencode-ai/ui/spinner"
import { getFilename } from "@opencode-ai/util/path"
import { DropdownMenu } from "@opencode-ai/ui/dropdown-menu"
import { Session, Project } from "@opencode-ai/sdk/v2/client"
import { Session } from "@opencode-ai/sdk/v2/client"
import { usePlatform } from "@/context/platform"
import { createStore, produce } from "solid-js/store"
import {
Expand Down Expand Up @@ -381,7 +369,7 @@ export default function Layout(props: ParentProps) {
}

const ProjectAvatar = (props: {
project: Project
project: LocalProject
class?: string
expandable?: boolean
notify?: boolean
Expand Down Expand Up @@ -424,7 +412,7 @@ export default function Layout(props: ParentProps) {
)
}

const ProjectVisual = (props: { project: Project & { expanded: boolean }; class?: string }): JSX.Element => {
const ProjectVisual = (props: { project: LocalProject; class?: string }): JSX.Element => {
const name = createMemo(() => getFilename(props.project.worktree))
const current = createMemo(() => base64Decode(params.dir ?? ""))
return (
Expand Down Expand Up @@ -460,7 +448,7 @@ export default function Layout(props: ParentProps) {
const SessionItem = (props: {
session: Session
slug: string
project: Project
project: LocalProject
depth?: number
childrenMap: Map<string, Session[]>
}): JSX.Element => {
Expand Down Expand Up @@ -550,7 +538,7 @@ export default function Layout(props: ParentProps) {
)
}

const SortableProject = (props: { project: Project & { expanded: boolean } }): JSX.Element => {
const SortableProject = (props: { project: LocalProject }): JSX.Element => {
const sortable = createSortable(props.project.worktree)
const slug = createMemo(() => base64Encode(props.project.worktree))
const name = createMemo(() => getFilename(props.project.worktree))
Expand All @@ -575,13 +563,21 @@ export default function Layout(props: ParentProps) {
setProjectStore("limit", (limit) => limit + 5)
await globalSync.project.loadSessions(props.project.worktree)
}
const [expanded, setExpanded] = createSignal(true)
const handleOpenChange = (open: boolean) => {
if (open) layout.projects.expand(props.project.worktree)
else layout.projects.collapse(props.project.worktree)
}
return (
// @ts-ignore
<div use:sortable classList={{ "opacity-30": sortable.isActiveDraggable }}>
<Switch>
<Match when={layout.sidebar.opened()}>
<Collapsible variant="ghost" defaultOpen class="gap-2 shrink-0" onOpenChange={setExpanded}>
<Collapsible
variant="ghost"
open={props.project.expanded}
class="gap-2 shrink-0"
onOpenChange={handleOpenChange}
>
<Button
as={"div"}
variant="ghost"
Expand All @@ -592,7 +588,7 @@ export default function Layout(props: ParentProps) {
project={props.project}
class="group-hover/session:hidden"
expandable
notify={!expanded()}
notify={!props.project.expanded}
/>
<span class="truncate text-14-medium text-text-strong">{name()}</span>
</Collapsible.Trigger>
Expand Down
2 changes: 1 addition & 1 deletion packages/enterprise/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/enterprise",
"version": "1.0.174-1",
"version": "1.0.176",
"private": true,
"type": "module",
"scripts": {
Expand Down
Loading
Loading