diff --git a/packages/app/src/components/dialog-select-server.tsx b/packages/app/src/components/dialog-select-server.tsx index 4762dddc41..ac0710c339 100644 --- a/packages/app/src/components/dialog-select-server.tsx +++ b/packages/app/src/components/dialog-select-server.tsx @@ -44,7 +44,6 @@ function versionOlderThan(current: string | null | undefined, expected: string | } interface DialogSelectServerProps { - initialView?: "add-wsl" onNavigateHome?: () => void } @@ -163,7 +162,7 @@ export function DialogSelectServer(props: DialogSelectServerProps = {}) { showForm: false, }, addWsl: { - showWizard: props.initialView === "add-wsl", + showWizard: false, }, editServer: { id: undefined as string | undefined, @@ -550,21 +549,6 @@ export function DialogSelectServer(props: DialogSelectServerProps = {}) { if (server.defaultKey() === key) await server.setDefault(null) } - function handleRemoveWsl(conn: ServerConnection.Any) { - if (!isWslSidecar(conn)) return - removeWslMutation.mutate(ServerConnection.key(conn)) - } - - function handleRetryWsl(conn: ServerConnection.Any) { - if (!isWslSidecar(conn)) return - retryWslMutation.mutate(ServerConnection.key(conn)) - } - - function handleUpdateWsl(conn: ServerConnection.Any) { - if (!isWslSidecar(conn)) return - updateWslMutation.mutate(conn.distro) - } - return ( health(key)?.healthy === false const canChangeDefault = () => server.canDefault() && i.type !== "ssh" const canRemove = () => i.type === "http" || wsl - const hasMenuActionsBeforeDelete = () => canRemove() && (i.type === "http" || canChangeDefault() || canRetryWsl(i)) const outdated = () => { const check = wslCheck(i) return versionOlderThan(check?.version, check?.expectedVersion) @@ -668,7 +651,7 @@ export function DialogSelectServer(props: DialogSelectServerProps = {}) { onPointerDown={(e: PointerEvent) => e.stopPropagation()} onClick={(e: MouseEvent) => { e.stopPropagation() - handleUpdateWsl(i) + if (wslDistro) updateWslMutation.mutate(wslDistro) }} > {updating() ? "Updating OpenCode..." : label()} @@ -702,7 +685,7 @@ export function DialogSelectServer(props: DialogSelectServerProps = {}) { - handleRetryWsl(i)}> + retryWslMutation.mutate(key)}> Retry start @@ -720,14 +703,14 @@ export function DialogSelectServer(props: DialogSelectServerProps = {}) { - + { if (wsl) { - handleRemoveWsl(i) + removeWslMutation.mutate(key) return } void handleRemove(key) diff --git a/packages/app/src/components/dialog-wsl-server.tsx b/packages/app/src/components/dialog-wsl-server.tsx index e400da6c58..5a1b4a21d1 100644 --- a/packages/app/src/components/dialog-wsl-server.tsx +++ b/packages/app/src/components/dialog-wsl-server.tsx @@ -244,20 +244,39 @@ export function DialogWslServer(props: DialogWslServerProps = {}) { } } - const steps = createMemo(() => - STEPS.map((step) => ({ - step, - title: stepTitle(step), - state: stepState(step, { - active: activeStep(), - wslReady: wslReady(), - distroReady: distroReady(), - opencodeReady: opencodeReady(), - opencodeMismatch: opencodeCheck()?.matchesDesktop === false, - }), - locked: stepIndex(step) > stepIndex(recommendedStep()), - })), - ) + const steps = createMemo(() => { + const active = activeStep() + const activeIndex = STEPS.indexOf(active) + const recommendedIndex = STEPS.indexOf(recommendedStep()) + return STEPS.map((step) => { + const index = STEPS.indexOf(step) + return { + step, + title: step === "wsl" ? "WSL" : step === "distro" ? "Choose distro" : "OpenCode", + state: + active === step + ? "current" + : step === "wsl" + ? wslReady() + ? "done" + : "warning" + : step === "distro" + ? distroReady() + ? "done" + : index > activeIndex + ? "locked" + : "warning" + : opencodeCheck()?.matchesDesktop === false + ? "warning" + : opencodeReady() + ? "done" + : index > activeIndex + ? "locked" + : "warning", + locked: index > recommendedIndex, + } + }) + }) const loadError = createMemo(() => { const error = wslServers.error if (!error) return "Failed to load WSL state." @@ -554,36 +573,3 @@ function requestError(language: ReturnType, err: unknown) { description: err instanceof Error ? err.message : String(err), }) } - -function stepIndex(step: WslServerStep) { - return STEPS.indexOf(step) -} - -function stepTitle(step: WslServerStep) { - if (step === "wsl") return "WSL" - if (step === "distro") return "Choose distro" - return "OpenCode" -} - -function stepState( - step: WslServerStep, - state: { - active: WslServerStep - wslReady: boolean - distroReady: boolean - opencodeReady: boolean - opencodeMismatch: boolean - }, -) { - if (state.active === step) return "current" - if (step === "wsl") return state.wslReady ? "done" : "warning" - if (step === "distro") - return state.distroReady ? "done" : stepIndex(step) > stepIndex(state.active) ? "locked" : "warning" - return state.opencodeMismatch - ? "warning" - : state.opencodeReady - ? "done" - : stepIndex(step) > stepIndex(state.active) - ? "locked" - : "warning" -} diff --git a/packages/desktop-electron/src/main/wsl.ts b/packages/desktop-electron/src/main/wsl.ts index e65abbd78a..6f05ec96f8 100644 --- a/packages/desktop-electron/src/main/wsl.ts +++ b/packages/desktop-electron/src/main/wsl.ts @@ -265,10 +265,6 @@ export function runWslSh(script: string, distro?: string | null, opts?: RunWslOp return runWslInDistro(["sh", "-lc", script], distro, opts) } -export function runWslBash(script: string, distro?: string | null, opts?: RunWslOptions) { - return runWslInDistro(["bash", "-lc", script], distro, opts) -} - export async function probeWslRuntime(opts?: RunWslOptions): Promise { const version = await runWsl(["--version"], opts).catch((error) => ({ code: 1, diff --git a/todo.md b/todo.md index 2a7dedda7b..ca0c46d059 100644 --- a/todo.md +++ b/todo.md @@ -21,30 +21,30 @@ - [x] [High][L] Revisit `DefaultServer` context; fold into server ownership or make it a real provider instead of ad hoc query hooks. - [x] [High][L] Collapse duplicated server health loops/logging across `ConnectionGate`, `ServerProvider`, dialog, and status popover. -- [ ] [Medium][S] Remove `initialView?: "add-wsl"` from `DialogSelectServer` if no callsites need it. -- [ ] [Medium][S] Remove `handleRemoveWsl`, `handleRetryWsl`, `handleUpdateWsl` guard helpers; callers already know when item is WSL. -- [ ] [Medium][S] Remove `hasMenuActionsBeforeDelete()` from `dialog-select-server.tsx`; inline or always render the separator in the delete block. +- [x] [Medium][S] Remove `initialView?: "add-wsl"` from `DialogSelectServer` if no callsites need it. +- [x] [Medium][S] Remove `handleRemoveWsl`, `handleRetryWsl`, `handleUpdateWsl` guard helpers; callers already know when item is WSL. +- [x] [Medium][S] Remove `hasMenuActionsBeforeDelete()` from `dialog-select-server.tsx`; inline or always render the separator in the delete block. - [x] [Medium][S] Remove UI-only `parseProgressPercent()` and percent display in WSL wizard unless progress is structured by backend. -- [ ] [Medium][S] Remove hard-coded Ubuntu installable distro special-case from UI; backend/platform should return installable distros. -- [ ] [Medium][S] Remove `isHiddenDistro()` UI filter for `docker-desktop`; backend/platform should decide hidden distros if needed. +- [ ] ~~[Medium][S] Remove hard-coded Ubuntu installable distro special-case from UI; backend/platform should return installable distros.~~ (Skipped: changes distro list behavior) +- [ ] ~~[Medium][S] Remove `isHiddenDistro()` UI filter for `docker-desktop`; backend/platform should decide hidden distros if needed.~~ (Skipped: changes visible distro behavior) - [x] [Medium][S] Remove `installProgress()` transcript shaping in WSL wizard; render raw transcript or structured progress. -- [ ] [Medium][S] Remove `stepIndex` / `stepTitle` / `stepState` helpers in WSL wizard; inline the 3-step UI state. -- [ ] [Medium][S] Remove `runWslBash()` from `wsl.ts`; it is unused. +- [x] [Medium][S] Remove `stepIndex` / `stepTitle` / `stepState` helpers in WSL wizard; inline the 3-step UI state. +- [x] [Medium][S] Remove `runWslBash()` from `wsl.ts`; it is unused. - [x] [Medium][S] Remove progress-line de-duping from either `wsl-pty.ts` or `wsl-servers.ts`; keep only one place if kept. -- [ ] [Medium][S] Remove `ensureLoopbackNoProxy()` and Chromium proxy-bypass mutation unless a measured proxy repro exists. -- [ ] [Medium][S] Remove broad renderer global error/rejection logging in Electron renderer unless this PR intentionally adds diagnostics. -- [ ] [Medium][S] Remove `wireWindowDiagnostics()` or move it to a separate diagnostics PR; it is unrelated WSL feature plumbing. -- [ ] [Medium][S] Remove terminal debug logging helpers/calls once current investigation is done. -- [ ] [Medium][S] Remove server-health retry logging helpers (`serializeError`, `stringifyLog`, per-attempt logs`) or dev-gate one final warning. -- [ ] [Medium][S] Remove `resolveSystem32Command()` if no PATH failure is proven; call `wsl.exe` directly. -- [ ] [Medium][S] Remove WSL path picker catch fallbacks in Electron renderer; for active WSL, failed conversion should fail, not pass Windows paths through. -- [ ] [Medium][M] Remove `createOutputDecoder()` / `detectOutputEncoding()` heuristic unless logs prove UTF-16 WSL output occurs. -- [ ] [Medium][M] Remove registry parsing/default-user discovery in `wsl.ts` if not proven necessary; use the actual WSL command context consistently. -- [ ] [Medium][M] Simplify `resolveWslOpencode()` fallback path search; prefer `command -v opencode` unless installer/PATH proves otherwise. -- [ ] [Medium][M] Simplify WSL sidecar shell script env/path/watchman workarounds in `server.ts`; add back only with repro/logs. -- [ ] [Medium][M] Remove `startAttempts` stale-start guard in WSL controller unless start/remove/stop race is reproduced. -- [ ] [Medium][M] Remove `acknowledgements` model/API/IPC if UI does not consume it. -- [ ] [Medium][M] Remove `Promise.allSettled` distro-list fallback; let listing errors surface instead of showing empty distros. +- [ ] ~~[Medium][S] Remove `ensureLoopbackNoProxy()` and Chromium proxy-bypass mutation unless a measured proxy repro exists.~~ (Skipped: networking behavior change) +- [ ] ~~[Medium][S] Remove broad renderer global error/rejection logging in Electron renderer unless this PR intentionally adds diagnostics.~~ (Skipped: keep diagnostics) +- [ ] ~~[Medium][S] Remove `wireWindowDiagnostics()` or move it to a separate diagnostics PR; it is unrelated WSL feature plumbing.~~ (Skipped: keep diagnostics) +- [ ] ~~[Medium][S] Remove terminal debug logging helpers/calls once current investigation is done.~~ (Skipped: keep diagnostics) +- [ ] ~~[Medium][S] Remove server-health retry logging helpers (`serializeError`, `stringifyLog`, per-attempt logs`) or dev-gate one final warning.~~ (Skipped: keep diagnostics) +- [ ] ~~[Medium][S] Remove `resolveSystem32Command()` if no PATH failure is proven; call `wsl.exe` directly.~~ (Skipped: PATH behavior change) +- [ ] ~~[Medium][S] Remove WSL path picker catch fallbacks in Electron renderer; for active WSL, failed conversion should fail, not pass Windows paths through.~~ (Skipped: behavior change) +- [ ] ~~[Medium][M] Remove `createOutputDecoder()` / `detectOutputEncoding()` heuristic unless logs prove UTF-16 WSL output occurs.~~ (Skipped: output compatibility change) +- [ ] ~~[Medium][M] Remove registry parsing/default-user discovery in `wsl.ts` if not proven necessary; use the actual WSL command context consistently.~~ (Skipped: opencode discovery behavior change) +- [ ] ~~[Medium][M] Simplify `resolveWslOpencode()` fallback path search; prefer `command -v opencode` unless installer/PATH proves otherwise.~~ (Skipped: opencode discovery behavior change) +- [ ] ~~[Medium][M] Simplify WSL sidecar shell script env/path/watchman workarounds in `server.ts`; add back only with repro/logs.~~ (Skipped: runtime environment behavior change) +- [ ] ~~[Medium][M] Remove `startAttempts` stale-start guard in WSL controller unless start/remove/stop race is reproduced.~~ (Skipped: race-safety behavior change) +- [x] [Medium][M] Remove `acknowledgements` model/API/IPC if UI does not consume it. +- [ ] ~~[Medium][M] Remove `Promise.allSettled` distro-list fallback; let listing errors surface instead of showing empty distros.~~ (Skipped: error/empty-list behavior change) - [ ] [Medium][M] Collapse WSL persisted config + state mutations into one owner/path, or derive runtime state instead of mutating both. - [ ] [Medium][M] Remove bespoke WSL subscribe/unsubscribe IPC lifecycle if broadcast event pattern is acceptable. - [ ] [Medium][M] Collapse repeated WSL IPC method lists in `ipc.ts`, `index.ts`, and preload into one simpler mapping or smaller API surface.