diff --git a/.opencode/opencode.jsonc b/.opencode/opencode.jsonc index dd5a4c750fb..f6501f3834e 100644 --- a/.opencode/opencode.jsonc +++ b/.opencode/opencode.jsonc @@ -1,9 +1,9 @@ { "$schema": "https://opencode.ai/config.json", "plugin": ["opencode-openai-codex-auth"], - // "enterprise": { - // "url": "http://localhost:3000", - // }, + "enterprise": { + "url": "http://localhost:3000", + }, "provider": { "opencode": { "options": { diff --git a/bun.lock b/bun.lock index 17d961b7328..5d505ae1c04 100644 --- a/bun.lock +++ b/bun.lock @@ -19,7 +19,7 @@ }, "packages/console/app": { "name": "@opencode-ai/console-app", - "version": "1.0.108", + "version": "1.0.109", "dependencies": { "@cloudflare/vite-plugin": "1.15.2", "@ibm/plex": "6.4.1", @@ -46,7 +46,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.108", + "version": "1.0.109", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -73,7 +73,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.108", + "version": "1.0.109", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -97,7 +97,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.108", + "version": "1.0.109", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -121,7 +121,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.108", + "version": "1.0.109", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -162,7 +162,7 @@ }, "packages/enterprise": { "name": "@opencode-ai/enterprise", - "version": "1.0.108", + "version": "1.0.109", "dependencies": { "@opencode-ai/ui": "workspace:*", "@opencode-ai/util": "workspace:*", @@ -188,7 +188,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.108", + "version": "1.0.109", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -204,7 +204,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.108", + "version": "1.0.109", "bin": { "opencode": "./bin/opencode", }, @@ -291,7 +291,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.108", + "version": "1.0.109", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -311,7 +311,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.108", + "version": "1.0.109", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -322,7 +322,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.108", + "version": "1.0.109", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -335,7 +335,7 @@ }, "packages/tauri": { "name": "@opencode-ai/tauri", - "version": "1.0.108", + "version": "1.0.109", "dependencies": { "@tauri-apps/api": "^2", "@tauri-apps/plugin-opener": "^2", @@ -348,7 +348,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.108", + "version": "1.0.109", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -380,7 +380,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "1.0.108", + "version": "1.0.109", "dependencies": { "zod": "catalog:", }, @@ -390,7 +390,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.108", + "version": "1.0.109", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 153c07c5843..d273a6fa3c9 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-app", - "version": "1.0.108", + "version": "1.0.109", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/console/app/public/favicon.svg b/packages/console/app/public/favicon.svg deleted file mode 100644 index bf8f9075d66..00000000000 --- a/packages/console/app/public/favicon.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/packages/console/app/public/favicon.svg b/packages/console/app/public/favicon.svg new file mode 120000 index 00000000000..9a9c41c9215 --- /dev/null +++ b/packages/console/app/public/favicon.svg @@ -0,0 +1 @@ +../../../ui/src/assets/favicon/favicon.svg \ No newline at end of file diff --git a/packages/console/app/src/component/icon.tsx b/packages/console/app/src/component/icon.tsx index 55f0940a061..a28fc51a3e0 100644 --- a/packages/console/app/src/component/icon.tsx +++ b/packages/console/app/src/component/icon.tsx @@ -202,7 +202,7 @@ export function IconZai(props: JSX.SvgSVGAttributes) { ) } -export function IconGoogle(props: JSX.SvgSVGAttributes) { +export function IconGemini(props: JSX.SvgSVGAttributes) { return ( diff --git a/packages/console/app/src/entry-server.tsx b/packages/console/app/src/entry-server.tsx index d5fca6aa560..7d86e4b2b2e 100644 --- a/packages/console/app/src/entry-server.tsx +++ b/packages/console/app/src/entry-server.tsx @@ -9,7 +9,7 @@ export default createHandler( - + {assets} diff --git a/packages/console/app/src/routes/index.tsx b/packages/console/app/src/routes/index.tsx index 89909744d64..1a41f0e6a0d 100644 --- a/packages/console/app/src/routes/index.tsx +++ b/packages/console/app/src/routes/index.tsx @@ -45,7 +45,6 @@ export default function Home() { {/**/} OpenCode | The AI coding agent built for the terminal -
diff --git a/packages/console/app/src/routes/workspace.tsx b/packages/console/app/src/routes/workspace.tsx index 35323da2832..f7aff5b4815 100644 --- a/packages/console/app/src/routes/workspace.tsx +++ b/packages/console/app/src/routes/workspace.tsx @@ -22,7 +22,7 @@ export default function WorkspaceLayout(props: RouteSectionProps) { const userEmail = createAsync(() => getUserEmail(params.id!)) return (
- +
diff --git a/packages/console/app/src/routes/workspace/[id]/model-section.tsx b/packages/console/app/src/routes/workspace/[id]/model-section.tsx index 8b88906671c..30815336d66 100644 --- a/packages/console/app/src/routes/workspace/[id]/model-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/model-section.tsx @@ -8,7 +8,7 @@ import { querySessionInfo } from "../common" import { IconAlibaba, IconAnthropic, - IconGoogle, + IconGemini, IconMoonshotAI, IconOpenAI, IconStealth, @@ -117,7 +117,7 @@ export function ModelSection() { case "Anthropic": return case "Google": - return + return case "Moonshot AI": return case "Z.ai": diff --git a/packages/console/app/src/routes/workspace/[id]/provider-section.tsx b/packages/console/app/src/routes/workspace/[id]/provider-section.tsx index ff2cc7dd03a..dbb170b6227 100644 --- a/packages/console/app/src/routes/workspace/[id]/provider-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/provider-section.tsx @@ -8,6 +8,7 @@ import styles from "./provider-section.module.css" const PROVIDERS = [ { name: "OpenAI", key: "openai", prefix: "sk-" }, { name: "Anthropic", key: "anthropic", prefix: "sk-ant-" }, + { name: "Google Gemini", key: "google", prefix: "AI" }, ] as const type Provider = (typeof PROVIDERS)[number] diff --git a/packages/console/app/src/routes/workspace/[id]/usage-section.tsx b/packages/console/app/src/routes/workspace/[id]/usage-section.tsx index 212904f3fa7..8ba5dfdbd16 100644 --- a/packages/console/app/src/routes/workspace/[id]/usage-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/usage-section.tsx @@ -50,6 +50,10 @@ export function UsageSection() { return u.inputTokens + (u.cacheReadTokens ?? 0) + (u.cacheWrite5mTokens ?? 0) + (u.cacheWrite1hTokens ?? 0) } + const calculateTotalOutputTokens = (u: Awaited>[0]) => { + return u.outputTokens + (u.reasoningTokens ?? 0) + } + const goPrev = async () => { const usage = await getUsageInfo(params.id!, store.page - 1) setStore({ @@ -95,8 +99,11 @@ export function UsageSection() { {(usage, index) => { const date = createMemo(() => new Date(usage.timeCreated)) const totalInputTokens = createMemo(() => calculateTotalInputTokens(usage)) - const breakdownId = `breakdown-${index()}` - const isOpen = createMemo(() => openBreakdownId() === breakdownId) + const totalOutputTokens = createMemo(() => calculateTotalOutputTokens(usage)) + const inputBreakdownId = `input-breakdown-${index()}` + const outputBreakdownId = `output-breakdown-${index()}` + const isInputOpen = createMemo(() => openBreakdownId() === inputBreakdownId) + const isOutputOpen = createMemo(() => openBreakdownId() === outputBreakdownId) const isClaude = usage.model.toLowerCase().includes("claude") return ( @@ -110,13 +117,13 @@ export function UsageSection() { data-slot="breakdown-button" onClick={(e) => { e.stopPropagation() - setOpenBreakdownId(isOpen() ? null : breakdownId) + setOpenBreakdownId(isInputOpen() ? null : inputBreakdownId) }} > setOpenBreakdownId(null)}>{totalInputTokens()} - +
e.stopPropagation()}>
Input @@ -136,7 +143,32 @@ export function UsageSection() {
- {usage.outputTokens} + +
e.stopPropagation()}> + + setOpenBreakdownId(null)}>{totalOutputTokens()} + +
e.stopPropagation()}> +
+ Output + {usage.outputTokens} +
+
+ Reasoning + {usage.reasoningTokens ?? 0} +
+
+
+
+ ${((usage.cost ?? 0) / 100000000).toFixed(4)} ) diff --git a/packages/console/app/src/routes/zen/index.tsx b/packages/console/app/src/routes/zen/index.tsx index 053f16e5f0c..0610efae44c 100644 --- a/packages/console/app/src/routes/zen/index.tsx +++ b/packages/console/app/src/routes/zen/index.tsx @@ -18,6 +18,7 @@ import { Legal } from "~/component/legal" import { Footer } from "~/component/footer" import { Header } from "~/component/header" import { getLastSeenWorkspaceID } from "../workspace/common" +import { IconGemini } from "~/component/icon" const checkLoggedIn = query(async () => { "use server" @@ -32,7 +33,7 @@ export default function Home() { {/**/} OpenCode Zen | A curated set of reliable optimized models for coding agents - + @@ -82,6 +83,9 @@ export default function Home() { />
+
+ +
1}> - + <> + + + ( - <> - - - - - {props.children} - - - - + + + + {props.children} + + )} > diff --git a/packages/enterprise/src/core/share.ts b/packages/enterprise/src/core/share.ts index a7dfbfdcc0d..c24077ec365 100644 --- a/packages/enterprise/src/core/share.ts +++ b/packages/enterprise/src/core/share.ts @@ -1,4 +1,4 @@ -import { FileDiff, Message, Part, Session, SessionStatus } from "@opencode-ai/sdk" +import { FileDiff, Message, Model, Part, Session, SessionStatus } from "@opencode-ai/sdk" import { fn } from "@opencode-ai/util/fn" import { iife } from "@opencode-ai/util/iife" import z from "zod" @@ -32,6 +32,10 @@ export namespace Share { type: z.literal("session_status"), data: z.custom(), }), + z.object({ + type: z.literal("model"), + data: z.custom(), + }), ]) export type Data = z.infer @@ -111,6 +115,9 @@ export namespace Share { case "session_status": await Storage.write(["share_data", input.share.id, "session_status"], item.data) break + case "model": + await Storage.write(["share_data", input.share.id, "model"], item.data) + break } }), ) diff --git a/packages/enterprise/src/entry-server.tsx b/packages/enterprise/src/entry-server.tsx index 9f6d3b42eed..f5755ffa3d3 100644 --- a/packages/enterprise/src/entry-server.tsx +++ b/packages/enterprise/src/entry-server.tsx @@ -8,7 +8,7 @@ export default createHandler(() => ( - + OpenCode {assets} diff --git a/packages/enterprise/src/routes/share/[sessionID].tsx b/packages/enterprise/src/routes/share/[sessionID].tsx index 0ff0482f170..e34cbcc7e13 100644 --- a/packages/enterprise/src/routes/share/[sessionID].tsx +++ b/packages/enterprise/src/routes/share/[sessionID].tsx @@ -1,17 +1,29 @@ -import { FileDiff, Message, Part, Session, SessionStatus, UserMessage } from "@opencode-ai/sdk" +import { FileDiff, Message, Model, Part, Session, SessionStatus, UserMessage } from "@opencode-ai/sdk" import { SessionTurn } from "@opencode-ai/ui/session-turn" import { SessionReview } from "@opencode-ai/ui/session-review" -import { DataProvider, useData } from "@opencode-ai/ui/context" +import { DataProvider } from "@opencode-ai/ui/context" import { createAsync, query, RouteDefinition, useParams } from "@solidjs/router" -import { createMemo, Show } from "solid-js" +import { createMemo, ErrorBoundary, For, Match, Show, Switch } from "solid-js" import { Share } from "~/core/share" import { Logo, Mark } from "@opencode-ai/ui/logo" import { IconButton } from "@opencode-ai/ui/icon-button" import { iife } from "@opencode-ai/util/iife" import { Binary } from "@opencode-ai/util/binary" +import { NamedError } from "@opencode-ai/util/error" import { DateTime } from "luxon" import { MessageNav } from "@opencode-ai/ui/message-nav" import { createStore } from "solid-js/store" +import z from "zod" +import NotFound from "../[...404]" +import { Tabs } from "@opencode-ai/ui/tabs" + +const SessionDataMissingError = NamedError.create( + "SessionDataMissingError", + z.object({ + sessionID: z.string(), + message: z.string().optional(), + }), +) const getData = query(async (sessionID) => { const data = await Share.data(sessionID) @@ -29,6 +41,9 @@ const getData = query(async (sessionID) => { part: { [messageID: string]: Part[] } + model: { + [sessionID: string]: Model[] + } } = { session: [], session_diff: { @@ -41,6 +56,7 @@ const getData = query(async (sessionID) => { }, message: {}, part: {}, + model: {}, } for (const item of data) { switch (item.type) { @@ -61,8 +77,13 @@ const getData = query(async (sessionID) => { result.part[item.data.messageID] = result.part[item.data.messageID] ?? [] result.part[item.data.messageID].push(item.data) break + case "model": + result.model[sessionID] = item.data + break } } + const match = Binary.search(result.session, sessionID!, (s) => s.id) + if (!match.found) throw new SessionDataMissingError({ sessionID }) return result }, "getShareData") @@ -73,126 +94,221 @@ export const route = { export default function () { const params = useParams() const data = createAsync(async () => { - if (!params.sessionID) return + if (!params.sessionID) throw new Error("Missing sessionID") return getData(params.sessionID) }) return ( - - {(data) => ( - - {iife(() => { - const data = useData() - const [store, setStore] = createStore({ - messageId: undefined as string | undefined, - }) - const match = createMemo(() => Binary.search(data.session, params.sessionID!, (s) => s.id)) - if (!match().found) throw new Error(`Session ${params.sessionID} not found`) - const info = createMemo(() => data.session[match().index]) - const messages = createMemo(() => - params.sessionID ? (data.message[params.sessionID]?.filter((m) => m.role === "user") ?? []) : [], - ) - const firstUserMessage = createMemo(() => messages().at(0)) - const activeMessage = createMemo( - () => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(), - ) - function setActiveMessage(message: UserMessage | undefined) { - if (message) { - setStore("messageId", message.id) - } else { - setStore("messageId", undefined) + { + return ( + + + + ) + }} + > + + {(data) => ( + + {iife(() => { + const [store, setStore] = createStore({ + messageId: undefined as string | undefined, + }) + const match = createMemo(() => Binary.search(data().session, params.sessionID!, (s) => s.id)) + if (!match().found) throw new Error(`Session ${params.sessionID} not found`) + const info = createMemo(() => data().session[match().index]) + const messages = createMemo(() => + params.sessionID + ? (data().message[params.sessionID]?.filter((m) => m.role === "user") ?? []).sort( + (a, b) => b.time.created - a.time.created, + ) + : [], + ) + const firstUserMessage = createMemo(() => messages().at(0)) + const activeMessage = createMemo( + () => messages().find((m) => m.id === store.messageId) ?? firstUserMessage(), + ) + function setActiveMessage(message: UserMessage | undefined) { + if (message) { + setStore("messageId", message.id) + } else { + setStore("messageId", undefined) + } } - } - const provider = createMemo(() => activeMessage()?.model?.providerID) - const model = createMemo(() => activeMessage()?.model?.modelID) - const diffs = createMemo(() => data.session_diff[params.sessionID!] ?? []) + const provider = createMemo(() => activeMessage()?.model?.providerID) + const modelID = createMemo(() => activeMessage()?.model?.modelID) + const model = createMemo(() => data().model[params.sessionID!]?.find((m) => m.id === modelID())) + const diffs = createMemo(() => data().session_diff[params.sessionID!] ?? []) - return ( -
-
- -
- - + const title = () => ( +
+
+
+ +
v{info().version}
+
+
+ +
{model()?.name ?? modelID()}
+
+
+ {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")} +
-
-
-
-
0, - "px-6 max-w-2xl": diffs().length === 0, - }} - > -
-
-
- -
v{info().version}
-
-
- -
{model()}
-
-
- {DateTime.fromMillis(info().time.created).toFormat("dd MMM yyyy, HH:mm")} -
-
-
{info().title}
-
-
- 1}> - - +
{info().title}
+
+ ) + + const turns = () => ( +
+ {title()} +
+ + {(message) => ( -
- -
-
-
+ messageID={message.id} + classes={{ + root: "min-w-0 w-full relative", + content: + "flex flex-col justify-between !overflow-visible [&_[data-slot=session-turn-message-header]]:top-[-32px]", + }} + /> + )} + +
+
+ +
+
+ ) + + return ( +
+
+
+ + + +
+
+ +
- -
- +
+
+ + + + + + + Session + + + 5 Files Changed + + + + {turns()} + + +
+ +
+
+
+
+ +
{turns()}
+
+
-
- ) - })} - - )} - + ) + })} + + )} + + ) } diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 2929c179da6..c6cbc24363e 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The AI coding agent built for the terminal" -version = "1.0.108" +version = "1.0.109" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/sst/opencode" @@ -11,26 +11,26 @@ name = "OpenCode" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.108/opencode-darwin-arm64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.109/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.108/opencode-darwin-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.109/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.108/opencode-linux-arm64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.109/opencode-linux-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.108/opencode-linux-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.109/opencode-linux-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.108/opencode-windows-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.109/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index f40b10a7abe..e887ec5be10 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.108", + "version": "1.0.109", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 595a99255f4..a17f226a729 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.108", + "version": "1.0.109", "name": "opencode", "type": "module", "private": true, diff --git a/packages/opencode/src/bun/index.ts b/packages/opencode/src/bun/index.ts index 7c19c303b0e..edf74c31097 100644 --- a/packages/opencode/src/bun/index.ts +++ b/packages/opencode/src/bun/index.ts @@ -2,7 +2,7 @@ import z from "zod" import { Global } from "../global" import { Log } from "../util/log" import path from "path" -import { NamedError } from "../util/error" +import { NamedError } from "@opencode-ai/util/error" import { readableStreamToText } from "bun" import { createRequire } from "module" import { Lock } from "../util/lock" diff --git a/packages/opencode/src/cli/cmd/models.ts b/packages/opencode/src/cli/cmd/models.ts index f7da2462a9f..8ce27c28472 100644 --- a/packages/opencode/src/cli/cmd/models.ts +++ b/packages/opencode/src/cli/cmd/models.ts @@ -1,6 +1,7 @@ import type { Argv } from "yargs" import { Instance } from "../../project/instance" import { Provider } from "../../provider/provider" +import { ModelsDev } from "../../provider/models" import { cmd } from "./cmd" import { UI } from "../ui" import { EOL } from "os" @@ -19,8 +20,17 @@ export const ModelsCommand = cmd({ describe: "use more verbose model output (includes metadata like costs)", type: "boolean", }) + .option("refresh", { + describe: "refresh the models cache from models.dev", + type: "boolean", + }) }, handler: async (args) => { + if (args.refresh) { + await ModelsDev.refresh() + UI.println(UI.Style.TEXT_SUCCESS_BOLD + "Models cache refreshed" + UI.Style.TEXT_NORMAL) + } + await Instance.provide({ directory: process.cwd(), async fn() { diff --git a/packages/opencode/src/cli/ui.ts b/packages/opencode/src/cli/ui.ts index 43760a65af5..acd1383a070 100644 --- a/packages/opencode/src/cli/ui.ts +++ b/packages/opencode/src/cli/ui.ts @@ -1,6 +1,6 @@ import z from "zod" import { EOL } from "os" -import { NamedError } from "../util/error" +import { NamedError } from "@opencode-ai/util/error" export namespace UI { const LOGO = [ diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index cdf9ce04bda..8a670174db0 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -8,7 +8,7 @@ import { mergeDeep, pipe } from "remeda" import { Global } from "../global" import fs from "fs/promises" import { resolveGlobalFile } from "./global-file" -import { NamedError } from "../util/error" +import { NamedError } from "@opencode-ai/util/error" import { Flag } from "../flag/flag" import { Auth } from "../auth" import { type ParseError as JsoncParseError, parse as parseJsonc, printParseErrorCode } from "jsonc-parser" diff --git a/packages/opencode/src/config/error.ts b/packages/opencode/src/config/error.ts index b0f1bfda450..37ec31f5123 100644 --- a/packages/opencode/src/config/error.ts +++ b/packages/opencode/src/config/error.ts @@ -1,5 +1,5 @@ import z from "zod" -import { NamedError } from "@/util/error" +import { NamedError } from "@opencode-ai/util/error" export const ConfigUpdateError = NamedError.create( "ConfigUpdateError", diff --git a/packages/opencode/src/config/markdown.ts b/packages/opencode/src/config/markdown.ts index 3e84bbf43f7..f20842c41a9 100644 --- a/packages/opencode/src/config/markdown.ts +++ b/packages/opencode/src/config/markdown.ts @@ -1,4 +1,4 @@ -import { NamedError } from "@/util/error" +import { NamedError } from "@opencode-ai/util/error" import matter from "gray-matter" import { z } from "zod" diff --git a/packages/opencode/src/file/fzf.ts b/packages/opencode/src/file/fzf.ts index cd0aa4fc8e3..50db8901d70 100644 --- a/packages/opencode/src/file/fzf.ts +++ b/packages/opencode/src/file/fzf.ts @@ -2,7 +2,7 @@ import path from "path" import { Global } from "../global" import fs from "fs/promises" import z from "zod" -import { NamedError } from "../util/error" +import { NamedError } from "@opencode-ai/util/error" import { lazy } from "../util/lazy" import { Log } from "../util/log" import { ZipReader, BlobReader, BlobWriter } from "@zip.js/zip.js" diff --git a/packages/opencode/src/file/ripgrep.ts b/packages/opencode/src/file/ripgrep.ts index 7c871fafba2..00d9e8c3867 100644 --- a/packages/opencode/src/file/ripgrep.ts +++ b/packages/opencode/src/file/ripgrep.ts @@ -3,7 +3,7 @@ import path from "path" import { Global } from "../global" import fs from "fs/promises" import z from "zod" -import { NamedError } from "../util/error" +import { NamedError } from "@opencode-ai/util/error" import { lazy } from "../util/lazy" import { $ } from "bun" diff --git a/packages/opencode/src/ide/index.ts b/packages/opencode/src/ide/index.ts index 035bccecfb9..268f115fc30 100644 --- a/packages/opencode/src/ide/index.ts +++ b/packages/opencode/src/ide/index.ts @@ -1,6 +1,6 @@ import { spawn } from "bun" import z from "zod" -import { NamedError } from "../util/error" +import { NamedError } from "@opencode-ai/util/error" import { Log } from "../util/log" import { Bus } from "../bus" diff --git a/packages/opencode/src/index.ts b/packages/opencode/src/index.ts index acd7ee1c099..38b6b5a3f0b 100644 --- a/packages/opencode/src/index.ts +++ b/packages/opencode/src/index.ts @@ -9,7 +9,7 @@ import { UpgradeCommand } from "./cli/cmd/upgrade" import { ModelsCommand } from "./cli/cmd/models" import { UI } from "./cli/ui" import { Installation } from "./installation" -import { NamedError } from "./util/error" +import { NamedError } from "@opencode-ai/util/error" import { FormatError } from "./cli/error" import { ServeCommand } from "./cli/cmd/serve" import { DebugCommand } from "./cli/cmd/debug" diff --git a/packages/opencode/src/installation/index.ts b/packages/opencode/src/installation/index.ts index cfb590013c2..7ac2980c46a 100644 --- a/packages/opencode/src/installation/index.ts +++ b/packages/opencode/src/installation/index.ts @@ -1,7 +1,7 @@ import path from "path" import { $ } from "bun" import z from "zod" -import { NamedError } from "../util/error" +import { NamedError } from "@opencode-ai/util/error" import { Bus } from "../bus" import { Log } from "../util/log" diff --git a/packages/opencode/src/lsp/client.ts b/packages/opencode/src/lsp/client.ts index 02363a599ca..f8b7db7aebe 100644 --- a/packages/opencode/src/lsp/client.ts +++ b/packages/opencode/src/lsp/client.ts @@ -6,7 +6,7 @@ import { LANGUAGE_EXTENSIONS } from "./language" import { Bus } from "../bus" import z from "zod" import type { LSPServer } from "./server" -import { NamedError } from "../util/error" +import { NamedError } from "@opencode-ai/util/error" import { withTimeout } from "../util/timeout" import { Instance } from "../project/instance" diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts index 4b94c38daeb..15965c6e5c8 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -5,7 +5,7 @@ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js" import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js" import { Config } from "../config/config" import { Log } from "../util/log" -import { NamedError } from "../util/error" +import { NamedError } from "@opencode-ai/util/error" import z from "zod/v4" import { Instance } from "../project/instance" import { State } from "../project/state" diff --git a/packages/opencode/src/provider/auth.ts b/packages/opencode/src/provider/auth.ts index fb001603936..d06253ab4ad 100644 --- a/packages/opencode/src/provider/auth.ts +++ b/packages/opencode/src/provider/auth.ts @@ -4,7 +4,7 @@ import { map, filter, pipe, fromEntries, mapValues } from "remeda" import z from "zod" import { fn } from "@/util/fn" import type { AuthOuathResult, Hooks } from "@opencode-ai/plugin" -import { NamedError } from "@/util/error" +import { NamedError } from "@opencode-ai/util/error" import { Auth } from "@/auth" export namespace ProviderAuth { diff --git a/packages/opencode/src/provider/provider.ts b/packages/opencode/src/provider/provider.ts index cd8fb83091e..8c762832450 100644 --- a/packages/opencode/src/provider/provider.ts +++ b/packages/opencode/src/provider/provider.ts @@ -7,7 +7,7 @@ import { Log } from "../util/log" import { BunProc } from "../bun" import { Plugin } from "../plugin" import { ModelsDev } from "./models" -import { NamedError } from "../util/error" +import { NamedError } from "@opencode-ai/util/error" import { Auth } from "../auth" import { Instance } from "../project/instance" import { State } from "../project/state" diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index eac7212e7ec..781ded8ad9c 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -9,7 +9,7 @@ import { Session } from "../session" import z from "zod" import { Provider } from "../provider/provider" import { mapValues } from "remeda" -import { NamedError } from "../util/error" +import { NamedError } from "@opencode-ai/util/error" import { ModelsDev } from "../provider/models" import { Ripgrep } from "../file/ripgrep" import { Config } from "../config/config" diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index e9e6d5e72d8..28e6f15107c 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -1,6 +1,6 @@ import z from "zod" import { Bus } from "../bus" -import { NamedError } from "../util/error" +import { NamedError } from "@opencode-ai/util/error" import { Message } from "./message" import { APICallError, convertToModelMessages, LoadAPIKeyError, type ModelMessage, type UIMessage } from "ai" import { Identifier } from "../id/id" diff --git a/packages/opencode/src/session/message.ts b/packages/opencode/src/session/message.ts index 4471f923592..5c950d0e402 100644 --- a/packages/opencode/src/session/message.ts +++ b/packages/opencode/src/session/message.ts @@ -1,5 +1,5 @@ import z from "zod" -import { NamedError } from "../util/error" +import { NamedError } from "@opencode-ai/util/error" export namespace Message { export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({})) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index ef1e07a4c6e..4fb8f4674dc 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -43,7 +43,7 @@ import { Command } from "../command" import { $, fileURLToPath } from "bun" import { ConfigMarkdown } from "../config/markdown" import { SessionSummary } from "./summary" -import { NamedError } from "@/util/error" +import { NamedError } from "@opencode-ai/util/error" import { fn } from "@/util/fn" import { SessionProcessor } from "./processor" import { TaskTool } from "@/tool/task" diff --git a/packages/opencode/src/share/share-next.ts b/packages/opencode/src/share/share-next.ts index 99269a50f97..b16c793cbb1 100644 --- a/packages/opencode/src/share/share-next.ts +++ b/packages/opencode/src/share/share-next.ts @@ -1,5 +1,7 @@ import { Bus } from "@/bus" import { Config } from "@/config/config" +import type { ModelsDev } from "@/provider/models" +import { Provider } from "@/provider/provider" import { Session } from "@/session" import { MessageV2 } from "@/session/message-v2" import { Storage } from "@/storage/storage" @@ -26,6 +28,18 @@ export namespace ShareNext { data: evt.properties.info, }, ]) + if (evt.properties.info.role === "user") { + await sync(evt.properties.info.sessionID, [ + { + type: "model", + data: [ + await Provider.getModel(evt.properties.info.model.providerID, evt.properties.info.model.modelID).then( + (m) => m.info, + ), + ], + }, + ]) + } }) Bus.subscribe(MessageV2.Event.PartUpdated, async (evt) => { await sync(evt.properties.part.sessionID, [ @@ -90,6 +104,10 @@ export namespace ShareNext { type: "session_diff" data: SDK.FileDiff[] } + | { + type: "model" + data: ModelsDev.Model[] + } async function sync(sessionID: string, data: Data[]) { const url = await Config.get().then((x) => x.enterprise!.url) @@ -129,6 +147,12 @@ export namespace ShareNext { const session = await Session.get(sessionID) const diffs = await Session.diff(sessionID) const messages = await Array.fromAsync(MessageV2.stream(sessionID)) + const models = await Promise.all( + messages + .filter((m) => m.info.role === "user") + .map((m) => (m.info as SDK.UserMessage).model) + .map((m) => Provider.getModel(m.providerID, m.modelID).then((m) => m.info)), + ) await sync(sessionID, [ { type: "session", @@ -143,6 +167,10 @@ export namespace ShareNext { type: "session_diff", data: diffs, }, + { + type: "model", + data: models, + }, ]) } } diff --git a/packages/opencode/src/storage/storage.ts b/packages/opencode/src/storage/storage.ts index 5d4f639431d..8b4042ea13f 100644 --- a/packages/opencode/src/storage/storage.ts +++ b/packages/opencode/src/storage/storage.ts @@ -5,7 +5,7 @@ import { Global } from "../global" import { lazy } from "../util/lazy" import { Lock } from "../util/lock" import { $ } from "bun" -import { NamedError } from "@/util/error" +import { NamedError } from "@opencode-ai/util/error" import z from "zod" export namespace Storage { diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 264df7b5a27..d1a80371122 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.108", + "version": "1.0.109", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 02474c3e6f2..5696b0c31b4 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.108", + "version": "1.0.109", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", diff --git a/packages/slack/package.json b/packages/slack/package.json index 99fe097ae3e..37f939aa46e 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.108", + "version": "1.0.109", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/tauri/package.json b/packages/tauri/package.json index b14db25bbb2..481d9e4cfba 100644 --- a/packages/tauri/package.json +++ b/packages/tauri/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/tauri", "private": true, - "version": "1.0.108", + "version": "1.0.109", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/ui/package.json b/packages/ui/package.json index 57a8319e3ee..193e69d270e 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.108", + "version": "1.0.109", "type": "module", "exports": { "./*": "./src/components/*.tsx", diff --git a/packages/ui/src/assets/fonts/tx-02.otf b/packages/ui/src/assets/fonts/tx-02.otf new file mode 100644 index 00000000000..dfdd2800bea Binary files /dev/null and b/packages/ui/src/assets/fonts/tx-02.otf differ diff --git a/packages/ui/src/assets/fonts/tx-02.ttf b/packages/ui/src/assets/fonts/tx-02.ttf new file mode 100644 index 00000000000..dcad94c2166 Binary files /dev/null and b/packages/ui/src/assets/fonts/tx-02.ttf differ diff --git a/packages/ui/src/assets/fonts/tx-02.woff2 b/packages/ui/src/assets/fonts/tx-02.woff2 new file mode 100644 index 00000000000..d18fc391296 Binary files /dev/null and b/packages/ui/src/assets/fonts/tx-02.woff2 differ diff --git a/packages/ui/src/components/fonts.tsx b/packages/ui/src/components/fonts.tsx index ff4fb758896..0b28e8f3c25 100644 --- a/packages/ui/src/components/fonts.tsx +++ b/packages/ui/src/components/fonts.tsx @@ -1,6 +1,6 @@ import { Style, Link } from "@solidjs/meta" import geist from "../assets/fonts/geist.woff2" -import geistMono from "../assets/fonts/geist-mono.woff2" +import tx02 from "../assets/fonts/tx-02.woff2" export const Fonts = () => { return ( @@ -22,14 +22,14 @@ export const Fonts = () => { line-gap-override: 1%; } @font-face { - font-family: "Geist Mono"; - src: url("${geistMono}") format("woff2-variations"); + font-family: "Berkeley Mono"; + src: url("${tx02}") format("woff2-variations"); font-display: swap; font-style: normal; - font-weight: 100 900; + font-weight: 400 700; } @font-face { - font-family: "Geist Mono Fallback"; + font-family: "Berkeley Mono Fallback"; src: local("Courier New"); size-adjust: 100%; ascent-override: 97%; @@ -38,7 +38,7 @@ export const Fonts = () => { } `} - + ) } diff --git a/packages/ui/src/components/message-nav.css b/packages/ui/src/components/message-nav.css index 6e9d96a2604..57316fbde85 100644 --- a/packages/ui/src/components/message-nav.css +++ b/packages/ui/src/components/message-nav.css @@ -1,6 +1,4 @@ [data-component="message-nav"] { - /* margin-right: 32px; */ - /* margin-top: 12px; */ flex-shrink: 0; display: flex; flex-direction: column; @@ -9,15 +7,8 @@ list-style: none; &[data-size="normal"] { - position: absolute; - right: 100%; width: 240px; - /* margin-top: 12px; */ - - @media (min-width: 80rem) { - gap: 8px; - /* margin-top: 4px; */ - } + gap: 4px; } } @@ -36,10 +27,8 @@ display: flex; align-items: center; justify-content: flex-start; - height: 8px; - width: 32px; - /* margin-right: -12px; */ - cursor: pointer; + height: 12px; + width: 24px; border: none; background: none; padding: 0; @@ -52,7 +41,7 @@ [data-slot="message-nav-tick-line"] { height: 1px; - width: 20px; + width: 16px; background-color: var(--icon-base); transition: width 0.2s, @@ -69,11 +58,12 @@ align-items: center; align-self: stretch; width: 100%; - column-gap: 8px; + column-gap: 12px; cursor: default; border: none; background: none; - padding: 0; + padding: 4px 12px; + border-radius: var(--radius-sm); } [data-slot="message-nav-title-preview"] { @@ -90,6 +80,37 @@ } } -[data-slot="message-nav-item"]:hover [data-slot="message-nav-title-preview"] { +[data-slot="message-nav-item"]:hover [data-slot="message-nav-message-button"] { + background-color: var(--surface-base); +} +[data-slot="message-nav-item"]:active [data-slot="message-nav-message-button"] { + background-color: var(--surface-base-active); +} + +[data-slot="message-nav-item"]:active [data-slot="message-nav-title-preview"] { color: var(--text-base); } + +[data-slot="message-nav-tooltip"] { + z-index: 1000; +} + +[data-slot="message-nav-tooltip-content"] { + display: flex; + padding: 4px 4px 6px 4px; + justify-content: center; + align-items: center; + border-radius: var(--radius-md); + background: var(--surface-raised-stronger-non-alpha); + + /* border/shadow-xs/base */ + box-shadow: + 0 0 0 1px var(--border-weak-base, rgba(17, 0, 0, 0.12)), + 0 1px 2px -1px rgba(19, 16, 16, 0.04), + 0 1px 2px 0 rgba(19, 16, 16, 0.06), + 0 1px 3px 0 rgba(19, 16, 16, 0.08); + + * { + margin: 0 !important; + } +} diff --git a/packages/ui/src/components/message-nav.tsx b/packages/ui/src/components/message-nav.tsx index 8475c320643..9d56ce1a668 100644 --- a/packages/ui/src/components/message-nav.tsx +++ b/packages/ui/src/components/message-nav.tsx @@ -2,6 +2,7 @@ import { UserMessage } from "@opencode-ai/sdk" import { ComponentProps, createMemo, For, Match, Show, splitProps, Switch } from "solid-js" import { DiffChanges } from "./diff-changes" import { Spinner } from "./spinner" +import { Tooltip } from "@kobalte/core/tooltip" export function MessageNav( props: ComponentProps<"ul"> & { @@ -17,7 +18,7 @@ export function MessageNav( return local.messages?.at(0) }) - return ( + const content = () => (
    {(message) => { @@ -28,13 +29,9 @@ export function MessageNav(
  • - +