diff --git a/packages/app/src/app/app.tsx b/packages/app/src/app/app.tsx index 214f68c4..4b3af371 100644 --- a/packages/app/src/app/app.tsx +++ b/packages/app/src/app/app.tsx @@ -3198,6 +3198,21 @@ export default function App() { } }; + const restartLocalServer = async () => { + const activeWorkspace = workspaceStore.activeWorkspaceDisplay(); + const activeLocalPath = + activeWorkspace.workspaceType === "local" ? workspaceStore.activeWorkspacePath().trim() : ""; + const runningProjectDir = workspaceStore.engine()?.projectDir?.trim() ?? ""; + const workspacePath = activeLocalPath || runningProjectDir; + + if (!workspacePath) { + setError("Pick a local worker folder before restarting the local server."); + return false; + } + + return workspaceStore.startHost({ workspacePath, navigate: false }); + }; + const openWorkspaceConnectionSettings = (workspaceId: string) => { const workspace = workspaceStore.workspaces().find((item) => item.id === workspaceId) ?? null; if (workspace?.workspaceType === "remote" && workspace.remoteType === "openwork") { @@ -5621,6 +5636,7 @@ export default function App() { toggleDeveloperMode: () => setDeveloperMode((v) => !v), developerMode: developerMode(), stopHost, + restartLocalServer, openResetModal, resetModalBusy: resetModalBusy(), onResetStartupPreference: () => { diff --git a/packages/app/src/app/context/workspace.ts b/packages/app/src/app/context/workspace.ts index e0119de0..1c3aef34 100644 --- a/packages/app/src/app/context/workspace.ts +++ b/packages/app/src/app/context/workspace.ts @@ -2380,12 +2380,13 @@ export function createWorkspaceStore(options: { return false; } - if (activeWorkspaceInfo()?.workspaceType === "remote") { + const overrideWorkspacePath = optionsOverride?.workspacePath?.trim() ?? ""; + if (activeWorkspaceInfo()?.workspaceType === "remote" && !overrideWorkspacePath) { options.setError(t("app.error.host_requires_local", currentLocale())); return false; } - const dir = (optionsOverride?.workspacePath ?? activeWorkspacePath() ?? projectDir()).trim(); + const dir = (overrideWorkspacePath || activeWorkspacePath() || projectDir()).trim(); if (!dir) { options.setError(t("app.error.pick_workspace_folder", currentLocale())); return false; diff --git a/packages/app/src/app/pages/dashboard.tsx b/packages/app/src/app/pages/dashboard.tsx index 47ba55f7..b7f931df 100644 --- a/packages/app/src/app/pages/dashboard.tsx +++ b/packages/app/src/app/pages/dashboard.tsx @@ -267,6 +267,7 @@ export type DashboardViewProps = { toggleDeveloperMode: () => void; developerMode: boolean; stopHost: () => void; + restartLocalServer: () => Promise; openResetModal: (mode: "onboarding" | "all") => void; resetModalBusy: boolean; onResetStartupPreference: () => void; @@ -1716,6 +1717,7 @@ export default function DashboardView(props: DashboardViewProps) { developerMode={props.developerMode} toggleDeveloperMode={props.toggleDeveloperMode} stopHost={props.stopHost} + restartLocalServer={props.restartLocalServer} engineSource={props.engineSource} setEngineSource={props.setEngineSource} engineCustomBinPath={props.engineCustomBinPath} diff --git a/packages/app/src/app/pages/settings.tsx b/packages/app/src/app/pages/settings.tsx index a7af645a..51e9d50a 100644 --- a/packages/app/src/app/pages/settings.tsx +++ b/packages/app/src/app/pages/settings.tsx @@ -57,6 +57,7 @@ export type SettingsViewProps = { developerMode: boolean; toggleDeveloperMode: () => void; stopHost: () => void; + restartLocalServer: () => Promise; engineSource: "path" | "sidecar" | "custom"; setEngineSource: (value: "path" | "sidecar" | "custom") => void; engineCustomBinPath: string; @@ -319,6 +320,9 @@ export default function SettingsView(props: SettingsViewProps) { const [providerConnectError, setProviderConnectError] = createSignal(null); const [openworkReconnectStatus, setOpenworkReconnectStatus] = createSignal(null); const [openworkReconnectError, setOpenworkReconnectError] = createSignal(null); + const [openworkRestartBusy, setOpenworkRestartBusy] = createSignal(false); + const [openworkRestartStatus, setOpenworkRestartStatus] = createSignal(null); + const [openworkRestartError, setOpenworkRestartError] = createSignal(null); const providerConnectedCount = createMemo(() => (props.providerConnectedIds ?? []).length); const providerAvailableCount = createMemo(() => (props.providers ?? []).length); const connectedProviderNames = createMemo(() => { @@ -383,6 +387,26 @@ export default function SettingsView(props: SettingsViewProps) { } }; + const handleRestartLocalServer = async () => { + if (props.busy || openworkRestartBusy()) return; + setOpenworkRestartStatus(null); + setOpenworkRestartError(null); + setOpenworkRestartBusy(true); + try { + const ok = await props.restartLocalServer(); + if (!ok) { + setOpenworkRestartError("Restart failed. Check logs and try again."); + return; + } + setOpenworkRestartStatus("Restarted local server."); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + setOpenworkRestartError(message || "Failed to restart local server."); + } finally { + setOpenworkRestartBusy(false); + } + }; + const openworkStatusLabel = createMemo(() => { switch (props.openworkServerStatus) { case "connected": @@ -886,6 +910,17 @@ export default function SettingsView(props: SettingsViewProps) { {props.openworkReconnectBusy ? "Reconnecting..." : "Reconnect server"} + + +