Compare commits

..
Author SHA1 Message Date
Aaron Iker b30c91de78 Merge branch 'dev' into update-design-subscriptions 2026-01-15 22:18:51 +01:00
Aaron Iker 2a22111b5e fix: small style adjustments, light rays params 2026-01-15 22:16:58 +01:00
Github Action 50badbd779 Update aarch64-darwin hash 2026-01-15 20:41:35 +00:00
Github Action 87eebad14e Update Nix flake.lock and x86_64-linux hash 2026-01-15 20:30:52 +00:00
Aaron Iker e258662178 Merge branch 'dev' into update-design-subscriptions 2026-01-15 21:28:10 +01:00
Aaron Iker 591f54cd0d feat: light rays improvement, mobile styles 2026-01-15 21:26:46 +01:00
Aaron Iker fdea599939 Merge branch 'update-design-subscriptions' of https://github.com/anomalyco/opencode into update-design-subscriptions 2026-01-15 21:15:07 +01:00
Aaron Iker ccac97c7c4 feat: transition improvements 2026-01-15 20:23:22 +01:00
Github Action 57b457f568 Update aarch64-darwin hash 2026-01-15 18:22:50 +00:00
Github Action 08068c3b91 Update Nix flake.lock and x86_64-linux hash 2026-01-15 18:13:32 +00:00
Aaron Iker 64edbb6b82 fix: webgp buffer 2026-01-15 19:12:17 +01:00
Aaron Iker 864f7ce129 feat: small style fixes, webgpu types 2026-01-15 19:08:24 +01:00
Aaron Iker 977827c9a4 feat: refacor light rays to WEBGPU 2026-01-15 19:08:08 +01:00
Aaron Iker d8b8854795 feat: remove ogl, add webgpu types 2026-01-15 19:07:51 +01:00
Aaron Iker d79dc295fd Merge branch 'update-design-subscriptions' of https://github.com/anomalyco/opencode into update-design-subscriptions 2026-01-15 18:24:03 +01:00
Aaron Iker abadacdce7 feat: small light rays tweaks 2026-01-15 18:22:12 +01:00
Github Action bd5a9002a8 Update aarch64-darwin hash 2026-01-15 17:19:44 +00:00
Github Action ecf33a72c3 Update Nix flake.lock and x86_64-linux hash 2026-01-15 17:12:46 +00:00
Aaron Iker f2711bf5ae Merge branch 'dev' into update-design-subscriptions 2026-01-15 18:12:20 +01:00
Aaron Iker 769c34c94f fix: desktop shellOpen 2026-01-15 18:11:34 +01:00
Aaron Iker ad33807627 feat: update select plan UI 2026-01-15 17:52:59 +01:00
Aaron Iker cf4fe5dc82 add light rays 2026-01-15 17:52:48 +01:00
Aaron Iker 56a7fbe131 feat: add ogl 2026-01-15 17:52:31 +01:00
Aaron Iker 3bc995dbe1 feat: restore former layout 2026-01-15 10:56:39 +01:00
34 changed files with 118 additions and 758 deletions
+34 -39
View File
@@ -17,11 +17,11 @@ on:
- "packages/*/package.json"
jobs:
update-flake:
update-linux:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
runs-on: blacksmith-4vcpu-ubuntu-2404
env:
TITLE: flake.lock
SYSTEM: x86_64-linux
steps:
- name: Checkout repository
@@ -33,32 +33,39 @@ jobs:
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
- name: Setup Nix
uses: nixbuild/nix-quick-install-action@v34
uses: DeterminateSystems/nix-installer-action@v20
- name: Configure git
run: |
git config --global user.email "action@github.com"
git config --global user.name "Github Action"
- name: Update ${{ env.TITLE }}
- name: Update flake.lock
run: |
set -euo pipefail
echo "📦 Updating $TITLE..."
echo "📦 Updating flake.lock..."
nix flake update
echo "✅ $TITLE updated successfully"
echo "✅ flake.lock updated successfully"
- name: Commit ${{ env.TITLE }} changes
- name: Update node_modules hash for x86_64-linux
run: |
set -euo pipefail
echo "🔄 Updating node_modules hash for x86_64-linux..."
nix/scripts/update-hashes.sh
echo "✅ node_modules hash for x86_64-linux updated successfully"
- name: Commit Linux hash changes
env:
TARGET_BRANCH: ${{ github.head_ref || github.ref_name }}
run: |
set -euo pipefail
echo "🔍 Checking for changes in tracked files..."
echo "🔍 Checking for changes in tracked Nix files..."
summarize() {
local status="$1"
{
echo "### Nix $TITLE"
echo "### Nix Hash Update (x86_64-linux)"
echo ""
echo "- ref: ${GITHUB_REF_NAME}"
echo "- status: ${status}"
@@ -68,10 +75,11 @@ jobs:
fi
echo "" >> "$GITHUB_STEP_SUMMARY"
}
FILES=(flake.lock flake.nix)
FILES=(flake.lock flake.nix nix/node-modules.nix nix/hashes.json)
STATUS="$(git status --short -- "${FILES[@]}" || true)"
if [ -z "$STATUS" ]; then
echo "✅ No changes detected."
echo "✅ No changes detected. Hashes are already up to date."
summarize "no changes"
exit 0
fi
@@ -81,7 +89,7 @@ jobs:
echo "🔗 Staging files..."
git add "${FILES[@]}"
echo "💾 Committing changes..."
git commit -m "Update $TITLE"
git commit -m "Update Nix flake.lock and x86_64-linux hash"
echo "✅ Changes committed"
BRANCH="${TARGET_BRANCH:-${GITHUB_REF_NAME}}"
@@ -93,25 +101,12 @@ jobs:
summarize "committed $(git rev-parse --short HEAD)"
update-node-modules-hash:
needs: update-flake
update-macos:
needs: update-linux
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
strategy:
fail-fast: false
matrix:
include:
- system: x86_64-linux
host: ubuntu-latest
- system: aarch64-linux
host: ubuntu-22.04-arm
- system: x86_64-darwin
host: macos-15-intel
- system: aarch64-darwin
host: macos-latest
runs-on: ${{ matrix.host }}
runs-on: macos-latest
env:
SYSTEM: ${{ matrix.system }}
TITLE: node_modules hash (${{ matrix.system }})
SYSTEM: aarch64-darwin
steps:
- name: Checkout repository
@@ -123,7 +118,7 @@ jobs:
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
- name: Setup Nix
uses: nixbuild/nix-quick-install-action@v34
uses: DeterminateSystems/nix-installer-action@v20
- name: Configure git
run: |
@@ -137,25 +132,25 @@ jobs:
BRANCH="${TARGET_BRANCH:-${GITHUB_REF_NAME}}"
git pull origin "$BRANCH"
- name: Update ${{ env.TITLE }}
- name: Update node_modules hash for aarch64-darwin
run: |
set -euo pipefail
echo "🔄 Updating $TITLE..."
echo "🔄 Updating node_modules hash for aarch64-darwin..."
nix/scripts/update-hashes.sh
echo "✅ $TITLE updated successfully"
echo "✅ node_modules hash for aarch64-darwin updated successfully"
- name: Commit ${{ env.TITLE }} changes
- name: Commit macOS hash changes
env:
TARGET_BRANCH: ${{ github.head_ref || github.ref_name }}
run: |
set -euo pipefail
echo "🔍 Checking for changes in tracked files..."
echo "🔍 Checking for changes in tracked Nix files..."
summarize() {
local status="$1"
{
echo "### Nix $TITLE"
echo "### Nix Hash Update (aarch64-darwin)"
echo ""
echo "- ref: ${GITHUB_REF_NAME}"
echo "- status: ${status}"
@@ -169,7 +164,7 @@ jobs:
FILES=(nix/hashes.json)
STATUS="$(git status --short -- "${FILES[@]}" || true)"
if [ -z "$STATUS" ]; then
echo "✅ No changes detected."
echo "✅ No changes detected. Hash is already up to date."
summarize "no changes"
exit 0
fi
@@ -179,7 +174,7 @@ jobs:
echo "🔗 Staging files..."
git add "${FILES[@]}"
echo "💾 Committing changes..."
git commit -m "Update $TITLE"
git commit -m "Update aarch64-darwin hash"
echo "✅ Changes committed"
BRANCH="${TARGET_BRANCH:-${GITHUB_REF_NAME}}"
+15 -15
View File
@@ -22,7 +22,7 @@
},
"packages/app": {
"name": "@opencode-ai/app",
"version": "1.1.23",
"version": "1.1.21",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/sdk": "workspace:*",
@@ -70,7 +70,7 @@
},
"packages/console/app": {
"name": "@opencode-ai/console-app",
"version": "1.1.23",
"version": "1.1.21",
"dependencies": {
"@cloudflare/vite-plugin": "1.15.2",
"@ibm/plex": "6.4.1",
@@ -102,7 +102,7 @@
},
"packages/console/core": {
"name": "@opencode-ai/console-core",
"version": "1.1.23",
"version": "1.1.21",
"dependencies": {
"@aws-sdk/client-sts": "3.782.0",
"@jsx-email/render": "1.1.1",
@@ -129,7 +129,7 @@
},
"packages/console/function": {
"name": "@opencode-ai/console-function",
"version": "1.1.23",
"version": "1.1.21",
"dependencies": {
"@ai-sdk/anthropic": "2.0.0",
"@ai-sdk/openai": "2.0.2",
@@ -153,7 +153,7 @@
},
"packages/console/mail": {
"name": "@opencode-ai/console-mail",
"version": "1.1.23",
"version": "1.1.21",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
@@ -177,7 +177,7 @@
},
"packages/desktop": {
"name": "@opencode-ai/desktop",
"version": "1.1.23",
"version": "1.1.21",
"dependencies": {
"@opencode-ai/app": "workspace:*",
"@opencode-ai/ui": "workspace:*",
@@ -206,7 +206,7 @@
},
"packages/enterprise": {
"name": "@opencode-ai/enterprise",
"version": "1.1.23",
"version": "1.1.21",
"dependencies": {
"@opencode-ai/ui": "workspace:*",
"@opencode-ai/util": "workspace:*",
@@ -235,7 +235,7 @@
},
"packages/function": {
"name": "@opencode-ai/function",
"version": "1.1.23",
"version": "1.1.21",
"dependencies": {
"@octokit/auth-app": "8.0.1",
"@octokit/rest": "catalog:",
@@ -251,7 +251,7 @@
},
"packages/opencode": {
"name": "opencode",
"version": "1.1.23",
"version": "1.1.21",
"bin": {
"opencode": "./bin/opencode",
},
@@ -355,7 +355,7 @@
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
"version": "1.1.23",
"version": "1.1.21",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"zod": "catalog:",
@@ -375,7 +375,7 @@
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
"version": "1.1.23",
"version": "1.1.21",
"devDependencies": {
"@hey-api/openapi-ts": "0.88.1",
"@tsconfig/node22": "catalog:",
@@ -386,7 +386,7 @@
},
"packages/slack": {
"name": "@opencode-ai/slack",
"version": "1.1.23",
"version": "1.1.21",
"dependencies": {
"@opencode-ai/sdk": "workspace:*",
"@slack/bolt": "^3.17.1",
@@ -399,7 +399,7 @@
},
"packages/ui": {
"name": "@opencode-ai/ui",
"version": "1.1.23",
"version": "1.1.21",
"dependencies": {
"@kobalte/core": "catalog:",
"@opencode-ai/sdk": "workspace:*",
@@ -439,7 +439,7 @@
},
"packages/util": {
"name": "@opencode-ai/util",
"version": "1.1.23",
"version": "1.1.21",
"dependencies": {
"zod": "catalog:",
},
@@ -450,7 +450,7 @@
},
"packages/web": {
"name": "@opencode-ai/web",
"version": "1.1.23",
"version": "1.1.21",
"dependencies": {
"@astrojs/cloudflare": "12.6.3",
"@astrojs/markdown-remark": "6.3.1",
+2 -4
View File
@@ -1,8 +1,6 @@
{
"nodeModules": {
"x86_64-linux": "sha256-4ndHIlS9t1ynRdFszJ1nvcu3YhunhuOc7jcuHI1FbnM=",
"aarch64-linux": "sha256-H9eUk/yVrQqVrAYONlb6As7mjkPXtOauBVfMBeVAmRo=",
"aarch64-darwin": "sha256-C0E9KAEj3GI83HwirIL2zlXYIe92T+7Iv6F51BB6slY=",
"x86_64-darwin": "sha256-wj5fZnyfu6Sf1HcqvsQM3M7dl5BKRAHmoqm1Ai1cL2M="
"x86_64-linux": "sha256-Fl1BdjNSg19LJVSgDMiBX8JuTaGlL2I5T+rqLfjSeO4=",
"aarch64-darwin": "sha256-7UajHu40n7JKqurU/+CGlitErsVFA2qDneUytI8+/zQ="
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/app",
"version": "1.1.23",
"version": "1.1.21",
"description": "",
"type": "module",
"exports": {
+1 -2
View File
@@ -17,7 +17,6 @@ export function Titlebar() {
const reserve = createMemo(
() => platform.platform === "desktop" && (platform.os === "windows" || platform.os === "linux"),
)
const web = createMemo(() => platform.platform === "web")
const getWin = () => {
if (platform.platform !== "desktop") return
@@ -89,7 +88,7 @@ export function Titlebar() {
onClick={layout.mobileSidebar.toggle}
/>
<TooltipKeybind
class={web() ? "hidden xl:flex shrink-0 ml-14" : "hidden xl:flex shrink-0"}
class="hidden xl:flex shrink-0 ml-14"
placement="bottom"
title="Toggle sidebar"
keybind={command.keybind("sidebar.toggle")}
+7 -50
View File
@@ -19,27 +19,15 @@ import {
type QuestionRequest,
createOpencodeClient,
} from "@opencode-ai/sdk/v2/client"
import { createStore, produce, reconcile, type SetStoreFunction, type Store } from "solid-js/store"
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 {
batch,
createContext,
createEffect,
useContext,
onCleanup,
onMount,
type Accessor,
type ParentProps,
Switch,
Match,
} from "solid-js"
import { batch, createContext, useContext, onCleanup, onMount, type ParentProps, Switch, Match } from "solid-js"
import { showToast } from "@opencode-ai/ui/toast"
import { getFilename } from "@opencode-ai/util/path"
import { usePlatform } from "./platform"
import { Persist, persisted } from "@/utils/persist"
type State = {
status: "loading" | "partial" | "complete"
@@ -80,16 +68,9 @@ type State = {
}
}
type VcsCache = {
store: Store<{ value: VcsInfo | undefined }>
setStore: SetStoreFunction<{ value: VcsInfo | undefined }>
ready: Accessor<boolean>
}
function createGlobalSync() {
const globalSDK = useGlobalSDK()
const platform = usePlatform()
const vcsCache = new Map<string, VcsCache>()
const [globalStore, setGlobalStore] = createStore<{
ready: boolean
error?: InitError
@@ -105,16 +86,10 @@ function createGlobalSync() {
provider_auth: {},
})
const children: Record<string, [Store<State>, SetStoreFunction<State>]> = {}
const children: Record<string, ReturnType<typeof createStore<State>>> = {}
function child(directory: string) {
if (!directory) console.error("No directory provided")
if (!children[directory]) {
const cache = persisted(
Persist.workspace(directory, "vcs", ["vcs.v1"]),
createStore({ value: undefined as VcsInfo | undefined }),
)
vcsCache.set(directory, { store: cache[0], setStore: cache[1], ready: cache[3] })
children[directory] = createStore<State>({
project: "",
provider: { all: [], connected: [], default: {} },
@@ -132,16 +107,14 @@ function createGlobalSync() {
question: {},
mcp: {},
lsp: [],
vcs: cache[0].value,
vcs: undefined,
limit: 5,
message: {},
part: {},
})
bootstrapInstance(directory)
}
const childStore = children[directory]
if (!childStore) throw new Error("Failed to create store")
return childStore
return children[directory]
}
async function loadSessions(directory: string) {
@@ -184,8 +157,6 @@ function createGlobalSync() {
async function bootstrapInstance(directory: string) {
if (!directory) return
const [store, setStore] = child(directory)
const cache = vcsCache.get(directory)
if (!cache) return
const sdk = createOpencodeClient({
baseUrl: globalSDK.url,
fetch: platform.fetch,
@@ -193,13 +164,6 @@ function createGlobalSync() {
throwOnError: true,
})
createEffect(() => {
if (!cache.ready()) return
const cached = cache.store.value
if (!cached?.branch) return
setStore("vcs", (value) => value ?? cached)
})
const blockingRequests = {
project: () => sdk.project.current().then((x) => setStore("project", x.data!.id)),
provider: () =>
@@ -229,11 +193,7 @@ function createGlobalSync() {
loadSessions(directory),
sdk.mcp.status().then((x) => setStore("mcp", x.data!)),
sdk.lsp.status().then((x) => setStore("lsp", x.data!)),
sdk.vcs.get().then((x) => {
const next = x.data ?? store.vcs
setStore("vcs", next)
if (next?.branch) cache.setStore("value", next)
}),
sdk.vcs.get().then((x) => setStore("vcs", x.data)),
sdk.permission.list().then((x) => {
const grouped: Record<string, PermissionRequest[]> = {}
for (const perm of x.data ?? []) {
@@ -446,10 +406,7 @@ function createGlobalSync() {
break
}
case "vcs.branch.updated": {
const next = { branch: event.properties.branch }
setStore("vcs", next)
const cache = vcsCache.get(directory)
if (cache) cache.setStore("value", next)
setStore("vcs", { branch: event.properties.branch })
break
}
case "permission.asked": {
+12 -17
View File
@@ -16,7 +16,6 @@ import {
import { A, useNavigate, useParams } from "@solidjs/router"
import { useLayout, getAvatarColors, LocalProject } from "@/context/layout"
import { useGlobalSync } from "@/context/global-sync"
import { Persist, persisted } from "@/utils/persist"
import { base64Decode, base64Encode } from "@opencode-ai/util/encode"
import { Avatar } from "@opencode-ai/ui/avatar"
import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
@@ -63,16 +62,13 @@ import { Titlebar } from "@/components/titlebar"
import { useServer } from "@/context/server"
export default function Layout(props: ParentProps) {
const [store, setStore, , ready] = persisted(
Persist.global("layout.page", ["layout.page.v1"]),
createStore({
lastSession: {} as { [directory: string]: string },
activeProject: undefined as string | undefined,
activeWorkspace: undefined as string | undefined,
workspaceOrder: {} as Record<string, string[]>,
workspaceExpanded: {} as Record<string, boolean>,
}),
)
const [store, setStore] = createStore({
lastSession: {} as { [directory: string]: string },
activeProject: undefined as string | undefined,
activeWorkspace: undefined as string | undefined,
workspaceOrder: {} as Record<string, string[]>,
workspaceExpanded: {} as Record<string, boolean>,
})
let scrollContainerRef: HTMLDivElement | undefined
const xlQuery = window.matchMedia("(min-width: 1280px)")
@@ -293,7 +289,6 @@ export default function Layout(props: ParentProps) {
})
createEffect(() => {
if (!ready()) return
const project = currentProject()
if (!project) return
@@ -713,7 +708,7 @@ export default function Layout(props: ParentProps) {
const id = params.id
setStore("lastSession", directory, id)
notification.session.markViewed(id)
untrack(() => setStore("workspaceExpanded", directory, (value) => value ?? true))
untrack(() => setStore("workspaceExpanded", directory, true))
requestAnimationFrame(() => scrollToSession(id))
})
@@ -821,13 +816,13 @@ export default function Layout(props: ParentProps) {
const opencode = "4b0ea68d7af9a6031a7ffda7ad66e0cb83315750"
return (
<div class={`relative size-8 shrink-0 rounded ${props.class ?? ""}`}>
<div class="size-full rounded overflow-clip">
<div class={`relative size-8 shrink-0 rounded-sm ${props.class ?? ""}`}>
<div class="size-full rounded-sm overflow-clip">
<Avatar
fallback={name()}
src={props.project.id === opencode ? "https://opencode.ai/favicon.svg" : props.project.icon?.url}
{...getAvatarColors(props.project.icon?.color)}
class="size-full rounded"
class="size-full rounded-sm"
style={
notifications().length > 0 && props.notify
? { "-webkit-mask-image": mask, "mask-image": mask }
@@ -982,7 +977,7 @@ export default function Layout(props: ParentProps) {
<button
type="button"
classList={{
"flex items-center justify-center size-10 p-1 rounded-lg border transition-colors cursor-default": true,
"flex items-center justify-center size-10 p-1 rounded-md border transition-colors cursor-default": true,
"bg-transparent border-icon-strong-base hover:bg-surface-base-hover": selected(),
"bg-transparent border-transparent hover:bg-surface-base-hover hover:border-border-weak-base": !selected(),
}}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-app",
"version": "1.1.23",
"version": "1.1.21",
"type": "module",
"license": "MIT",
"scripts": {
+20 -3
View File
@@ -98,7 +98,7 @@
::view-transition-new(actions-20),
::view-transition-new(actions-100),
::view-transition-new(actions-200) {
animation: fade-in-up 300ms cubic-bezier(0.16, 1, 0.3, 1) 300ms forwards;
animation: fade-in-up 200ms cubic-bezier(0.16, 1, 0.3, 1) 300ms forwards;
opacity: 0;
}
@@ -109,6 +109,25 @@
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
::view-transition-image-pair(card-20),
::view-transition-image-pair(card-100),
::view-transition-image-pair(card-200) {
isolation: isolate;
overflow: hidden;
}
::view-transition-old(card-20),
::view-transition-old(card-100),
::view-transition-old(card-200) {
mix-blend-mode: normal;
}
::view-transition-new(card-20),
::view-transition-new(card-100),
::view-transition-new(card-200) {
mix-blend-mode: normal;
}
[data-page="black"] {
background: #000;
min-height: 100vh;
@@ -581,8 +600,6 @@
[data-slot="icon"] {
color: rgba(255, 255, 255, 0.59);
isolation: isolate;
transform: translateZ(0);
}
[data-slot="price"] {
@@ -49,10 +49,10 @@ export default function Black() {
data-slot="pricing-card"
style={{ "view-transition-name": `card-${plan.id}` }}
>
<div data-slot="icon">
<div data-slot="icon" style={{ "view-transition-name": `icon-${plan.id}` }}>
<PlanIcon plan={plan.id} />
</div>
<p data-slot="price">
<p data-slot="price" style={{ "view-transition-name": `price-${plan.id}` }}>
<span data-slot="amount">${plan.id}</span> <span data-slot="period">per month</span>
<Show when={plan.multiplier}>
<span data-slot="multiplier">{plan.multiplier}</span>
@@ -67,10 +67,10 @@ export default function Black() {
{(plan) => (
<div data-slot="selected-plan">
<div data-slot="selected-card" style={{ "view-transition-name": `card-${plan().id}` }}>
<div data-slot="icon">
<div data-slot="icon" style={{ "view-transition-name": `icon-${plan().id}` }}>
<PlanIcon plan={plan().id} />
</div>
<p data-slot="price">
<p data-slot="price" style={{ "view-transition-name": `price-${plan().id}` }}>
<span data-slot="amount">${plan().id}</span>{" "}
<span data-slot="period">per person billed monthly</span>
<Show when={plan().multiplier}>
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/console-core",
"version": "1.1.23",
"version": "1.1.21",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-function",
"version": "1.1.23",
"version": "1.1.21",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/console-mail",
"version": "1.1.23",
"version": "1.1.21",
"dependencies": {
"@jsx-email/all": "2.2.3",
"@jsx-email/cli": "1.4.3",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@opencode-ai/desktop",
"private": true,
"version": "1.1.23",
"version": "1.1.21",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/enterprise",
"version": "1.1.23",
"version": "1.1.21",
"private": true,
"type": "module",
"license": "MIT",
+6 -6
View File
@@ -1,7 +1,7 @@
id = "opencode"
name = "OpenCode"
description = "The open source coding agent."
version = "1.1.23"
version = "1.1.21"
schema_version = 1
authors = ["Anomaly"]
repository = "https://github.com/anomalyco/opencode"
@@ -11,26 +11,26 @@ name = "OpenCode"
icon = "./icons/opencode.svg"
[agent_servers.opencode.targets.darwin-aarch64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.23/opencode-darwin-arm64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.21/opencode-darwin-arm64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.darwin-x86_64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.23/opencode-darwin-x64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.21/opencode-darwin-x64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-aarch64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.23/opencode-linux-arm64.tar.gz"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.21/opencode-linux-arm64.tar.gz"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-x86_64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.23/opencode-linux-x64.tar.gz"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.21/opencode-linux-x64.tar.gz"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.windows-x86_64]
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.23/opencode-windows-x64.zip"
archive = "https://github.com/anomalyco/opencode/releases/download/v1.1.21/opencode-windows-x64.zip"
cmd = "./opencode.exe"
args = ["acp"]
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/function",
"version": "1.1.23",
"version": "1.1.21",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "1.1.23",
"version": "1.1.21",
"name": "opencode",
"type": "module",
"license": "MIT",
@@ -35,7 +35,6 @@ import tokyonight from "./theme/tokyonight.json" with { type: "json" }
import vercel from "./theme/vercel.json" with { type: "json" }
import vesper from "./theme/vesper.json" with { type: "json" }
import zenburn from "./theme/zenburn.json" with { type: "json" }
import carbonfox from "./theme/carbonfox.json" with { type: "json" }
import { useKV } from "./kv"
import { useRenderer } from "@opentui/solid"
import { createStore, produce } from "solid-js/store"
@@ -171,7 +170,6 @@ export const DEFAULT_THEMES: Record<string, ThemeJson> = {
vesper,
vercel,
zenburn,
carbonfox,
}
function resolveTheme(theme: ThemeJson, mode: "dark" | "light") {
@@ -1,248 +0,0 @@
{
"$schema": "https://opencode.ai/theme.json",
"defs": {
"bg0": "#0d0d0d",
"bg1": "#161616",
"bg1a": "#1a1a1a",
"bg2": "#1e1e1e",
"bg3": "#262626",
"bg4": "#303030",
"fg0": "#ffffff",
"fg1": "#f2f4f8",
"fg2": "#a9afbc",
"fg3": "#7d848f",
"lbg0": "#ffffff",
"lbg1": "#f4f4f4",
"lbg2": "#e8e8e8",
"lbg3": "#dcdcdc",
"lfg0": "#000000",
"lfg1": "#161616",
"lfg2": "#525252",
"lfg3": "#6f6f6f",
"red": "#ee5396",
"green": "#25be6a",
"yellow": "#08bdba",
"blue": "#78a9ff",
"magenta": "#be95ff",
"cyan": "#33b1ff",
"white": "#dfdfe0",
"orange": "#3ddbd9",
"pink": "#ff7eb6",
"blueBright": "#8cb6ff",
"cyanBright": "#52c7ff",
"greenBright": "#46c880",
"redLight": "#9f1853",
"greenLight": "#198038",
"yellowLight": "#007d79",
"blueLight": "#0043ce",
"magentaLight": "#6929c4",
"cyanLight": "#0072c3",
"warning": "#f1c21b",
"diffGreen": "#50fa7b",
"diffRed": "#ff6b6b",
"diffGreenBg": "#0f2418",
"diffRedBg": "#2a1216"
},
"theme": {
"primary": {
"dark": "cyan",
"light": "blueLight"
},
"secondary": {
"dark": "blue",
"light": "blueLight"
},
"accent": {
"dark": "pink",
"light": "redLight"
},
"error": {
"dark": "red",
"light": "redLight"
},
"warning": {
"dark": "warning",
"light": "yellowLight"
},
"success": {
"dark": "green",
"light": "greenLight"
},
"info": {
"dark": "blue",
"light": "blueLight"
},
"text": {
"dark": "fg1",
"light": "lfg1"
},
"textMuted": {
"dark": "fg3",
"light": "lfg3"
},
"background": {
"dark": "bg1",
"light": "lbg0"
},
"backgroundPanel": {
"dark": "bg1a",
"light": "lbg1"
},
"backgroundElement": {
"dark": "bg2",
"light": "lbg1"
},
"border": {
"dark": "bg4",
"light": "lbg3"
},
"borderActive": {
"dark": "cyan",
"light": "blueLight"
},
"borderSubtle": {
"dark": "bg3",
"light": "lbg2"
},
"diffAdded": {
"dark": "diffGreen",
"light": "greenLight"
},
"diffRemoved": {
"dark": "diffRed",
"light": "redLight"
},
"diffContext": {
"dark": "fg3",
"light": "lfg3"
},
"diffHunkHeader": {
"dark": "blue",
"light": "blueLight"
},
"diffHighlightAdded": {
"dark": "#7dffaa",
"light": "greenLight"
},
"diffHighlightRemoved": {
"dark": "#ff9999",
"light": "redLight"
},
"diffAddedBg": {
"dark": "diffGreenBg",
"light": "#defbe6"
},
"diffRemovedBg": {
"dark": "diffRedBg",
"light": "#fff1f1"
},
"diffContextBg": {
"dark": "bg1",
"light": "lbg1"
},
"diffLineNumber": {
"dark": "fg3",
"light": "lfg3"
},
"diffAddedLineNumberBg": {
"dark": "diffGreenBg",
"light": "#defbe6"
},
"diffRemovedLineNumberBg": {
"dark": "diffRedBg",
"light": "#fff1f1"
},
"markdownText": {
"dark": "fg1",
"light": "lfg1"
},
"markdownHeading": {
"dark": "blueBright",
"light": "blueLight"
},
"markdownLink": {
"dark": "blue",
"light": "blueLight"
},
"markdownLinkText": {
"dark": "cyan",
"light": "cyanLight"
},
"markdownCode": {
"dark": "green",
"light": "greenLight"
},
"markdownBlockQuote": {
"dark": "fg3",
"light": "lfg3"
},
"markdownEmph": {
"dark": "magenta",
"light": "magentaLight"
},
"markdownStrong": {
"dark": "fg0",
"light": "lfg0"
},
"markdownHorizontalRule": {
"dark": "bg4",
"light": "lbg3"
},
"markdownListItem": {
"dark": "cyan",
"light": "cyanLight"
},
"markdownListEnumeration": {
"dark": "cyan",
"light": "cyanLight"
},
"markdownImage": {
"dark": "blue",
"light": "blueLight"
},
"markdownImageText": {
"dark": "cyan",
"light": "cyanLight"
},
"markdownCodeBlock": {
"dark": "fg2",
"light": "lfg2"
},
"syntaxComment": {
"dark": "fg3",
"light": "lfg3"
},
"syntaxKeyword": {
"dark": "magenta",
"light": "magentaLight"
},
"syntaxFunction": {
"dark": "blueBright",
"light": "blueLight"
},
"syntaxVariable": {
"dark": "white",
"light": "lfg1"
},
"syntaxString": {
"dark": "green",
"light": "greenLight"
},
"syntaxNumber": {
"dark": "orange",
"light": "yellowLight"
},
"syntaxType": {
"dark": "yellow",
"light": "yellowLight"
},
"syntaxOperator": {
"dark": "fg2",
"light": "lfg2"
},
"syntaxPunctuation": {
"dark": "fg2",
"light": "lfg1"
}
}
}
+1 -35
View File
@@ -10,8 +10,6 @@ import {
type Tool,
type ToolSet,
extractReasoningMiddleware,
tool,
jsonSchema,
} from "ai"
import { clone, mergeDeep, pipe } from "remeda"
import { ProviderTransform } from "@/provider/transform"
@@ -142,26 +140,6 @@ export namespace LLM {
const tools = await resolveTools(input)
// LiteLLM and some Anthropic proxies require the tools parameter to be present
// when message history contains tool calls, even if no tools are being used.
// Add a dummy tool that is never called to satisfy this validation.
// This is enabled for:
// 1. Providers with "litellm" in their ID or API ID (auto-detected)
// 2. Providers with explicit "litellmProxy: true" option (opt-in for custom gateways)
const isLiteLLMProxy =
provider.options?.["litellmProxy"] === true ||
input.model.providerID.toLowerCase().includes("litellm") ||
input.model.api.id.toLowerCase().includes("litellm")
if (isLiteLLMProxy && Object.keys(tools).length === 0 && hasToolCalls(input.messages)) {
tools["_noop"] = tool({
description:
"Placeholder for LiteLLM/Anthropic proxy compatibility - required when message history contains tool calls but no active tools are needed",
inputSchema: jsonSchema({ type: "object", properties: {} }),
execute: async () => ({ output: "", title: "", metadata: {} }),
})
}
return streamText({
onError(error) {
l.error("stream error", {
@@ -193,7 +171,7 @@ export namespace LLM {
topP: params.topP,
topK: params.topK,
providerOptions: ProviderTransform.providerOptions(input.model, params.options),
activeTools: Object.keys(tools).filter((x) => x !== "invalid" && x !== "_noop"),
activeTools: Object.keys(tools).filter((x) => x !== "invalid"),
tools,
maxOutputTokens,
abortSignal: input.abort,
@@ -260,16 +238,4 @@ export namespace LLM {
}
return input.tools
}
// Check if messages contain any tool-call content
// Used to determine if a dummy tool should be added for LiteLLM proxy compatibility
export function hasToolCalls(messages: ModelMessage[]): boolean {
for (const msg of messages) {
if (!Array.isArray(msg.content)) continue
for (const part of msg.content) {
if (part.type === "tool-call" || part.type === "tool-result") return true
}
}
return false
}
}
@@ -533,17 +533,6 @@ export namespace MessageV2 {
errorText: part.state.error,
callProviderMetadata: part.metadata,
})
// Handle pending/running tool calls to prevent dangling tool_use blocks
// Anthropic/Claude APIs require every tool_use to have a corresponding tool_result
if (part.state.status === "pending" || part.state.status === "running")
assistantMessage.parts.push({
type: ("tool-" + part.tool) as `tool-${string}`,
state: "output-error",
toolCallId: part.callID,
input: part.state.input,
errorText: "[Tool execution was interrupted]",
callProviderMetadata: part.metadata,
})
}
if (part.type === "reasoning") {
assistantMessage.parts.push({
-1
View File
@@ -77,7 +77,6 @@ export namespace SessionSummary {
const textPart = msgWithParts.parts.find((p) => p.type === "text" && !p.synthetic) as MessageV2.TextPart
if (textPart && !userMsg.summary?.title) {
const agent = await Agent.get("title")
if (!agent) return
const stream = await LLM.stream({
agent,
user: userMsg,
@@ -1,90 +0,0 @@
import { describe, expect, test } from "bun:test"
import { LLM } from "../../src/session/llm"
import type { ModelMessage } from "ai"
describe("session.llm.hasToolCalls", () => {
test("returns false for empty messages array", () => {
expect(LLM.hasToolCalls([])).toBe(false)
})
test("returns false for messages with only text content", () => {
const messages: ModelMessage[] = [
{
role: "user",
content: [{ type: "text", text: "Hello" }],
},
{
role: "assistant",
content: [{ type: "text", text: "Hi there" }],
},
]
expect(LLM.hasToolCalls(messages)).toBe(false)
})
test("returns true when messages contain tool-call", () => {
const messages = [
{
role: "user",
content: [{ type: "text", text: "Run a command" }],
},
{
role: "assistant",
content: [
{
type: "tool-call",
toolCallId: "call-123",
toolName: "bash",
},
],
},
] as ModelMessage[]
expect(LLM.hasToolCalls(messages)).toBe(true)
})
test("returns true when messages contain tool-result", () => {
const messages = [
{
role: "tool",
content: [
{
type: "tool-result",
toolCallId: "call-123",
toolName: "bash",
},
],
},
] as ModelMessage[]
expect(LLM.hasToolCalls(messages)).toBe(true)
})
test("returns false for messages with string content", () => {
const messages: ModelMessage[] = [
{
role: "user",
content: "Hello world",
},
{
role: "assistant",
content: "Hi there",
},
]
expect(LLM.hasToolCalls(messages)).toBe(false)
})
test("returns true when tool-call is mixed with text content", () => {
const messages = [
{
role: "assistant",
content: [
{ type: "text", text: "Let me run that command" },
{
type: "tool-call",
toolCallId: "call-456",
toolName: "read",
},
],
},
] as ModelMessage[]
expect(LLM.hasToolCalls(messages)).toBe(true)
})
})
@@ -569,94 +569,4 @@ describe("session.message-v2.toModelMessage", () => {
expect(MessageV2.toModelMessage(input)).toStrictEqual([])
})
test("converts pending/running tool calls to error results to prevent dangling tool_use", () => {
const userID = "m-user"
const assistantID = "m-assistant"
const input: MessageV2.WithParts[] = [
{
info: userInfo(userID),
parts: [
{
...basePart(userID, "u1"),
type: "text",
text: "run tool",
},
] as MessageV2.Part[],
},
{
info: assistantInfo(assistantID, userID),
parts: [
{
...basePart(assistantID, "a1"),
type: "tool",
callID: "call-pending",
tool: "bash",
state: {
status: "pending",
input: { cmd: "ls" },
raw: "",
},
},
{
...basePart(assistantID, "a2"),
type: "tool",
callID: "call-running",
tool: "read",
state: {
status: "running",
input: { path: "/tmp" },
time: { start: 0 },
},
},
] as MessageV2.Part[],
},
]
const result = MessageV2.toModelMessage(input)
expect(result).toStrictEqual([
{
role: "user",
content: [{ type: "text", text: "run tool" }],
},
{
role: "assistant",
content: [
{
type: "tool-call",
toolCallId: "call-pending",
toolName: "bash",
input: { cmd: "ls" },
providerExecuted: undefined,
},
{
type: "tool-call",
toolCallId: "call-running",
toolName: "read",
input: { path: "/tmp" },
providerExecuted: undefined,
},
],
},
{
role: "tool",
content: [
{
type: "tool-result",
toolCallId: "call-pending",
toolName: "bash",
output: { type: "error-text", value: "[Tool execution was interrupted]" },
},
{
type: "tool-result",
toolCallId: "call-running",
toolName: "read",
output: { type: "error-text", value: "[Tool execution was interrupted]" },
},
],
},
])
})
})
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
"version": "1.1.23",
"version": "1.1.21",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
"version": "1.1.23",
"version": "1.1.21",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/slack",
"version": "1.1.23",
"version": "1.1.21",
"type": "module",
"license": "MIT",
"scripts": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/ui",
"version": "1.1.23",
"version": "1.1.21",
"type": "module",
"license": "MIT",
"exports": {
-3
View File
@@ -11,7 +11,6 @@ import oneDarkProThemeJson from "./themes/onedarkpro.json"
import shadesOfPurpleThemeJson from "./themes/shadesofpurple.json"
import nightowlThemeJson from "./themes/nightowl.json"
import vesperThemeJson from "./themes/vesper.json"
import carbonfoxThemeJson from "./themes/carbonfox.json"
export const oc1Theme = oc1ThemeJson as DesktopTheme
export const tokyonightTheme = tokyoThemeJson as DesktopTheme
@@ -25,7 +24,6 @@ export const oneDarkProTheme = oneDarkProThemeJson as DesktopTheme
export const shadesOfPurpleTheme = shadesOfPurpleThemeJson as DesktopTheme
export const nightowlTheme = nightowlThemeJson as DesktopTheme
export const vesperTheme = vesperThemeJson as DesktopTheme
export const carbonfoxTheme = carbonfoxThemeJson as DesktopTheme
export const DEFAULT_THEMES: Record<string, DesktopTheme> = {
"oc-1": oc1Theme,
@@ -40,5 +38,4 @@ export const DEFAULT_THEMES: Record<string, DesktopTheme> = {
shadesofpurple: shadesOfPurpleTheme,
nightowl: nightowlTheme,
vesper: vesperTheme,
carbonfox: carbonfoxTheme,
}
-122
View File
@@ -1,122 +0,0 @@
{
"$schema": "https://opencode.ai/desktop-theme.json",
"name": "Carbonfox",
"id": "carbonfox",
"light": {
"seeds": {
"neutral": "#8e8e8e",
"primary": "#0072c3",
"success": "#198038",
"warning": "#f1c21b",
"error": "#da1e28",
"info": "#0043ce",
"interactive": "#0f62fe",
"diffAdd": "#198038",
"diffDelete": "#da1e28"
},
"overrides": {
"background-base": "#ffffff",
"background-weak": "#f4f4f4",
"background-strong": "#e8e8e8",
"background-stronger": "#dcdcdc",
"surface-raised-strong": "#ffffff",
"surface-raised-stronger": "#ffffff",
"surface-float-base": "#161616",
"surface-float-base-hover": "#262626",
"text-base": "#161616",
"text-weak": "#525252",
"text-strong": "#000000",
"syntax-string": "#198038",
"syntax-primitive": "#da1e28",
"syntax-property": "#0043ce",
"syntax-type": "#007d79",
"syntax-constant": "#6929c4",
"syntax-keyword": "#525252",
"syntax-info": "#0043ce",
"markdown-heading": "#0043ce",
"markdown-text": "#161616",
"markdown-link": "#0043ce",
"markdown-link-text": "#0072c3",
"markdown-code": "#198038",
"markdown-block-quote": "#525252",
"markdown-emph": "#6929c4",
"markdown-strong": "#161616",
"markdown-horizontal-rule": "#c6c6c6",
"markdown-list-item": "#0072c3",
"markdown-list-enumeration": "#0072c3",
"markdown-image": "#0043ce",
"markdown-image-text": "#0072c3",
"markdown-code-block": "#393939"
}
},
"dark": {
"seeds": {
"neutral": "#393939",
"primary": "#33b1ff",
"success": "#42be65",
"warning": "#f1c21b",
"error": "#ff8389",
"info": "#78a9ff",
"interactive": "#4589ff",
"diffAdd": "#42be65",
"diffDelete": "#ff8389"
},
"overrides": {
"background-base": "#161616",
"background-weak": "#262626",
"background-strong": "#0d0d0d",
"background-stronger": "#000000",
"surface-raised-base": "#1c1c1c",
"surface-raised-base-hover": "#262626",
"surface-raised-strong": "#262626",
"surface-raised-strong-hover": "#303030",
"surface-raised-stronger": "#303030",
"surface-raised-stronger-hover": "#393939",
"surface-raised-stronger-non-alpha": "#303030",
"surface-float-base": "#0d0d0d",
"surface-float-base-hover": "#1a1a1a",
"surface-inset-base": "#0d0d0d",
"surface-inset-strong": "#000000",
"surface-base": "#1e1e1e",
"surface-base-hover": "#262626",
"surface-diff-add-base": "#0e3a22",
"surface-diff-delete-base": "#4d1a1f",
"input-base": "#262626",
"input-hover": "#303030",
"button-secondary-base": "#393939",
"button-secondary-hover": "#4c4c4c",
"border-weak-base": "#393939",
"border-weak-hover": "#4c4c4c",
"border-base": "#525252",
"border-hover": "#636363",
"border-strong-base": "#6f6f6f",
"text-base": "#f2f4f8",
"text-weak": "#8d8d8d",
"text-weaker": "#6f6f6f",
"text-strong": "#ffffff",
"icon-base": "#8d8d8d",
"icon-weak-base": "#6f6f6f",
"syntax-string": "#42be65",
"syntax-primitive": "#ff8389",
"syntax-property": "#78a9ff",
"syntax-type": "#08bdba",
"syntax-constant": "#be95ff",
"syntax-keyword": "#8d8d8d",
"syntax-info": "#78a9ff",
"markdown-heading": "#82cfff",
"markdown-text": "#f2f4f8",
"markdown-link": "#78a9ff",
"markdown-link-text": "#33b1ff",
"markdown-code": "#42be65",
"markdown-block-quote": "#8d8d8d",
"markdown-emph": "#be95ff",
"markdown-strong": "#ffffff",
"markdown-horizontal-rule": "#393939",
"markdown-list-item": "#33b1ff",
"markdown-list-enumeration": "#33b1ff",
"markdown-image": "#78a9ff",
"markdown-image-text": "#33b1ff",
"markdown-code-block": "#c6c6c6"
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/util",
"version": "1.1.23",
"version": "1.1.21",
"private": true,
"type": "module",
"license": "MIT",
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "@opencode-ai/web",
"type": "module",
"license": "MIT",
"version": "1.1.23",
"version": "1.1.21",
"scripts": {
"dev": "astro dev",
"dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev",
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "opencode",
"displayName": "opencode",
"description": "opencode for VS Code",
"version": "1.1.23",
"version": "1.1.21",
"publisher": "sst-dev",
"repository": {
"type": "git",