diff --git a/packages/app/src/app.tsx b/packages/app/src/app.tsx
index a15b65cd84..fd956f0afa 100644
--- a/packages/app/src/app.tsx
+++ b/packages/app/src/app.tsx
@@ -286,11 +286,11 @@ function ConnectionError(props: { onRetry?: () => void; onServerSelected?: (key:
)
}
-function ServerKey(props: ParentProps) {
+function ServerKey(props: { children: (key: ServerConnection.Key) => JSX.Element }) {
const server = useServer()
return (
- {props.children}
+ {(key) => props.children(key)}
)
}
@@ -310,22 +310,24 @@ export function AppInterface(props: {
>
-
-
-
- {routerProps.children}}
- >
-
-
-
-
-
-
-
-
-
+ {() => (
+
+
+
+ {routerProps.children}}
+ >
+
+
+
+
+
+
+
+
+
+ )}
diff --git a/packages/app/src/components/dialog-select-server.tsx b/packages/app/src/components/dialog-select-server.tsx
index ef62315bb5..c627deed30 100644
--- a/packages/app/src/components/dialog-select-server.tsx
+++ b/packages/app/src/components/dialog-select-server.tsx
@@ -8,7 +8,7 @@ import { List } from "@opencode-ai/ui/list"
import { TextField } from "@opencode-ai/ui/text-field"
import { useMutation } from "@tanstack/solid-query"
import { showToast } from "@opencode-ai/ui/toast"
-import { batch, createEffect, createMemo, createResource, For, onCleanup, Show, startTransition, untrack } from "solid-js"
+import { batch, createEffect, createMemo, createResource, For, onCleanup, Show, untrack } from "solid-js"
import { createStore, reconcile } from "solid-js/store"
import { DialogWslServer } from "@/components/dialog-wsl-server"
import { ServerHealthIndicator, ServerRow } from "@/components/server/server-row"
@@ -386,28 +386,21 @@ export function DialogSelectServer(props: DialogSelectServerProps = {}) {
const nextKey = ServerConnection.key(conn)
const changed = server.key !== nextKey
- const navigateHome = () => {
- if (changed && typeof window !== "undefined" && window.history?.replaceState) {
- window.history.replaceState(null, "", "/")
+ const navigateHome = () => props.onNavigateHome?.()
+
+ const apply = () => {
+ dialog.close()
+ if (persist && conn.type === "http") {
+ server.add(conn)
+ navigateHome()
return
}
- props.onNavigateHome?.()
- }
- const apply = () =>
- startTransition(() => {
- dialog.close()
- if (persist && conn.type === "http") {
- server.add(conn)
- navigateHome()
- return
- }
-
- batch(() => {
- navigateHome()
- server.setActive(nextKey)
- })
+ batch(() => {
+ navigateHome()
+ server.setActive(nextKey)
})
+ }
if (!changed) {
await apply()
diff --git a/packages/app/src/components/status-popover-body.tsx b/packages/app/src/components/status-popover-body.tsx
index 952e3eac64..787c91a21c 100644
--- a/packages/app/src/components/status-popover-body.tsx
+++ b/packages/app/src/components/status-popover-body.tsx
@@ -5,7 +5,7 @@ import { Switch } from "@opencode-ai/ui/switch"
import { Tabs } from "@opencode-ai/ui/tabs"
import { useMutation, useQueryClient } from "@tanstack/solid-query"
import { showToast } from "@opencode-ai/ui/toast"
-import { useNavigate } from "@solidjs/router"
+import { useLocation, useNavigate } from "@solidjs/router"
import { type Accessor, createEffect, createMemo, For, type JSXElement, onCleanup, Show } from "solid-js"
import { createStore, reconcile } from "solid-js/store"
import { ServerHealthIndicator, ServerRow } from "@/components/server/server-row"
@@ -156,13 +156,14 @@ const useMcpToggleMutation = () => {
}))
}
-export function StatusPopoverBody(props: { shown: Accessor }) {
+export function StatusPopoverBody(props: { shown: Accessor; close?: () => void }) {
const sync = useSync()
const server = useServer()
const platform = usePlatform()
const dialog = useDialog()
const language = useLanguage()
const navigate = useNavigate()
+ const location = useLocation()
const fail = (err: unknown) => {
showToast({
@@ -251,8 +252,16 @@ export function StatusPopoverBody(props: { shown: Accessor }) {
aria-disabled={blocked()}
onClick={() => {
if (blocked()) return
+ props.close?.()
navigate("/")
- queueMicrotask(() => server.setActive(key))
+ const activate = () => {
+ if (location.pathname !== "/") {
+ setTimeout(activate, 16)
+ return
+ }
+ setTimeout(() => server.setActive(key), 0)
+ }
+ setTimeout(activate, 0)
}}
>
diff --git a/packages/app/src/components/status-popover.tsx b/packages/app/src/components/status-popover.tsx
index 6820a940b0..152cddffc8 100644
--- a/packages/app/src/components/status-popover.tsx
+++ b/packages/app/src/components/status-popover.tsx
@@ -58,7 +58,7 @@ export function StatusPopover() {
}
>
-
+ setShown(false)} />
diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx
index 6190deb1ee..0a729a38de 100644
--- a/packages/app/src/context/global-sync.tsx
+++ b/packages/app/src/context/global-sync.tsx
@@ -371,11 +371,7 @@ function createGlobalSync() {
onCleanup(() => {
queue.dispose()
})
- onCleanup(() => {
- for (const directory of Object.keys(children.children)) {
- children.disposeDirectory(directoryKey(directory))
- }
- })
+ onCleanup(children.disposeAll)
onMount(() => {
if (typeof requestAnimationFrame === "function") {
diff --git a/packages/app/src/context/global-sync/child-store.ts b/packages/app/src/context/global-sync/child-store.ts
index 0138310cdc..411102e26f 100644
--- a/packages/app/src/context/global-sync/child-store.ts
+++ b/packages/app/src/context/global-sync/child-store.ts
@@ -92,6 +92,22 @@ export function createChildStoreManager(input: {
})
}
+ function disposeChild(key: DirectoryKey) {
+ const dispose = disposers.get(key)
+ if (!key || !children[key]) return false
+ vcsCache.delete(key)
+ metaCache.delete(key)
+ iconCache.delete(key)
+ lifecycle.delete(key)
+ disposers.delete(key)
+ delete children[key]
+ input.onDispose(key)
+ if (dispose) {
+ dispose()
+ }
+ return true
+ }
+
function disposeDirectory(directory: DirectoryKey) {
const key = directory
if (
@@ -106,18 +122,13 @@ export function createChildStoreManager(input: {
return false
}
- vcsCache.delete(key)
- metaCache.delete(key)
- iconCache.delete(key)
- lifecycle.delete(key)
- const dispose = disposers.get(key)
- if (dispose) {
- dispose()
- disposers.delete(key)
+ return disposeChild(key)
+ }
+
+ function disposeAll() {
+ for (const directory of Object.keys(children)) {
+ disposeChild(directoryKey(directory))
}
- delete children[key]
- input.onDispose(key)
- return true
}
function runEviction(skip?: string) {
@@ -329,6 +340,7 @@ export function createChildStoreManager(input: {
unpin,
pinned,
disposeDirectory,
+ disposeAll,
runEviction,
vcsCache,
metaCache,
diff --git a/packages/app/src/utils/solid-dnd.tsx b/packages/app/src/utils/solid-dnd.tsx
index 8e30a033ae..363db50814 100644
--- a/packages/app/src/utils/solid-dnd.tsx
+++ b/packages/app/src/utils/solid-dnd.tsx
@@ -1,6 +1,6 @@
import { useDragDropContext } from "@thisbeyond/solid-dnd"
import type { Transformer } from "@thisbeyond/solid-dnd"
-import { createRoot, onCleanup, type JSXElement } from "solid-js"
+import type { JSXElement } from "solid-js"
type DragEvent = { draggable?: { id?: unknown } }
@@ -27,20 +27,16 @@ const createAxisConstraint = (axis: "x" | "y", transformerId: string) => (): JSX
if (!context) return null
const [, { onDragStart, onDragEnd, addTransformer, removeTransformer }] = context
const transformer = createTransformer(transformerId, axis)
- const dispose = createRoot((dispose) => {
- onDragStart((event) => {
- const id = getDraggableId(event)
- if (!id) return
- addTransformer("draggables", id, transformer)
- })
- onDragEnd((event) => {
- const id = getDraggableId(event)
- if (!id) return
- removeTransformer("draggables", id, transformer.id)
- })
- return dispose
+ onDragStart((event) => {
+ const id = getDraggableId(event)
+ if (!id) return
+ addTransformer("draggables", id, transformer)
+ })
+ onDragEnd((event) => {
+ const id = getDraggableId(event)
+ if (!id) return
+ removeTransformer("draggables", id, transformer.id)
})
- onCleanup(dispose)
return null
}
diff --git a/packages/desktop-electron/src/main/index.ts b/packages/desktop-electron/src/main/index.ts
index b12dcb3b17..e0e1a37e0f 100644
--- a/packages/desktop-electron/src/main/index.ts
+++ b/packages/desktop-electron/src/main/index.ts
@@ -87,6 +87,7 @@ setupApp()
function setupApp() {
ensureLoopbackNoProxy()
app.commandLine.appendSwitch("proxy-bypass-list", "<-loopback>")
+ if (!app.isPackaged) app.commandLine.appendSwitch("remote-debugging-port", "9222")
if (!app.requestSingleInstanceLock()) {
app.quit()