From 2eb3072e3e5b251931be54973e75dab4a322880e Mon Sep 17 00:00:00 2001 From: LukeParkerDev <10430890+Hona@users.noreply.github.com> Date: Wed, 29 Apr 2026 08:37:16 +1000 Subject: [PATCH] review --- .../app/src/components/dialog-wsl-server.tsx | 3 +- packages/app/src/components/prompt-input.tsx | 8 ++-- packages/app/src/components/terminal.tsx | 21 +++------ packages/app/src/context/global-sync.tsx | 10 ++--- .../app/src/context/global-sync/bootstrap.ts | 17 +++---- packages/app/src/context/platform.tsx | 7 --- packages/app/src/context/server.tsx | 15 +------ packages/app/src/context/wsl-servers.tsx | 21 +++++---- packages/app/src/index.ts | 1 - .../src/pages/layout/sidebar-workspace.tsx | 45 +++++-------------- packages/app/src/utils/server-health.ts | 27 ----------- packages/desktop-electron/src/main/index.ts | 9 ---- packages/desktop-electron/src/main/ipc.ts | 24 ---------- .../desktop-electron/src/main/wsl-servers.ts | 19 +------- packages/desktop-electron/src/main/wsl.ts | 10 +---- .../desktop-electron/src/preload/index.ts | 2 - .../desktop-electron/src/preload/types.ts | 11 ----- .../desktop-electron/src/renderer/index.tsx | 17 +++---- 18 files changed, 55 insertions(+), 212 deletions(-) diff --git a/packages/app/src/components/dialog-wsl-server.tsx b/packages/app/src/components/dialog-wsl-server.tsx index 5a1b4a21d1..4123221824 100644 --- a/packages/app/src/components/dialog-wsl-server.tsx +++ b/packages/app/src/components/dialog-wsl-server.tsx @@ -5,10 +5,11 @@ import { showToast } from "@opencode-ai/ui/toast" import { createEffect, createMemo, For, Match, onCleanup, Show, Switch } from "solid-js" import { createStore } from "solid-js/store" import { useLanguage } from "@/context/language" -import type { WslServerStep } from "@/context/platform" import { usePlatform } from "@/context/platform" import { useWslServers } from "@/context/wsl-servers" +type WslServerStep = "wsl" | "distro" | "opencode" + const STEPS: WslServerStep[] = ["wsl", "distro", "opencode"] function isHiddenDistro(name: string) { diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index 474a1af580..a85e160d10 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -33,7 +33,6 @@ import { Persist, persisted } from "@/utils/persist" import { usePermission } from "@/context/permission" import { useLanguage } from "@/context/language" import { usePlatform } from "@/context/platform" -import { useServer } from "@/context/server" import { useSessionLayout } from "@/pages/session/session-layout" import { createSessionTabs } from "@/pages/session/helpers" import { createTextFragment, getCursorPosition, setCursorPosition, setRangeEdge } from "./prompt-input/editor-dom" @@ -113,7 +112,6 @@ export const PromptInput: Component = (props) => { const dialog = useDialog() const providers = useProviders() const command = useCommand() - const server = useServer() const permission = usePermission() const language = useLanguage() const platform = usePlatform() @@ -1256,9 +1254,9 @@ export const PromptInput: Component = (props) => { const [agentsQuery, globalProvidersQuery, providersQuery] = useQueries(() => ({ queries: [ - loadAgentsQuery(sdk.directory, server.key), - loadProvidersQuery(null, server.key), - loadProvidersQuery(sdk.directory, server.key), + loadAgentsQuery(sdk.directory), + loadProvidersQuery(null), + loadProvidersQuery(sdk.directory), ], })) diff --git a/packages/app/src/components/terminal.tsx b/packages/app/src/components/terminal.tsx index f31a584ee8..12e1ba5e3f 100644 --- a/packages/app/src/components/terminal.tsx +++ b/packages/app/src/components/terminal.tsx @@ -194,11 +194,11 @@ export const Terminal = (props: TerminalProps) => { const server = useServer() const directory = sdk.directory const client = sdk.client + const url = sdk.url const auth = server.current?.http const username = auth?.username ?? "opencode" const password = auth?.password ?? "" - const currentUrl = () => server.current?.http.url ?? sdk.url - const sameOrigin = () => new URL(currentUrl(), location.href).origin === location.origin + const sameOrigin = new URL(url, location.href).origin === location.origin let container!: HTMLDivElement const [local, others] = splitProps(props, ["pty", "class", "classList", "autoFocus", "onConnect", "onConnectError"]) const id = local.pty.id @@ -525,18 +525,11 @@ export const Terminal = (props: TerminalProps) => { if (disposed) return drop?.() - const baseUrl = currentUrl() - if (sdk.url !== baseUrl) { - console.error( - `[terminal panic] sdk.url mismatch id=${id} serverKey=${server.key ?? ""} directory=${directory} sdkUrl=${sdk.url} currentUrl=${baseUrl}`, - ) - } - - const next = new URL(baseUrl + `/pty/${id}/connect`) + const next = new URL(url + `/pty/${id}/connect`) next.searchParams.set("directory", directory) next.searchParams.set("cursor", String(seek)) next.protocol = next.protocol === "https:" ? "wss:" : "ws:" - if (!sameOrigin() && password) { + if (!sameOrigin && password) { next.searchParams.set("auth_token", btoa(`${username}:${password}`)) // For same-origin requests, let the browser reuse the page's existing auth. next.username = username @@ -549,7 +542,7 @@ export const Terminal = (props: TerminalProps) => { directory, restoreLength: restore.length, sdkUrl: sdk.url, - currentUrl: baseUrl, + currentUrl: url, wsUrl: next.toString(), }) @@ -564,7 +557,7 @@ export const Terminal = (props: TerminalProps) => { id, serverKey: server.key ?? null, directory, - currentUrl: baseUrl, + currentUrl: url, }) // Paint the saved buffer now that we've confirmed the pty really // exists on the current sidecar. Fire-and-forget: write()'s own @@ -630,7 +623,7 @@ export const Terminal = (props: TerminalProps) => { directory, code: event.code, reason: event.reason || null, - currentUrl: baseUrl, + currentUrl: url, }) retry(new Error(language.t("terminal.connectionLost.abnormalClose", { code: event.code }))) } diff --git a/packages/app/src/context/global-sync.tsx b/packages/app/src/context/global-sync.tsx index f35b979f5b..86496bad50 100644 --- a/packages/app/src/context/global-sync.tsx +++ b/packages/app/src/context/global-sync.tsx @@ -14,7 +14,6 @@ import { createStore, produce, reconcile } from "solid-js/store" import { useLanguage } from "@/context/language" import type { InitError } from "../pages/error" import { useGlobalSDK } from "./global-sdk" -import { useServer } from "./server" import { bootstrapDirectory, bootstrapGlobal, clearProviderRev } from "./global-sync/bootstrap" import { createChildStoreManager } from "./global-sync/child-store" import { applyDirectoryEvent, applyGlobalEvent, cleanupDroppedSessionCaches } from "./global-sync/event-reducer" @@ -41,12 +40,11 @@ type GlobalStore = { reload: undefined | "pending" | "complete" } -export const loadSessionsQuery = (directory: string, serverKey: string | undefined) => - queryOptions({ queryKey: [serverKey, directory, "loadSessions"], queryFn: skipToken }) +export const loadSessionsQuery = (directory: string) => + queryOptions({ queryKey: [directory, "loadSessions"], queryFn: skipToken }) function createGlobalSync() { const globalSDK = useGlobalSDK() - const server = useServer() const language = useLanguage() const owner = getOwner() if (!owner) throw new Error("GlobalSync must be created within owner") @@ -171,7 +169,7 @@ function createGlobalSync() { const limit = Math.max(store.limit + SESSION_RECENT_LIMIT, SESSION_RECENT_LIMIT) const promise = queryClient .fetchQuery({ - ...loadSessionsQuery(directory, server.key), + ...loadSessionsQuery(directory), queryFn: () => loadRootSessionsWithFallback({ directory, @@ -237,7 +235,6 @@ function createGlobalSync() { const sdk = sdkFor(directory) await bootstrapDirectory({ directory, - serverKey: server.key, global: { config: globalStore.config, path: globalStore.path, @@ -337,7 +334,6 @@ function createGlobalSync() { try { await bootstrapGlobal({ globalSDK: globalSDK.client, - serverKey: server.key, requestFailedTitle: language.t("common.requestFailed"), translate: language.t, formatMoreCount: (count) => language.t("common.moreCountSuffix", { count }), diff --git a/packages/app/src/context/global-sync/bootstrap.ts b/packages/app/src/context/global-sync/bootstrap.ts index dde86a98f7..a83030fad2 100644 --- a/packages/app/src/context/global-sync/bootstrap.ts +++ b/packages/app/src/context/global-sync/bootstrap.ts @@ -68,7 +68,6 @@ function runAll(list: Array<() => Promise>) { export async function bootstrapGlobal(input: { globalSDK: OpencodeClient - serverKey: string | undefined requestFailedTitle: string translate: (key: string, vars?: Record) => string formatMoreCount: (count: number) => string @@ -87,7 +86,7 @@ export async function bootstrapGlobal(input: { const slow = [ () => input.queryClient.fetchQuery({ - ...loadProvidersQuery(null, input.serverKey), + ...loadProvidersQuery(null), queryFn: () => retry(() => input.globalSDK.provider.list().then((x) => { @@ -180,17 +179,16 @@ function warmSessions(input: { ).then(() => undefined) } -export const loadProvidersQuery = (directory: string | null, serverKey: string | undefined) => - queryOptions({ queryKey: [serverKey, directory, "providers"], queryFn: skipToken }) +export const loadProvidersQuery = (directory: string | null) => + queryOptions({ queryKey: [directory, "providers"], queryFn: skipToken }) export const loadAgentsQuery = ( directory: string | null, - serverKey: string | undefined, sdk?: OpencodeClient, transform?: (x: Awaited>) => void, ) => queryOptions({ - queryKey: [serverKey, directory, "agents"], + queryKey: [directory, "agents"], queryFn: sdk && transform ? () => @@ -224,7 +222,6 @@ export const loadPathQuery = ( export async function bootstrapDirectory(input: { directory: string - serverKey: string | undefined sdk: OpencodeClient store: Store setStore: SetStoreFunction @@ -266,9 +263,7 @@ export async function bootstrapDirectory(input: { () => Promise.resolve(input.loadSessions(input.directory)), () => input.queryClient.ensureQueryData( - loadAgentsQuery(input.directory, input.serverKey, input.sdk, (x) => - input.setStore("agent", normalizeAgentList(x.data)), - ), + loadAgentsQuery(input.directory, input.sdk, (x) => input.setStore("agent", normalizeAgentList(x.data))), ), () => retry(() => input.sdk.config.get().then((x) => input.setStore("config", reconcile(x.data!, { merge: false })))), @@ -354,7 +349,7 @@ export async function bootstrapDirectory(input: { ), () => input.queryClient.ensureQueryData({ - ...loadProvidersQuery(input.directory, input.serverKey), + ...loadProvidersQuery(input.directory), queryFn: () => retry(() => input.sdk.provider.list()) .then((x) => { diff --git a/packages/app/src/context/platform.tsx b/packages/app/src/context/platform.tsx index 4221f31831..928ed5ee2e 100644 --- a/packages/app/src/context/platform.tsx +++ b/packages/app/src/context/platform.tsx @@ -9,17 +9,13 @@ type OpenFilePickerOptions = { title?: string; multiple?: boolean; accept?: stri type SaveFilePickerOptions = { title?: string; defaultPath?: string } type UpdateInfo = { updateAvailable: boolean; version?: string } -export type WslServerStep = "wsl" | "distro" | "opencode" - export type WslRuntimeCheck = { available: boolean version: string | null - status: string | null error: string | null } export type WslInstalledDistro = { name: string - state: string | null version: number | null isDefault: boolean } @@ -32,7 +28,6 @@ export type WslDistroProbe = { canExecute: boolean hasBash: boolean hasCurl: boolean - username: string | null isRoot: boolean | null error: string | null } @@ -95,8 +90,6 @@ export type WslServersPlatform = { addServer(distro: string): Promise removeServer(id: string): Promise startServer(id: string): Promise - stopServer(id: string): Promise - cancelJob(): Promise } export type Platform = { diff --git a/packages/app/src/context/server.tsx b/packages/app/src/context/server.tsx index 67d2ad3cd4..2bc8951837 100644 --- a/packages/app/src/context/server.tsx +++ b/packages/app/src/context/server.tsx @@ -228,19 +228,7 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext( }) } - const check = (conn: ServerConnection.Any) => - checkServerHealth(conn.http).then((x) => { - if (!x.healthy) { - // Electron's console-message bridge only preserves the first - // console argument, so pre-stringify everything into one string. - console.warn( - `[server health] unhealthy key=${ServerConnection.key(conn)} url=${conn.http.url} hasAuth=${!!( - conn.http.username || conn.http.password - )}`, - ) - } - return x.healthy - }) + const check = (conn: ServerConnection.Any) => checkServerHealth(conn.http).then((x) => x.healthy) createEffect(() => { const key = state.active @@ -275,7 +263,6 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext( return } setState("healthy", undefined) - console.log(`[server health] start polling key=${ServerConnection.key(current_)} url=${current_.http.url}`) onCleanup(startHealthPolling(current_)) }) diff --git a/packages/app/src/context/wsl-servers.tsx b/packages/app/src/context/wsl-servers.tsx index 0668c905f6..e38f857aa8 100644 --- a/packages/app/src/context/wsl-servers.tsx +++ b/packages/app/src/context/wsl-servers.tsx @@ -4,23 +4,22 @@ import { createEffect, onCleanup } from "solid-js" import type { WslServersPlatform, WslServersState } from "./platform" import { usePlatform } from "./platform" -export const wslServersQueryKey = ["platform", "wslServers"] as const - -export function wslServersQueryOptions(api: WslServersPlatform | undefined) { - return queryOptions({ - queryKey: wslServersQueryKey, - queryFn: api ? () => api.getState() : skipToken, - staleTime: Number.POSITIVE_INFINITY, - gcTime: Number.POSITIVE_INFINITY, - }) -} +const wslServersQueryKey = ["platform", "wslServers"] as const export const { use: useWslServers, provider: WslServersProvider } = createSimpleContext({ name: "WslServers", init: () => { const platform = usePlatform() const queryClient = useQueryClient() - const query = useQuery(() => ({ ...wslServersQueryOptions(platform.wslServers) })) + const query = useQuery(() => { + const api = platform.wslServers + return queryOptions({ + queryKey: wslServersQueryKey, + queryFn: api ? () => api.getState() : skipToken, + staleTime: Number.POSITIVE_INFINITY, + gcTime: Number.POSITIVE_INFINITY, + }) + }) createEffect(() => { const api = platform.wslServers diff --git a/packages/app/src/index.ts b/packages/app/src/index.ts index b960238e9a..2b5feecd74 100644 --- a/packages/app/src/index.ts +++ b/packages/app/src/index.ts @@ -16,7 +16,6 @@ export { type WslServersEvent, type WslServersPlatform, type WslServersState, - type WslServerStep, } from "./context/platform" export { ServerConnection } from "./context/server" export { handleNotificationClick } from "./utils/notification-click" diff --git a/packages/app/src/pages/layout/sidebar-workspace.tsx b/packages/app/src/pages/layout/sidebar-workspace.tsx index 77d8a7d7f8..7b235e6d16 100644 --- a/packages/app/src/pages/layout/sidebar-workspace.tsx +++ b/packages/app/src/pages/layout/sidebar-workspace.tsx @@ -16,7 +16,6 @@ import { type Session } from "@opencode-ai/sdk/v2/client" import { type LocalProject } from "@/context/layout" import { loadSessionsQuery, useGlobalSync } from "@/context/global-sync" import { useLanguage } from "@/context/language" -import { useServer } from "@/context/server" import { NewSessionItem, SessionItem, SessionSkeleton } from "./sidebar-items" import { sortedRootSessions, workspaceKey } from "./helpers" import { useQuery } from "@tanstack/solid-query" @@ -320,19 +319,12 @@ export const SortableWorkspace = (props: { }) const slug = createMemo(() => base64Encode(props.directory)) const sessions = createMemo(() => sortedRootSessions(workspaceStore, props.sortNow())) - // Guard against `props.project` being transiently undefined during a - // server-switch cascade. The parent renders - // {(dir) => } - // where `project()` can flip to undefined while the enclosing - // gate hasn't yet unmounted this child. Bootstrap's setStore can then fire - // these memos with stale props. - const local = createMemo(() => props.directory === (props.project?.worktree ?? "")) + const local = createMemo(() => props.directory === props.project.worktree) const active = createMemo(() => workspaceKey(props.ctx.currentDir()) === workspaceKey(props.directory)) - const server = useServer() const workspaceValue = createMemo(() => { const branch = workspaceStore.vcs?.branch const name = branch ?? getFilename(props.directory) - const projectId = props.project?.id + const projectId = props.project.id if (!projectId) return name return props.ctx.workspaceName(props.directory, projectId, branch) ?? name }) @@ -340,7 +332,7 @@ export const SortableWorkspace = (props: { const boot = createMemo(() => open() || active()) const count = createMemo(() => sessions()?.length ?? 0) const hasMore = createMemo(() => workspaceStore.sessionTotal > count()) - const query = useQuery(() => ({ ...loadSessionsQuery(props.project.worktree, server.key) })) + const query = useQuery(() => ({ ...loadSessionsQuery(props.project.worktree) })) const busy = createMemo(() => props.ctx.isBusy(props.directory)) const loading = () => query.isLoading && count() === 0 const touch = createMediaQuery("(hover: none)") @@ -364,7 +356,7 @@ export const SortableWorkspace = (props: { InlineEditor={props.ctx.InlineEditor} renameWorkspace={props.ctx.renameWorkspace} setEditor={props.ctx.setEditor} - projectId={props.project?.id ?? ""} + projectId={props.project.id ?? ""} /> ) @@ -433,7 +425,7 @@ export const SortableWorkspace = (props: { openEditor={props.ctx.openEditor} showResetWorkspaceDialog={props.ctx.showResetWorkspaceDialog} showDeleteWorkspaceDialog={props.ctx.showDeleteWorkspaceDialog} - root={props.project?.worktree ?? props.directory} + root={props.project.worktree} clearHoverProjectSoon={props.ctx.clearHoverProjectSoon} navigateToNewSession={() => navigate(`/${slug()}/session`)} /> @@ -467,33 +459,20 @@ export const LocalWorkspace = (props: { }): JSX.Element => { const globalSync = useGlobalSync() const language = useLanguage() - const server = useServer() - // Same guard pattern as SortableWorkspace: the parent passes - // `project={project()!}` but `project()` can transiently flip to - // undefined during a server-switch cascade before this component - // unmounts, so every reactive memo reading props.project has to - // tolerate undefined. - const worktree = createMemo(() => props.project?.worktree ?? "") + const worktree = createMemo(() => props.project.worktree) const workspace = createMemo(() => { - const dir = worktree() - if (!dir) return undefined - const [store, setStore] = globalSync.child(dir) + const [store, setStore] = globalSync.child(worktree()) return { store, setStore } }) - const slug = createMemo(() => (worktree() ? base64Encode(worktree()) : "")) - const sessions = createMemo(() => { - const store = workspace()?.store - return store ? sortedRootSessions(store, props.sortNow()) : [] - }) - const booted = createMemo((prev) => prev || workspace()?.store.status === "complete", false) + const slug = createMemo(() => base64Encode(worktree())) + const sessions = createMemo(() => sortedRootSessions(workspace().store, props.sortNow())) const count = createMemo(() => sessions()?.length ?? 0) - const query = useQuery(() => ({ ...loadSessionsQuery(worktree(), server.key) })) + const query = useQuery(() => ({ ...loadSessionsQuery(worktree()) })) const loading = createMemo(() => query.isPending && count() === 0) - const hasMore = createMemo(() => (workspace()?.store.sessionTotal ?? 0) > count()) + const hasMore = createMemo(() => workspace().store.sessionTotal > count()) const loadMore = async () => { const dir = worktree() - if (!dir) return - workspace()?.setStore("limit", (limit) => (limit ?? 0) + 5) + workspace().setStore("limit", (limit) => (limit ?? 0) + 5) await globalSync.project.loadSessions(dir) } diff --git a/packages/app/src/utils/server-health.ts b/packages/app/src/utils/server-health.ts index 1b054c4ffd..52c82dbebf 100644 --- a/packages/app/src/utils/server-health.ts +++ b/packages/app/src/utils/server-health.ts @@ -65,21 +65,6 @@ function retryable(error: unknown, signal?: AbortSignal) { return /network|fetch|econnreset|econnrefused|enotfound|timedout/i.test(error.message) } -function serializeError(error: unknown): unknown { - if (error instanceof Error) { - return { - name: error.name, - message: error.message, - stack: error.stack, - } - } - return error -} - -function stringifyLog(label: string, value: unknown) { - return `${label} ${JSON.stringify(value)}` -} - export async function checkServerHealth( server: ServerConnection.HttpBase, fetch: typeof globalThis.fetch, @@ -89,19 +74,7 @@ export async function checkServerHealth( const signal = opts?.signal ?? timeout?.signal const retryCount = opts?.retryCount ?? defaultRetryCount const retryDelayMs = opts?.retryDelayMs ?? defaultRetryDelayMs - const logFailure = (phase: string, count: number, error: unknown) => { - console.error( - stringifyLog("[server health] request failed", { - phase, - attempt: count + 1, - url: server.url, - hasAuth: !!server.password, - error: serializeError(error), - }), - ) - } const next = (count: number, error: unknown) => { - logFailure("retry", count, error) if (count >= retryCount || !retryable(error, signal)) return Promise.resolve({ healthy: false } as const) return wait(retryDelayMs * (count + 1), signal) .then(() => attempt(count + 1)) diff --git a/packages/desktop-electron/src/main/index.ts b/packages/desktop-electron/src/main/index.ts index d98282f264..ad13359892 100644 --- a/packages/desktop-electron/src/main/index.ts +++ b/packages/desktop-electron/src/main/index.ts @@ -181,18 +181,11 @@ async function initialize() { const hostname = "127.0.0.1" const url = `http://${hostname}:${port}` const password = randomUUID() - const key = "local:windows" const startupData: ServerReadyData = { url, username: "opencode", password, - local: { - key, - url, - username: "opencode", - password, - }, } const loadingTask = (async () => { logger.log("sidecar connection started", { url }) @@ -371,8 +364,6 @@ registerIpcHandlers({ wslServersAddServer: (distro) => wslServers.addServer(distro), wslServersRemoveServer: (id) => wslServers.removeServer(id), wslServersStartServer: (id) => wslServers.startServer(id), - wslServersStopServer: (id) => wslServers.stopServer(id), - wslServersCancelJob: () => wslServers.cancelJob(), getWindowConfig: () => ({ updaterEnabled: UPDATER_ENABLED }), consumeInitialDeepLinks: () => pendingDeepLinks.splice(0), getDefaultServerUrl: () => getDefaultServerUrl(), diff --git a/packages/desktop-electron/src/main/ipc.ts b/packages/desktop-electron/src/main/ipc.ts index fc6cec5204..82563e6aa6 100644 --- a/packages/desktop-electron/src/main/ipc.ts +++ b/packages/desktop-electron/src/main/ipc.ts @@ -37,8 +37,6 @@ type Deps = { wslServersAddServer: (distro: string) => Promise | WslServerConfig wslServersRemoveServer: (id: string) => Promise | void wslServersStartServer: (id: string) => Promise | void - wslServersStopServer: (id: string) => Promise | void - wslServersCancelJob: () => Promise | void getWindowConfig: () => Promise | WindowConfig consumeInitialDeepLinks: () => Promise | string[] getDefaultServerUrl: () => Promise | string | null @@ -57,13 +55,6 @@ type Deps = { } export function registerIpcHandlers(deps: Deps) { - const debugStore = (op: string, name: string, key: string, meta?: Record) => { - if (app.isPackaged) return - if (!name.startsWith("opencode.workspace.")) return - if (!key.includes("terminal")) return - console.log(`[store ${op}] ${JSON.stringify({ name, key, ...meta })}`) - } - const requireString = (name: string, value: unknown) => { if (typeof value === "string" && value.length > 0) return value throw new Error(`Invalid ${name}`) @@ -165,10 +156,6 @@ export function registerIpcHandlers(deps: Deps) { handle("wsl-servers-start", (_event: IpcMainInvokeEvent, id: string) => deps.wslServersStartServer(requireString("server id", id)), ) - handle("wsl-servers-stop", (_event: IpcMainInvokeEvent, id: string) => - deps.wslServersStopServer(requireString("server id", id)), - ) - handle("wsl-servers-cancel", () => deps.wslServersCancelJob()) handle("get-window-config", () => deps.getWindowConfig()) handle("consume-initial-deep-links", () => deps.consumeInitialDeepLinks()) handle("get-default-server-url", () => deps.getDefaultServerUrl()) @@ -195,24 +182,13 @@ export function registerIpcHandlers(deps: Deps) { handle("store-get", (_event: IpcMainInvokeEvent, name: string, key: string) => { const store = getStore(name) const value = store.get(key) - debugStore("get", name, key, { - found: value !== undefined && value !== null, - length: - typeof value === "string" - ? value.length - : value === undefined || value === null - ? 0 - : JSON.stringify(value).length, - }) if (value === undefined || value === null) return null return typeof value === "string" ? value : JSON.stringify(value) }) handle("store-set", (_event: IpcMainInvokeEvent, name: string, key: string, value: string) => { - debugStore("set", name, key, { length: value.length }) getStore(name).set(key, value) }) handle("store-delete", (_event: IpcMainInvokeEvent, name: string, key: string) => { - debugStore("delete", name, key) getStore(name).delete(key) }) handle("store-clear", (_event: IpcMainInvokeEvent, name: string) => { diff --git a/packages/desktop-electron/src/main/wsl-servers.ts b/packages/desktop-electron/src/main/wsl-servers.ts index 4c5885e4ec..8614c6647b 100644 --- a/packages/desktop-electron/src/main/wsl-servers.ts +++ b/packages/desktop-electron/src/main/wsl-servers.ts @@ -120,14 +120,11 @@ export function createWslServersController(appVersion: string, spawnSidecar: Spa } const refreshDistroLists = async (opts: { signal?: AbortSignal }) => { - const [installedResult, onlineResult] = await Promise.allSettled([ + const [installed, online] = await Promise.all([ listInstalledWslDistros(opts), listOnlineWslDistros(opts), ]) - return { - installed: installedResult.status === "fulfilled" ? installedResult.value : [], - online: onlineResult.status === "fulfilled" ? onlineResult.value : [], - } + return { installed, online } } const nextStartAttempt = (id: string) => { @@ -316,12 +313,6 @@ export function createWslServersController(appVersion: string, spawnSidecar: Spa await openWslTerminal(name) }, - async cancelJob() { - jobAbort?.abort() - jobAbort = undefined - setState({ job: null }) - }, - async addServer(distro: string): Promise { const id = wslServerIdForDistro(distro) if (state.servers.some((item) => item.config.id === id)) { @@ -349,12 +340,6 @@ export function createWslServersController(appVersion: string, spawnSidecar: Spa startServer, - async stopServer(id: string) { - invalidateStartAttempt(id) - await stopServerInternal(id) - setRuntime(id, { kind: "stopped" }) - }, - stopAll() { for (const item of state.servers) invalidateStartAttempt(item.config.id) for (const existing of sidecars.values()) { diff --git a/packages/desktop-electron/src/main/wsl.ts b/packages/desktop-electron/src/main/wsl.ts index 6f05ec96f8..b8267bc77d 100644 --- a/packages/desktop-electron/src/main/wsl.ts +++ b/packages/desktop-electron/src/main/wsl.ts @@ -277,16 +277,13 @@ export async function probeWslRuntime(opts?: RunWslOptions): Promise undefined) return { available: true, version: firstLine(version.stdout), - status: status?.code === 0 ? summarize(status.stdout) : null, error: null, } } @@ -351,7 +348,6 @@ export async function probeWslDistro(name: string, opts?: RunWslOptions): Promis canExecute: false, hasBash: false, hasCurl: false, - username: null, isRoot: null, error: summarize(executable.stderr || executable.stdout) || "Cannot execute commands in distro", } @@ -369,7 +365,6 @@ export async function probeWslDistro(name: string, opts?: RunWslOptions): Promis canExecute: true, hasBash: bash.code === 0 && summarize(bash.stdout) === "yes", hasCurl: curl.code === 0 && summarize(curl.stdout) === "yes", - username: username || null, isRoot: username ? username === "root" : null, error: null, } @@ -472,14 +467,13 @@ function parseInstalledDistros(output: string) { return output.split(/\r?\n/g).flatMap((line) => { const trimmed = line.trim() if (!trimmed) return [] - const match = line.match(/^\s*(\*)?\s*(.*?)\s{2,}(\S+)\s+(\d+)\s*$/) + const match = line.match(/^\s*(\*)?\s*(.*?)\s{2,}\S+\s+(\d+)\s*$/) if (!match) return [] - const [, marker, name, state, version] = match + const [, marker, name, version] = match if (!name || /^name$/i.test(name)) return [] return [ { name: name.trim(), - state: state || null, version: Number.isNaN(Number.parseInt(version, 10)) ? null : Number.parseInt(version, 10), isDefault: marker === "*", } satisfies WslInstalledDistro, diff --git a/packages/desktop-electron/src/preload/index.ts b/packages/desktop-electron/src/preload/index.ts index b72ac6b934..bdda548d47 100644 --- a/packages/desktop-electron/src/preload/index.ts +++ b/packages/desktop-electron/src/preload/index.ts @@ -33,8 +33,6 @@ const api: ElectronAPI = { addServer: (distro) => ipcRenderer.invoke("wsl-servers-add", distro), removeServer: (id) => ipcRenderer.invoke("wsl-servers-remove", id), startServer: (id) => ipcRenderer.invoke("wsl-servers-start", id), - stopServer: (id) => ipcRenderer.invoke("wsl-servers-stop", id), - cancelJob: () => ipcRenderer.invoke("wsl-servers-cancel"), }, getWindowConfig: () => ipcRenderer.invoke("get-window-config"), consumeInitialDeepLinks: () => ipcRenderer.invoke("consume-initial-deep-links"), diff --git a/packages/desktop-electron/src/preload/types.ts b/packages/desktop-electron/src/preload/types.ts index f2e379e8b1..b8bb7790b1 100644 --- a/packages/desktop-electron/src/preload/types.ts +++ b/packages/desktop-electron/src/preload/types.ts @@ -4,12 +4,6 @@ export type ServerReadyData = { url: string username: string | null password: string | null - local: { - key: string - url: string - username: string | null - password: string | null - } } export type SqliteMigrationProgress = { type: "InProgress"; value: number } | { type: "Done" } @@ -17,12 +11,10 @@ export type SqliteMigrationProgress = { type: "InProgress"; value: number } | { export type WslRuntimeCheck = { available: boolean version: string | null - status: string | null error: string | null } export type WslInstalledDistro = { name: string - state: string | null version: number | null isDefault: boolean } @@ -35,7 +27,6 @@ export type WslDistroProbe = { canExecute: boolean hasBash: boolean hasCurl: boolean - username: string | null isRoot: boolean | null error: string | null } @@ -98,8 +89,6 @@ export type WslServersAPI = { addServer: (distro: string) => Promise removeServer: (id: string) => Promise startServer: (id: string) => Promise - stopServer: (id: string) => Promise - cancelJob: () => Promise } export type LinuxDisplayBackend = "wayland" | "auto" diff --git a/packages/desktop-electron/src/renderer/index.tsx b/packages/desktop-electron/src/renderer/index.tsx index a60176b8d7..ef9a34e8b2 100644 --- a/packages/desktop-electron/src/renderer/index.tsx +++ b/packages/desktop-electron/src/renderer/index.tsx @@ -134,13 +134,13 @@ const createPlatform = (): Platform => { const wslHome = async () => { const distro = activeWslDistro() if (!distro) return undefined - return window.api.wslPath("~", "windows", distro).catch(() => undefined) + return window.api.wslPath("~", "windows", distro) } const handleWslPicker = async (result: T): Promise => { const distro = activeWslDistro() if (!result || !distro) return result - const convert = (path: string) => window.api.wslPath(path, "linux", distro).catch(() => path) + const convert = (path: string) => window.api.wslPath(path, "linux", distro) if (Array.isArray(result)) { return (await Promise.all(result.map(convert))) as T } @@ -217,10 +217,7 @@ const createPlatform = (): Platform => { const resolvedApp = app ? await window.api.resolveAppPath(app).catch(() => null) : null const resolvedPath = await (async () => { const distro = activeWslDistro() - if (distro) { - const converted = await window.api.wslPath(path, "windows", distro).catch(() => null) - if (converted) return converted - } + if (distro) return window.api.wslPath(path, "windows", distro) return path })() return window.api.openPath(resolvedPath, resolvedApp ?? undefined) @@ -404,9 +401,9 @@ render(() => { type: "sidecar", variant: "base", http: { - url: data.local.url, - username: data.local.username ?? undefined, - password: data.local.password ?? undefined, + url: data.url, + username: data.username ?? undefined, + password: data.password ?? undefined, }, }) } @@ -434,7 +431,7 @@ render(() => { return (