diff --git a/.github/workflows/nix-desktop.yml b/.github/workflows/nix-desktop.yml index 01cfaed78b4..b7919c062cc 100644 --- a/.github/workflows/nix-desktop.yml +++ b/.github/workflows/nix-desktop.yml @@ -25,8 +25,6 @@ jobs: matrix: os: - blacksmith-4vcpu-ubuntu-2404 - - blacksmith-4vcpu-ubuntu-2404-arm - - macos-15 - macos-latest runs-on: ${{ matrix.os }} timeout-minutes: 60 @@ -35,7 +33,7 @@ jobs: uses: actions/checkout@v6 - name: Setup Nix - uses: nixbuild/nix-quick-install-action@v34 + uses: DeterminateSystems/nix-installer-action@v21 - name: Build desktop via flake run: | diff --git a/.github/workflows/update-nix-hashes.yml b/.github/workflows/update-nix-hashes.yml index 19373f748f2..46ea12d1870 100644 --- a/.github/workflows/update-nix-hashes.yml +++ b/.github/workflows/update-nix-hashes.yml @@ -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: 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: blacksmith-4vcpu-ubuntu-2404 - - system: aarch64-linux - host: blacksmith-4vcpu-ubuntu-2404-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}}" diff --git a/bun.lock b/bun.lock index b5971a500c8..1f0f163f948 100644 --- a/bun.lock +++ b/bun.lock @@ -1,6 +1,5 @@ { "lockfileVersion": 1, - "configVersion": 1, "workspaces": { "": { "name": "opencode", @@ -22,7 +21,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 +69,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", @@ -95,14 +94,13 @@ }, "devDependencies": { "@typescript/native-preview": "catalog:", - "@webgpu/types": "0.1.54", "typescript": "catalog:", "wrangler": "4.50.0", }, }, "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 +127,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 +151,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 +175,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 +204,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 +233,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 +249,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.1.23", + "version": "1.1.21", "bin": { "opencode": "./bin/opencode", }, @@ -355,7 +353,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.1.23", + "version": "1.1.21", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -375,7 +373,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 +384,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 +397,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 +437,7 @@ }, "packages/util": { "name": "@opencode-ai/util", - "version": "1.1.23", + "version": "1.1.21", "dependencies": { "zod": "catalog:", }, @@ -450,7 +448,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", @@ -1904,7 +1902,7 @@ "@vitest/utils": ["@vitest/utils@4.0.16", "", { "dependencies": { "@vitest/pretty-format": "4.0.16", "tinyrainbow": "^3.0.3" } }, "sha512-h8z9yYhV3e1LEfaQ3zdypIrnAg/9hguReGZoS7Gl0aBG5xgA410zBqECqmaF/+RkTggRsfnzc1XaAHA6bmUufA=="], - "@webgpu/types": ["@webgpu/types@0.1.54", "", {}, "sha512-81oaalC8LFrXjhsczomEQ0u3jG+TqE6V9QHLA8GNZq/Rnot0KDugu3LhSYSlie8tSdooAN1Hov05asrUUp9qgg=="], + "@webgpu/types": ["@webgpu/types@0.1.66", "", {}, "sha512-YA2hLrwLpDsRueNDXIMqN9NTzD6bCDkuXbOSe0heS+f8YE8usA6Gbv1prj81pzVHrbaAma7zObnIC+I6/sXJgA=="], "@zip.js/zip.js": ["@zip.js/zip.js@2.7.62", "", {}, "sha512-OaLvZ8j4gCkLn048ypkZu29KX30r8/OfFF2w4Jo5WXFr+J04J+lzJ5TKZBVgFXhlvSkqNFQdfnY1Q8TMTCyBVA=="], @@ -4292,8 +4290,6 @@ "body-parser/qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], - "bun-webgpu/@webgpu/types": ["@webgpu/types@0.1.66", "", {}, "sha512-YA2hLrwLpDsRueNDXIMqN9NTzD6bCDkuXbOSe0heS+f8YE8usA6Gbv1prj81pzVHrbaAma7zObnIC+I6/sXJgA=="], - "clean-css/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "compress-commons/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], diff --git a/infra/console.ts b/infra/console.ts index 539b86f5d2b..17e4deab6e2 100644 --- a/infra/console.ts +++ b/infra/console.ts @@ -119,7 +119,6 @@ const ZEN_MODELS = [ new sst.Secret("ZEN_MODELS5"), new sst.Secret("ZEN_MODELS6"), new sst.Secret("ZEN_MODELS7"), - new sst.Secret("ZEN_MODELS8"), ] const ZEN_BLACK = new sst.Secret("ZEN_BLACK") const STRIPE_SECRET_KEY = new sst.Secret("STRIPE_SECRET_KEY") diff --git a/nix/hashes.json b/nix/hashes.json index d99fd4c9fad..c89b60ef97a 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,6 @@ { "nodeModules": { - "x86_64-linux": "sha256-Fl1BdjNSg19LJVSgDMiBX8JuTaGlL2I5T+rqLfjSeO4=", - "aarch64-linux": "sha256-6d20RnBuhOUMaY+5Ms/IOAta1HqHCtb/3yjkGsPgJzA=", - "aarch64-darwin": "sha256-7UajHu40n7JKqurU/+CGlitErsVFA2qDneUytI8+/zQ=", - "x86_64-darwin": "sha256-u3izLZJZ0+KVqOu0agm4lBY8A3cY62syF0QaL9c1E/g=" + "x86_64-linux": "sha256-4ndHIlS9t1ynRdFszJ1nvcu3YhunhuOc7jcuHI1FbnM=", + "aarch64-darwin": "sha256-C0E9KAEj3GI83HwirIL2zlXYIe92T+7Iv6F51BB6slY=" } } diff --git a/packages/app/package.json b/packages/app/package.json index d7276d231a9..8c9b5bee54d 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/app", - "version": "1.1.23", + "version": "1.1.21", "description": "", "type": "module", "exports": { diff --git a/packages/app/src/components/dialog-select-file.tsx b/packages/app/src/components/dialog-select-file.tsx index 3b80c2687f1..461f8a0c0ac 100644 --- a/packages/app/src/components/dialog-select-file.tsx +++ b/packages/app/src/components/dialog-select-file.tsx @@ -4,26 +4,11 @@ import { FileIcon } from "@opencode-ai/ui/file-icon" import { List } from "@opencode-ai/ui/list" import { getDirectory, getFilename } from "@opencode-ai/util/path" import { useParams } from "@solidjs/router" -import { createMemo, createSignal, onCleanup, Show } from "solid-js" -import { formatKeybind, useCommand, type CommandOption } from "@/context/command" +import { createMemo } from "solid-js" import { useLayout } from "@/context/layout" import { useFile } from "@/context/file" -type EntryType = "command" | "file" - -type Entry = { - id: string - type: EntryType - title: string - description?: string - keybind?: string - category: "Commands" | "Files" - option?: CommandOption - path?: string -} - export function DialogSelectFile() { - const command = useCommand() const layout = useLayout() const file = useFile() const dialog = useDialog() @@ -31,148 +16,35 @@ export function DialogSelectFile() { const sessionKey = createMemo(() => `${params.dir}${params.id ? "/" + params.id : ""}`) const tabs = createMemo(() => layout.tabs(sessionKey())) const view = createMemo(() => layout.view(sessionKey())) - const state = { cleanup: undefined as (() => void) | void, committed: false } - const [grouped, setGrouped] = createSignal(false) - const common = ["session.new", "session.previous", "session.next", "terminal.toggle", "review.toggle"] - const limit = 5 - - const allowed = createMemo(() => - command.options.filter( - (option) => !option.disabled && !option.id.startsWith("suggested.") && option.id !== "file.open", - ), - ) - - const commandItem = (option: CommandOption): Entry => ({ - id: "command:" + option.id, - type: "command", - title: option.title, - description: option.description, - keybind: option.keybind, - category: "Commands", - option, - }) - - const fileItem = (path: string): Entry => ({ - id: "file:" + path, - type: "file", - title: path, - category: "Files", - path, - }) - - const list = createMemo(() => allowed().map(commandItem)) - - const picks = createMemo(() => { - const all = allowed() - const order = new Map(common.map((id, index) => [id, index])) - const picked = all.filter((option) => order.has(option.id)) - const base = picked.length ? picked : all.slice(0, limit) - const sorted = picked.length ? [...base].sort((a, b) => (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0)) : base - return sorted.map(commandItem) - }) - - const recent = createMemo(() => { - const all = tabs().all() - const active = tabs().active() - const order = active ? [active, ...all.filter((item) => item !== active)] : all - const seen = new Set() - const items: Entry[] = [] - - for (const item of order) { - const path = file.pathFromTab(item) - if (!path) continue - if (seen.has(path)) continue - seen.add(path) - items.push(fileItem(path)) - } - - return items.slice(0, limit) - }) - - const items = async (filter: string) => { - const query = filter.trim() - setGrouped(query.length > 0) - if (!query) return [...picks(), ...recent()] - const files = await file.searchFiles(query) - const entries = files.map(fileItem) - return [...list(), ...entries] - } - - const handleMove = (item: Entry | undefined) => { - state.cleanup?.() - if (!item) return - if (item.type !== "command") return - state.cleanup = item.option?.onHighlight?.() - } - - const open = (path: string) => { - const value = file.tab(path) - tabs().open(value) - file.load(path) - view().reviewPanel.open() - } - - const handleSelect = (item: Entry | undefined) => { - if (!item) return - state.committed = true - state.cleanup = undefined - dialog.close() - - if (item.type === "command") { - item.option?.onSelect?.("palette") - return - } - - if (!item.path) return - open(item.path) - } - - onCleanup(() => { - if (state.committed) return - state.cleanup?.() - }) - return ( - + item.id} - filterKeys={["title", "description", "category"]} - groupBy={(item) => (grouped() ? item.category : "")} - onMove={handleMove} - onSelect={handleSelect} + search={{ placeholder: "Search files", autofocus: true }} + emptyMessage="No files found" + items={file.searchFiles} + key={(x) => x} + onSelect={(path) => { + if (path) { + const value = file.tab(path) + tabs().open(value) + file.load(path) + view().reviewPanel.open() + } + dialog.close() + }} > - {(item) => ( - -
- -
- - {getDirectory(item.path ?? "")} - - {getFilename(item.path ?? "")} -
-
- - } - > -
-
- {item.title} - - {item.description} - + {(i) => ( +
+
+ +
+ + {getDirectory(i)} + + {getFilename(i)}
- - {formatKeybind(item.keybind ?? "")} -
- +
)}
diff --git a/packages/app/src/components/titlebar.tsx b/packages/app/src/components/titlebar.tsx index a1ce45a97e7..2192ed0e4a7 100644 --- a/packages/app/src/components/titlebar.tsx +++ b/packages/app/src/components/titlebar.tsx @@ -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} /> void) | void + let committed = false + + const handleMove = (option: CommandOption | undefined) => { + cleanup?.() + cleanup = option?.onHighlight?.() + } + + const handleSelect = (option: CommandOption | undefined) => { + if (option) { + committed = true + cleanup = undefined + dialog.close() + option.onSelect?.("palette") + } + } + + onCleanup(() => { + if (!committed) { + cleanup?.() + } + }) + + return ( + + props.options.filter((x) => !x.id.startsWith("suggested.") || !x.disabled)} + key={(x) => x?.id} + filterKeys={["title", "description", "category"]} + groupBy={(x) => x.category ?? ""} + onMove={handleMove} + onSelect={handleSelect} + > + {(option) => ( +
+
+ {option.title} + + {option.description} + +
+ + {formatKeybind(option.keybind!)} + +
+ )} +
+
+ ) +} + export const { use: useCommand, provider: CommandProvider } = createSimpleContext({ name: "Command", init: () => { const [registrations, setRegistrations] = createSignal[]>([]) const [suspendCount, setSuspendCount] = createSignal(0) + const dialog = useDialog() const options = createMemo(() => { const seen = new Set() @@ -143,17 +202,10 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex const suspended = () => suspendCount() > 0 - const run = (id: string, source?: "palette" | "keybind" | "slash") => { - for (const option of options()) { - if (option.id === id || option.id === "suggested." + id) { - option.onSelect?.(source) - return - } - } - } - const showPalette = () => { - run("file.open", "palette") + if (!dialog.active) { + dialog.show(() => !x.disabled)} />) + } } const handleKeyDown = (event: KeyboardEvent) => { @@ -196,7 +248,12 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex }) }, trigger(id: string, source?: "palette" | "keybind" | "slash") { - run(id, source) + for (const option of options()) { + if (option.id === id || option.id === "suggested." + id) { + option.onSelect?.(source) + return + } + } }, keybind(id: string) { const option = options().find((x) => x.id === id || x.id === "suggested." + id) diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx index 82452ed4895..a0b25705686 100644 --- a/packages/app/src/context/global-sync.tsx +++ b/packages/app/src/context/global-sync.tsx @@ -19,29 +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, - getOwner, - runWithOwner, - 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" @@ -82,18 +68,9 @@ type State = { } } -type VcsCache = { - store: Store<{ value: VcsInfo | undefined }> - setStore: SetStoreFunction<{ value: VcsInfo | undefined }> - ready: Accessor -} - function createGlobalSync() { const globalSDK = useGlobalSDK() const platform = usePlatform() - const owner = getOwner() - if (!owner) throw new Error("GlobalSync must be created within owner") - const vcsCache = new Map() const [globalStore, setGlobalStore] = createStore<{ ready: boolean error?: InitError @@ -109,19 +86,10 @@ function createGlobalSync() { provider_auth: {}, }) - const children: Record, SetStoreFunction]> = {} + const children: Record>> = {} function child(directory: string) { if (!directory) console.error("No directory provided") if (!children[directory]) { - const cache = runWithOwner(owner, () => - persisted( - Persist.workspace(directory, "vcs", ["vcs.v1"]), - createStore({ value: undefined as VcsInfo | undefined }), - ), - ) - if (!cache) throw new Error("Failed to create persisted cache") - vcsCache.set(directory, { store: cache[0], setStore: cache[1], ready: cache[3] }) - children[directory] = createStore({ project: "", provider: { all: [], connected: [], default: {} }, @@ -139,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) { @@ -191,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, @@ -200,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: () => @@ -236,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 = {} for (const perm of x.data ?? []) { @@ -453,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": { diff --git a/packages/app/src/pages/layout.tsx b/packages/app/src/pages/layout.tsx index f2a777fd354..d7a491aa9e0 100644 --- a/packages/app/src/pages/layout.tsx +++ b/packages/app/src/pages/layout.tsx @@ -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", ["layout.v6"]), - createStore({ - lastSession: {} as { [directory: string]: string }, - activeProject: undefined as string | undefined, - activeWorkspace: undefined as string | undefined, - workspaceOrder: {} as Record, - workspaceExpanded: {} as Record, - }), - ) + const [store, setStore] = createStore({ + lastSession: {} as { [directory: string]: string }, + activeProject: undefined as string | undefined, + activeWorkspace: undefined as string | undefined, + workspaceOrder: {} as Record, + workspaceExpanded: {} as Record, + }) 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 ( -
-
+
+
0 && props.notify ? { "-webkit-mask-image": mask, "mask-image": mask } @@ -944,17 +939,6 @@ export default function Layout(props: ParentProps) { ) } - const SessionSkeleton = (props: { count?: number }): JSX.Element => { - const items = Array.from({ length: props.count ?? 4 }, (_, index) => index) - return ( -
- - {() =>
} - -
- ) - } - const SortableProject = (props: { project: LocalProject; mobile?: boolean }): JSX.Element => { const sortable = createSortable(props.project.worktree) const selected = createMemo(() => { @@ -993,7 +977,7 @@ export default function Layout(props: ParentProps) { - - - {(session) => } @@ -1215,7 +1195,6 @@ export default function Layout(props: ParentProps) { .filter((session) => !session.parentID) .toSorted(sortSessions), ) - const loading = createMemo(() => workspaceStore.status !== "complete" && sessions().length === 0) const hasMore = createMemo(() => workspaceStore.sessionTotal > workspaceStore.session.length) const loadMore = async () => { setWorkspaceStore("limit", (limit) => limit + 5) @@ -1230,9 +1209,6 @@ export default function Layout(props: ParentProps) { class="size-full flex flex-col py-2 overflow-y-auto no-scrollbar" >