From 4e06e48f1f13282bcc432fa3a134c6dc95b925f1 Mon Sep 17 00:00:00 2001 From: Benjamin Shafii Date: Sat, 4 Apr 2026 15:32:19 -0700 Subject: [PATCH 1/2] fix(app): remove more dead settings shell code --- apps/app/src/app/app.tsx | 1 - .../app/components/session/inbox-panel.tsx | 298 ------------------ .../app/src/app/components/workspace-chip.tsx | 65 ---- .../components/workspace-right-sidebar.tsx | 161 ---------- .../connections/openwork-server-provider.tsx | 10 +- apps/app/src/app/context/sync.tsx | 33 -- apps/app/src/app/lib/safe-run.ts | 71 ----- apps/app/src/app/pages/settings.tsx | 29 -- apps/app/src/app/shell/settings-shell.tsx | 53 +--- apps/app/src/app/state/extensions.ts | 1 - apps/app/src/app/state/sessions.ts | 1 - apps/app/src/app/state/system.ts | 1 - apps/app/src/app/types.ts | 1 - 13 files changed, 2 insertions(+), 723 deletions(-) delete mode 100644 apps/app/src/app/components/session/inbox-panel.tsx delete mode 100644 apps/app/src/app/components/workspace-chip.tsx delete mode 100644 apps/app/src/app/components/workspace-right-sidebar.tsx delete mode 100644 apps/app/src/app/context/sync.tsx delete mode 100644 apps/app/src/app/lib/safe-run.ts delete mode 100644 apps/app/src/app/state/extensions.ts delete mode 100644 apps/app/src/app/state/sessions.ts delete mode 100644 apps/app/src/app/state/system.ts diff --git a/apps/app/src/app/app.tsx b/apps/app/src/app/app.tsx index 9b4c82e60..d5366e1dc 100644 --- a/apps/app/src/app/app.tsx +++ b/apps/app/src/app/app.tsx @@ -2069,7 +2069,6 @@ export default function App() { const settingsTabs = new Set([ "general", "den", - "model", "automations", "skills", "extensions", diff --git a/apps/app/src/app/components/session/inbox-panel.tsx b/apps/app/src/app/components/session/inbox-panel.tsx deleted file mode 100644 index f81f74a78..000000000 --- a/apps/app/src/app/components/session/inbox-panel.tsx +++ /dev/null @@ -1,298 +0,0 @@ -import { For, Show, createEffect, createMemo, createSignal } from "solid-js"; -import { Download, RefreshCw, UploadCloud } from "lucide-solid"; - -import { getOpenWorkDeployment } from "../../lib/openwork-deployment"; -import { t } from "../../../i18n"; -import type { OpenworkInboxItem, OpenworkServerClient } from "../../lib/openwork-server"; -import WebUnavailableSurface from "../web-unavailable-surface"; -import { formatBytes, formatRelativeTime } from "../../utils"; - -export type InboxPanelProps = { - id?: string; - client: OpenworkServerClient | null; - workspaceId: string | null; - onToast?: (message: string) => void; - maxPreview?: number; -}; - -const INBOX_PREFIX = ".opencode/openwork/inbox/"; - -function safeName(item: OpenworkInboxItem): string { - return String(item.name ?? item.path ?? "file").trim() || "file"; -} - -function safeRelPath(item: OpenworkInboxItem): string { - const raw = String(item.path ?? item.name ?? "").trim(); - if (!raw) return ""; - return raw.replace(/^\/+/, ""); -} - -function toInboxWorkspacePath(item: OpenworkInboxItem): string { - const rel = safeRelPath(item); - return rel ? `${INBOX_PREFIX}${rel}` : INBOX_PREFIX; -} - -export default function InboxPanel(props: InboxPanelProps) { - const [items, setItems] = createSignal([]); - const [loading, setLoading] = createSignal(false); - const [uploading, setUploading] = createSignal(false); - const [dragOver, setDragOver] = createSignal(false); - const [error, setError] = createSignal(null); - const webDeployment = createMemo(() => getOpenWorkDeployment() === "web"); - - let fileInputRef: HTMLInputElement | undefined; - - const maxPreview = createMemo(() => { - const raw = props.maxPreview ?? 6; - if (!Number.isFinite(raw)) return 6; - return Math.min(12, Math.max(3, Math.floor(raw))); - }); - - const connected = createMemo(() => Boolean(props.client && (props.workspaceId ?? "").trim())); - const helperText = () => t("inbox_panel.helper_text"); - - const visibleItems = createMemo(() => (items() ?? []).slice(0, maxPreview())); - const hiddenCount = createMemo(() => Math.max(0, (items() ?? []).length - visibleItems().length)); - - const toast = (message: string) => { - props.onToast?.(message); - }; - - const refresh = async () => { - const client = props.client; - const workspaceId = (props.workspaceId ?? "").trim(); - if (!client || !workspaceId) { - setItems([]); - return; - } - - setLoading(true); - setError(null); - try { - const result = await client.listInbox(workspaceId); - setItems(result.items ?? []); - } catch (err) { - const message = - err instanceof Error ? err.message : t("inbox_panel.load_failed"); - setError(message); - setItems([]); - } finally { - setLoading(false); - } - }; - - const uploadFiles = async (files: File[]) => { - const client = props.client; - const workspaceId = (props.workspaceId ?? "").trim(); - if (!client || !workspaceId) { - toast(t("inbox_panel.upload_needs_worker")); - return; - } - if (!files.length) return; - - setUploading(true); - setError(null); - try { - const label = files.length === 1 ? files[0]?.name ?? "file" : `${files.length} files`; - toast(t("inbox_panel.uploading_label", undefined, { label })); - for (const file of files) { - await client.uploadInbox(workspaceId, file); - } - toast(t("inbox_panel.upload_success")); - await refresh(); - } catch (err) { - const message = - err instanceof Error ? err.message : t("inbox_panel.upload_failed"); - setError(message); - toast(message); - } finally { - setUploading(false); - } - }; - - const copyPath = async (item: OpenworkInboxItem) => { - const path = toInboxWorkspacePath(item); - try { - await navigator.clipboard.writeText(path); - toast(t("inbox_panel.copied_path", undefined, { path })); - } catch { - toast(t("inbox_panel.copy_failed")); - } - }; - - const downloadItem = async (item: OpenworkInboxItem) => { - const client = props.client; - const workspaceId = (props.workspaceId ?? "").trim(); - if (!client || !workspaceId) { - toast(t("inbox_panel.connect_to_download")); - return; - } - const id = String(item.id ?? "").trim(); - if (!id) { - toast(t("inbox_panel.missing_file_id")); - return; - } - - try { - const result = await client.downloadInboxItem(workspaceId, id); - const blob = new Blob([result.data], { type: result.contentType ?? "application/octet-stream" }); - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = result.filename ?? safeName(item); - document.body.appendChild(a); - a.click(); - a.remove(); - URL.revokeObjectURL(url); - } catch (err) { - const message = err instanceof Error ? err.message : t("inbox_panel.download_failed"); - toast(message); - } - }; - - createEffect(() => { - // Refresh when switching workers. - void props.workspaceId; - void props.client; - void refresh(); - }); - - return ( - -
-
- {t("inbox_panel.shared_folder")} -
- 0}> - - {(items() ?? []).length} - - - -
-
- - { - const target = event.currentTarget as HTMLInputElement; - const files = Array.from(target.files ?? []); - if (files.length) void uploadFiles(files); - target.value = ""; - }} - /> - - - -
- -
{error()}
-
- - 0} - fallback={ -
- - {t("inbox_panel.no_files")} - -
- } - > - - {(item) => { - const name = () => safeName(item); - const rel = () => safeRelPath(item); - const bytes = () => (typeof item.size === "number" ? item.size : null); - const updatedAt = () => (typeof item.updatedAt === "number" ? item.updatedAt : null); - - return ( -
- - - -
- ); - }} -
-
- - 0}> -
{t("inbox_panel.showing_first", undefined, { count: maxPreview() })}
-
-
-
-
- ); -} diff --git a/apps/app/src/app/components/workspace-chip.tsx b/apps/app/src/app/components/workspace-chip.tsx deleted file mode 100644 index 54972e6f9..000000000 --- a/apps/app/src/app/components/workspace-chip.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import type { WorkspaceInfo } from "../lib/tauri"; - -import { t, currentLocale } from "../../i18n"; - -import { ChevronDown, Folder, Globe, Loader2, Zap } from "lucide-solid"; - -function iconForWorkspace(preset: string, workspaceType: string) { - if (workspaceType === "remote") return Globe; - if (preset === "starter") return Zap; - if (preset === "automation") return Folder; - if (preset === "minimal") return Globe; - return Folder; -} - -export default function WorkspaceChip(props: { - workspace: WorkspaceInfo; - onClick: () => void; - connecting?: boolean; -}) { - const Icon = iconForWorkspace(props.workspace.preset, props.workspace.workspaceType); - const subtitle = () => - props.workspace.workspaceType === "remote" - ? props.workspace.baseUrl ?? props.workspace.path - : props.workspace.path; - const isSandboxWorkspace = - props.workspace.workspaceType === "remote" && - (props.workspace.sandboxBackend === "docker" || - Boolean(props.workspace.sandboxRunId?.trim()) || - Boolean(props.workspace.sandboxContainerName?.trim())); - const translate = (key: string) => t(key, currentLocale()); - - return ( - - ); -} diff --git a/apps/app/src/app/components/workspace-right-sidebar.tsx b/apps/app/src/app/components/workspace-right-sidebar.tsx deleted file mode 100644 index 26f05a76e..000000000 --- a/apps/app/src/app/components/workspace-right-sidebar.tsx +++ /dev/null @@ -1,161 +0,0 @@ -import { Show, type JSX } from "solid-js"; -import { t } from "../../i18n"; -import { - Box, - ChevronLeft, - ChevronRight, - History, - MessageCircle, - Settings, - SlidersHorizontal, - X, - Zap, -} from "lucide-solid"; - -import type { SettingsTab } from "../types"; -import type { OpenworkServerClient } from "../lib/openwork-server"; -import InboxPanel from "./session/inbox-panel"; - -type Props = { - expanded: boolean; - mobile?: boolean; - showSelection?: boolean; - settingsTab?: SettingsTab; - developerMode: boolean; - activeWorkspaceLabel: string; - activeWorkspaceType: "local" | "remote"; - openworkServerClient: OpenworkServerClient | null; - runtimeWorkspaceId: string | null; - inboxId: string; - onToggleExpanded: () => void; - onCloseMobile?: () => void; - onOpenAutomations: () => void; - onOpenSkills: () => void; - onOpenExtensions: () => void; - onOpenMessaging: () => void; - onOpenAdvanced: () => void; - onOpenSettings: () => void; - onInboxToast?: (message: string) => void; -}; - -export default function WorkspaceRightSidebar(props: Props) { - const mobile = () => props.mobile ?? false; - const showSelection = () => props.showSelection ?? true; - const closeMobile = () => props.onCloseMobile?.(); - const sidebarButton = ( - label: string, - icon: JSX.Element, - active: boolean, - onClick: () => void, - ) => ( - - ); - - return ( -
-
- -
-
- {(props.activeWorkspaceLabel || t("dashboard.workspaces"))} {t("workspace_sidebar.configuration")} -
-
-
- -
-
-
- {sidebarButton( - t("workspace_sidebar.automations"), - , - showSelection() && props.settingsTab === "automations", - props.onOpenAutomations, - )} - {sidebarButton( - t("dashboard.skills"), - , - showSelection() && props.settingsTab === "skills", - props.onOpenSkills, - )} - {sidebarButton( - t("workspace_sidebar.extensions"), - , - showSelection() && props.settingsTab === "extensions", - props.onOpenExtensions, - )} - {sidebarButton( - t("workspace_sidebar.messaging"), - , - showSelection() && props.settingsTab === "messaging", - props.onOpenMessaging, - )} - - {sidebarButton( - t("settings.advanced_title"), - , - showSelection() && props.settingsTab === "advanced", - props.onOpenAdvanced, - )} - -
- - -
- -
-
-
- -
- {sidebarButton( - t("dashboard.settings"), - , - showSelection() && props.settingsTab === "general", - props.onOpenSettings, - )} -
-
- ); -} diff --git a/apps/app/src/app/connections/openwork-server-provider.tsx b/apps/app/src/app/connections/openwork-server-provider.tsx index 5c30332b9..b536f2dff 100644 --- a/apps/app/src/app/connections/openwork-server-provider.tsx +++ b/apps/app/src/app/connections/openwork-server-provider.tsx @@ -1,4 +1,4 @@ -import { createContext, useContext, type ParentProps } from "solid-js"; +import { createContext, type ParentProps } from "solid-js"; import type { OpenworkServerStore } from "./openwork-server-store"; @@ -11,11 +11,3 @@ export function OpenworkServerProvider(props: ParentProps<{ store: OpenworkServe ); } - -export function useOpenworkServer() { - const context = useContext(OpenworkServerContext); - if (!context) { - throw new Error("useOpenworkServer must be used within an OpenworkServerProvider"); - } - return context; -} diff --git a/apps/app/src/app/context/sync.tsx b/apps/app/src/app/context/sync.tsx deleted file mode 100644 index c3dedabb7..000000000 --- a/apps/app/src/app/context/sync.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { createContext, useContext, type ParentProps } from "solid-js"; -import type { SetStoreFunction, Store } from "solid-js/store"; - -import { useGlobalSync, type WorkspaceState } from "./global-sync"; - -type SyncContextValue = { - directory: string; - data: Store; - set: SetStoreFunction; -}; - -const SyncContext = createContext(undefined); - -export function SyncProvider(props: ParentProps & { directory: string }) { - const globalSync = useGlobalSync(); - const [store, setStore] = globalSync.child(props.directory); - - const value: SyncContextValue = { - directory: props.directory, - data: store, - set: setStore, - }; - - return {props.children}; -} - -export function useSync() { - const context = useContext(SyncContext); - if (!context) { - throw new Error("Sync context is missing"); - } - return context; -} diff --git a/apps/app/src/app/lib/safe-run.ts b/apps/app/src/app/lib/safe-run.ts deleted file mode 100644 index 3c0c3d19e..000000000 --- a/apps/app/src/app/lib/safe-run.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Safe execution utilities for error handling. - * - * Replaces bare `catch {}` blocks with structured handling that - * at least logs errors in development, while keeping the same - * "swallow and continue" behavior in production. - */ - -const isDev = typeof import.meta !== "undefined" && import.meta.env?.DEV; - -/** - * Run an async function, returning the result or a fallback on error. - * Logs errors in development mode. - * - * @example - * const sessions = await safeAsync(() => loadSessions(), []); - */ -export async function safeAsync( - fn: () => Promise, - fallback: T, - label?: string, -): Promise { - try { - return await fn(); - } catch (error) { - if (isDev) { - console.warn(`[safeAsync]${label ? ` ${label}:` : ""}`, error); - } - return fallback; - } -} - -/** - * Run a synchronous function, returning the result or a fallback on error. - * Logs errors in development mode. - * - * @example - * const parsed = safeSync(() => JSON.parse(raw), null); - */ -export function safeSync( - fn: () => T, - fallback: T, - label?: string, -): T { - try { - return fn(); - } catch (error) { - if (isDev) { - console.warn(`[safeSync]${label ? ` ${label}:` : ""}`, error); - } - return fallback; - } -} - -/** - * Fire-and-forget an async operation. Logs errors in development. - * Use for cleanup, best-effort writes, etc. - * - * @example - * fireAndForget(() => saveDraft(content), "save draft"); - */ -export function fireAndForget( - fn: () => Promise, - label?: string, -): void { - fn().catch((error) => { - if (isDev) { - console.warn(`[fireAndForget]${label ? ` ${label}:` : ""}`, error); - } - }); -} diff --git a/apps/app/src/app/pages/settings.tsx b/apps/app/src/app/pages/settings.tsx index db36b27bf..97e0635a2 100644 --- a/apps/app/src/app/pages/settings.tsx +++ b/apps/app/src/app/pages/settings.tsx @@ -217,31 +217,6 @@ const DISCORD_INVITE_URL = "https://discord.gg/VEhNQXxYMB"; const BUG_REPORT_URL = "https://github.com/different-ai/openwork/issues/new?template=bug.yml"; -// OpenCodeRouter Settings Component -// -// Messaging identities + routing are managed in the Identities tab. -export function OpenCodeRouterSettings(_props: { - busy: boolean; - openworkServerStatus: OpenworkServerStatus; - openworkServerUrl: string; - openworkServerSettings: OpenworkServerSettings; - runtimeWorkspaceId: string | null; - openworkServerHostInfo: OpenworkServerInfo | null; - developerMode: boolean; -}) { - return ( -
-
- -
{t("settings.messaging_section_title")}
-
-
- {t("settings.messaging_section_desc")} -
-
- ); -} - export default function SettingsView(props: SettingsViewProps) { const modelControls = useModelControls(); const { showThinking, toggleShowThinking } = useSessionDisplayPreferences(); @@ -807,8 +782,6 @@ export default function SettingsView(props: SettingsViewProps) { switch (tab) { case "den": return translate("settings.tab_cloud"); - case "model": - return translate("settings.tab_model"); case "automations": return translate("settings.tab_automations"); case "skills": @@ -1372,8 +1345,6 @@ export default function SettingsView(props: SettingsViewProps) { switch (tab) { case "den": return translate("settings.tab_description_den"); - case "model": - return translate("settings.tab_description_model"); case "automations": return translate("settings.tab_description_automations"); case "skills": diff --git a/apps/app/src/app/shell/settings-shell.tsx b/apps/app/src/app/shell/settings-shell.tsx index 7cedc6155..b1481e5b8 100644 --- a/apps/app/src/app/shell/settings-shell.tsx +++ b/apps/app/src/app/shell/settings-shell.tsx @@ -440,7 +440,7 @@ export default function SettingsShell(props: SettingsShellProps) { }; const openAdvanced = () => { - openSettings(props.developerMode ? "advanced" : "messaging"); + openSettings("advanced"); }; const revealWorkspaceInFinder = async (workspaceId: string) => { @@ -1353,57 +1353,6 @@ export default function SettingsShell(props: SettingsShellProps) { onOpenMcp={openExtensions} providerConnectedIds={props.providerConnectedIds} /> - diff --git a/apps/app/src/app/state/extensions.ts b/apps/app/src/app/state/extensions.ts deleted file mode 100644 index a5a12c433..000000000 --- a/apps/app/src/app/state/extensions.ts +++ /dev/null @@ -1 +0,0 @@ -export { createExtensionsStore } from "../context/extensions"; diff --git a/apps/app/src/app/state/sessions.ts b/apps/app/src/app/state/sessions.ts deleted file mode 100644 index ec318e592..000000000 --- a/apps/app/src/app/state/sessions.ts +++ /dev/null @@ -1 +0,0 @@ -export { createSessionStore } from "../context/session"; diff --git a/apps/app/src/app/state/system.ts b/apps/app/src/app/state/system.ts deleted file mode 100644 index 437a6d4ee..000000000 --- a/apps/app/src/app/state/system.ts +++ /dev/null @@ -1 +0,0 @@ -export { createSystemState } from "../system-state"; diff --git a/apps/app/src/app/types.ts b/apps/app/src/app/types.ts index 8bf631aaf..b2dddc7e1 100644 --- a/apps/app/src/app/types.ts +++ b/apps/app/src/app/types.ts @@ -161,7 +161,6 @@ export type OnboardingStep = "welcome" | "local" | "server" | "connecting"; export type SettingsTab = | "general" | "den" - | "model" | "automations" | "skills" | "extensions" From ada2333136fa92a8b4ba4d78407e66a15ececce1 Mon Sep 17 00:00:00 2001 From: Benjamin Shafii Date: Sat, 4 Apr 2026 16:59:27 -0700 Subject: [PATCH 2/2] fix(app): prune more dead helpers and props --- .../app/src/app/components/question-modal.tsx | 1 - apps/app/src/app/components/status-bar.tsx | 3 - apps/app/src/app/context/openwork-server.ts | 393 ------------------ apps/app/src/app/lib/openwork-server.ts | 24 -- apps/app/src/app/pages/session.tsx | 7 - apps/app/src/app/shell/settings-shell.tsx | 11 - apps/app/src/app/utils/index.ts | 73 ---- apps/app/src/app/utils/persist.ts | 16 - apps/app/src/app/utils/plugins.ts | 5 - apps/story-book/src/new-layout.tsx | 24 +- apps/story-book/src/story-book.tsx | 14 +- 11 files changed, 4 insertions(+), 567 deletions(-) delete mode 100644 apps/app/src/app/context/openwork-server.ts diff --git a/apps/app/src/app/components/question-modal.tsx b/apps/app/src/app/components/question-modal.tsx index 94448f56b..e77b06420 100644 --- a/apps/app/src/app/components/question-modal.tsx +++ b/apps/app/src/app/components/question-modal.tsx @@ -10,7 +10,6 @@ export type QuestionModalProps = { open: boolean; questions: QuestionInfo[]; busy: boolean; - onClose: () => void; onReply: (answers: string[][]) => void; }; diff --git a/apps/app/src/app/components/status-bar.tsx b/apps/app/src/app/components/status-bar.tsx index d2013cbd1..bc556cf86 100644 --- a/apps/app/src/app/components/status-bar.tsx +++ b/apps/app/src/app/components/status-bar.tsx @@ -12,9 +12,6 @@ type StatusBarProps = { settingsOpen: boolean; onSendFeedback: () => void; onOpenSettings: () => void; - onOpenMessaging: () => void; - onOpenProviders: () => Promise | void; - onOpenMcp: () => void; providerConnectedIds: string[]; statusLabel?: string; statusDetail?: string; diff --git a/apps/app/src/app/context/openwork-server.ts b/apps/app/src/app/context/openwork-server.ts deleted file mode 100644 index 68368a551..000000000 --- a/apps/app/src/app/context/openwork-server.ts +++ /dev/null @@ -1,393 +0,0 @@ -/** - * OpenWork server connection state. - * - * Encapsulates all signals, effects, and helpers related to the OpenWork - * server lifecycle: connection status, capabilities polling, host info, - * diagnostics, audit entries, and the server client instance. - */ -import { createEffect, createMemo, createSignal, onCleanup } from "solid-js"; - -import { - createOpenworkServerClient, - hydrateOpenworkServerSettingsFromEnv, - normalizeOpenworkServerUrl, - readOpenworkServerSettings, - OpenworkServerError, - type OpenworkAuditEntry, - type OpenworkServerCapabilities, - type OpenworkServerClient, - type OpenworkServerDiagnostics, - type OpenworkServerSettings, - type OpenworkServerStatus, -} from "../lib/openwork-server"; -import { - openworkServerInfo, - orchestratorStatus, - opencodeRouterInfo, - type OrchestratorStatus, - type OpenworkServerInfo, - type OpenCodeRouterInfo, -} from "../lib/tauri"; -import { isTauriRuntime } from "../utils"; -import type { StartupPreference } from "../types"; - -export type OpenworkServerStore = ReturnType; - -export function createOpenworkServerStore(options: { - startupPreference: () => StartupPreference | null; - developerMode: () => boolean; - documentVisible: () => boolean; - refreshEngine?: () => Promise; -}) { - const [settings, setSettings] = createSignal({}); - const [url, setUrl] = createSignal(""); - const [status, setStatus] = createSignal("disconnected"); - const [capabilities, setCapabilities] = createSignal(null); - const [checkedAt, setCheckedAt] = createSignal(null); - const [workspaceId, setWorkspaceId] = createSignal(null); - const [hostInfo, setHostInfo] = createSignal(null); - const [diagnostics, setDiagnostics] = createSignal(null); - const [reconnectBusy, setReconnectBusy] = createSignal(false); - const [routerInfo, setRouterInfo] = createSignal(null); - const [orchStatus, setOrchStatus] = createSignal(null); - const [auditEntries, setAuditEntries] = createSignal([]); - const [auditStatus, setAuditStatus] = createSignal<"idle" | "loading" | "error">("idle"); - const [auditError, setAuditError] = createSignal(null); - const [devtoolsWorkspaceId, setDevtoolsWorkspaceId] = createSignal(null); - - // -- Derived -- - - const baseUrl = createMemo(() => { - const pref = options.startupPreference(); - const info = hostInfo(); - const settingsUrl = normalizeOpenworkServerUrl(settings().urlOverride ?? "") ?? ""; - - if (pref === "local") return info?.baseUrl ?? ""; - if (pref === "server") return settingsUrl; - return info?.baseUrl ?? settingsUrl; - }); - - const auth = createMemo(() => { - const pref = options.startupPreference(); - const info = hostInfo(); - const settingsToken = settings().token?.trim() ?? ""; - const clientToken = info?.clientToken?.trim() ?? ""; - const hostToken = info?.hostToken?.trim() ?? ""; - - if (pref === "local") { - return { token: clientToken || undefined, hostToken: hostToken || undefined }; - } - if (pref === "server") { - return { token: settingsToken || undefined, hostToken: undefined }; - } - if (info?.baseUrl) { - return { token: clientToken || undefined, hostToken: hostToken || undefined }; - } - return { token: settingsToken || undefined, hostToken: undefined }; - }); - - const client = createMemo(() => { - const base = baseUrl().trim(); - if (!base) return null; - const a = auth(); - return createOpenworkServerClient({ baseUrl: base, token: a.token, hostToken: a.hostToken }); - }); - - const devtoolsClient = createMemo(() => client()); - - // -- Effects -- - - // Hydrate settings from env/localStorage on mount - createEffect(() => { - if (typeof window === "undefined") return; - hydrateOpenworkServerSettingsFromEnv(); - setSettings(readOpenworkServerSettings()); - }); - - // Derive URL from preference + host info - createEffect(() => { - const pref = options.startupPreference(); - const info = hostInfo(); - const hostUrl = info?.connectUrl ?? info?.lanUrl ?? info?.mdnsUrl ?? info?.baseUrl ?? ""; - const settingsUrl = normalizeOpenworkServerUrl(settings().urlOverride ?? "") ?? ""; - - if (pref === "local") { - setUrl(hostUrl); - return; - } - if (pref === "server") { - setUrl(settingsUrl); - return; - } - setUrl(hostUrl || settingsUrl); - }); - - // Poll server health + capabilities - createEffect(() => { - if (typeof window === "undefined") return; - if (!options.documentVisible()) return; - const serverUrl = baseUrl().trim(); - const a = auth(); - const token = a.token; - const ht = a.hostToken; - - if (!serverUrl) { - setStatus("disconnected"); - setCapabilities(null); - setCheckedAt(Date.now()); - return; - } - - let active = true; - let busy = false; - let timeoutId: number | undefined; - let delayMs = 10_000; - - const scheduleNext = () => { - if (!active) return; - timeoutId = window.setTimeout(run, delayMs); - }; - - const run = async () => { - if (busy) return; - busy = true; - try { - const result = await checkServer(serverUrl, token, ht); - if (!active) return; - setStatus(result.status); - setCapabilities(result.capabilities); - delayMs = - result.status === "connected" || result.status === "limited" - ? 10_000 - : Math.min(delayMs * 2, 60_000); - } catch { - delayMs = Math.min(delayMs * 2, 60_000); - } finally { - if (!active) return; - setCheckedAt(Date.now()); - busy = false; - scheduleNext(); - } - }; - - run(); - onCleanup(() => { - active = false; - if (timeoutId) window.clearTimeout(timeoutId); - }); - }); - - // Poll host info (Tauri only) - createEffect(() => { - if (!isTauriRuntime()) return; - if (!options.documentVisible()) return; - let active = true; - - const run = async () => { - try { - const info = await openworkServerInfo(); - if (active) setHostInfo(info); - } catch { - if (active) setHostInfo(null); - } - }; - - run(); - const interval = window.setInterval(run, 10_000); - onCleanup(() => { - active = false; - window.clearInterval(interval); - }); - }); - - // Poll diagnostics (developer mode only) - createEffect(() => { - if (typeof window === "undefined") return; - if (!options.documentVisible()) return; - if (!options.developerMode()) { - setDiagnostics(null); - return; - } - - const c = client(); - if (!c || status() === "disconnected") { - setDiagnostics(null); - return; - } - - let active = true; - let busy = false; - - const run = async () => { - if (busy) return; - busy = true; - try { - const s = await c.status(); - if (active) setDiagnostics(s); - } catch { - if (active) setDiagnostics(null); - } finally { - busy = false; - } - }; - - run(); - const interval = window.setInterval(run, 10_000); - onCleanup(() => { - active = false; - window.clearInterval(interval); - }); - }); - - // Poll engine (developer mode, Tauri only) - createEffect(() => { - if (!isTauriRuntime()) return; - if (!options.developerMode()) return; - if (!options.documentVisible()) return; - - let busy = false; - const run = async () => { - if (busy) return; - busy = true; - try { - await options.refreshEngine?.(); - } finally { - busy = false; - } - }; - - run(); - const interval = window.setInterval(run, 10_000); - onCleanup(() => { - window.clearInterval(interval); - }); - }); - - // Poll OpenCode Router info (developer mode, Tauri only) - createEffect(() => { - if (!isTauriRuntime()) return; - if (!options.developerMode()) { - setRouterInfo(null); - return; - } - if (!options.documentVisible()) return; - - let active = true; - const run = async () => { - try { - const info = await opencodeRouterInfo(); - if (active) setRouterInfo(info); - } catch { - if (active) setRouterInfo(null); - } - }; - - run(); - const interval = window.setInterval(run, 10_000); - onCleanup(() => { - active = false; - window.clearInterval(interval); - }); - }); - - // Poll orchestrator status (developer mode, Tauri only) - createEffect(() => { - if (!isTauriRuntime()) return; - if (!options.developerMode()) { - setOrchStatus(null); - return; - } - if (!options.documentVisible()) return; - - let active = true; - const run = async () => { - try { - const s = await orchestratorStatus(); - if (active) setOrchStatus(s); - } catch { - if (active) setOrchStatus(null); - } - }; - - run(); - const interval = window.setInterval(run, 10_000); - onCleanup(() => { - active = false; - window.clearInterval(interval); - }); - }); - - return { - // Signals (read) - settings, - url, - status, - capabilities, - checkedAt, - workspaceId, - hostInfo, - diagnostics, - reconnectBusy, - routerInfo, - orchestratorStatus: orchStatus, - auditEntries, - auditStatus, - auditError, - devtoolsWorkspaceId, - - // Derived - baseUrl, - auth, - client, - devtoolsClient, - - // Setters (for external use) - setSettings, - setUrl, - setStatus, - setCapabilities, - setCheckedAt, - setWorkspaceId, - setHostInfo, - setDiagnostics, - setReconnectBusy, - setRouterInfo, - setOrchestratorStatus: setOrchStatus, - setAuditEntries, - setAuditStatus, - setAuditError, - setDevtoolsWorkspaceId, - }; -} - -// -- Helpers -- - -async function checkServer( - url: string, - token?: string, - hostToken?: string, -): Promise<{ status: OpenworkServerStatus; capabilities: OpenworkServerCapabilities | null }> { - const c = createOpenworkServerClient({ baseUrl: url, token, hostToken }); - try { - await c.health(); - } catch (error) { - if (error instanceof OpenworkServerError && (error.status === 401 || error.status === 403)) { - return { status: "limited", capabilities: null }; - } - return { status: "disconnected", capabilities: null }; - } - - if (!token) { - return { status: "limited", capabilities: null }; - } - - try { - const caps = await c.capabilities(); - return { status: "connected", capabilities: caps }; - } catch (error) { - if (error instanceof OpenworkServerError && (error.status === 401 || error.status === 403)) { - return { status: "limited", capabilities: null }; - } - return { status: "disconnected", capabilities: null }; - } -} diff --git a/apps/app/src/app/lib/openwork-server.ts b/apps/app/src/app/lib/openwork-server.ts index 7ad57bf43..301b22dfb 100644 --- a/apps/app/src/app/lib/openwork-server.ts +++ b/apps/app/src/app/lib/openwork-server.ts @@ -690,30 +690,6 @@ export function clearOpenworkServerSettings() { } } -export function deriveOpenworkServerUrl( - opencodeBaseUrl: string, - settings?: OpenworkServerSettings, -) { - const override = settings?.urlOverride?.trim(); - if (override) { - return normalizeOpenworkServerUrl(override); - } - - const base = opencodeBaseUrl.trim(); - if (!base) return null; - try { - const url = new URL(base); - const port = settings?.portOverride ?? DEFAULT_OPENWORK_SERVER_PORT; - url.port = String(port); - url.pathname = ""; - url.search = ""; - url.hash = ""; - return url.origin; - } catch { - return null; - } -} - export class OpenworkServerError extends Error { status: number; code: string; diff --git a/apps/app/src/app/pages/session.tsx b/apps/app/src/app/pages/session.tsx index 626ff015f..ecc266b75 100644 --- a/apps/app/src/app/pages/session.tsx +++ b/apps/app/src/app/pages/session.tsx @@ -3510,12 +3510,6 @@ export default function SessionView(props: SessionViewProps) { onSendFeedback={openFeedback} showSettingsButton={true} onOpenSettings={props.toggleSettings} - onOpenMessaging={() => { - props.setSettingsTab("messaging"); - props.setView("settings"); - }} - onOpenProviders={openProviderAuth} - onOpenMcp={openMcp} providerConnectedIds={props.providerConnectedIds} statusLabel={statusBarCopy().label} statusDetail={statusBarCopy().detail} @@ -3834,7 +3828,6 @@ export default function SessionView(props: SessionViewProps) { open={Boolean(props.activeQuestion)} questions={props.activeQuestion?.questions ?? []} busy={props.questionReplyBusy} - onClose={() => {}} onReply={(answers) => { if (props.activeQuestion) { props.respondQuestion(props.activeQuestion.id, answers); diff --git a/apps/app/src/app/shell/settings-shell.tsx b/apps/app/src/app/shell/settings-shell.tsx index b1481e5b8..3a24667d9 100644 --- a/apps/app/src/app/shell/settings-shell.tsx +++ b/apps/app/src/app/shell/settings-shell.tsx @@ -431,14 +431,6 @@ export default function SettingsShell(props: SettingsShellProps) { props.setSettingsTab(tab); }; - const openMessaging = () => { - openSettings("messaging"); - }; - - const openExtensions = () => { - openSettings("extensions"); - }; - const openAdvanced = () => { openSettings("advanced"); }; @@ -1348,9 +1340,6 @@ export default function SettingsShell(props: SettingsShellProps) { showSettingsButton={true} onSendFeedback={openFeedback} onOpenSettings={props.toggleSettings} - onOpenMessaging={openMessaging} - onOpenProviders={() => props.openProviderAuthModal()} - onOpenMcp={openExtensions} providerConnectedIds={props.providerConnectedIds} /> diff --git a/apps/app/src/app/utils/index.ts b/apps/app/src/app/utils/index.ts index 7ba440f60..afdebaddb 100644 --- a/apps/app/src/app/utils/index.ts +++ b/apps/app/src/app/utils/index.ts @@ -274,21 +274,6 @@ export function formatRelativeTime(timestampMs: number) { return new Date(timestampMs).toLocaleDateString(); } -export function commandPathFromWorkspaceRoot(workspaceRoot: string, commandName: string) { - const root = workspaceRoot.trim().replace(/\/+$/, ""); - const name = commandName.trim().replace(/^\/+/, ""); - if (!root || !name) return null; - return `${root}/.opencode/commands/${name}.md`; -} - -export function safeParseJson(raw: string): T | null { - try { - return JSON.parse(raw) as T; - } catch { - return null; - } -} - export function addOpencodeCacheHint(message: string) { const lower = message.toLowerCase(); const cacheSignals = [ @@ -439,64 +424,6 @@ export function upsertSession(list: Session[], next: Session) { return copy; } -export function upsertMessage(list: MessageWithParts[], nextInfo: MessageInfo) { - const idx = list.findIndex((m) => m.info.id === nextInfo.id); - if (idx === -1) { - return list.concat({ info: nextInfo, parts: [] }); - } - - const copy = list.slice(); - copy[idx] = { ...copy[idx], info: nextInfo }; - return copy; -} - -export function upsertPart(list: MessageWithParts[], nextPart: Part) { - const msgIdx = list.findIndex((m) => m.info.id === nextPart.messageID); - if (msgIdx === -1) { - // avoids missing streaming events before message.updated - const placeholder: PlaceholderAssistantMessage = { - id: nextPart.messageID, - sessionID: nextPart.sessionID, - role: "assistant", - time: { created: Date.now() }, - parentID: "", - modelID: "", - providerID: "", - mode: "", - agent: "", - path: { cwd: "", root: "" }, - cost: 0, - tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } }, - }; - - return list.concat({ info: placeholder, parts: [nextPart] }); - } - - const copy = list.slice(); - const msg = copy[msgIdx]; - const parts = msg.parts.slice(); - const partIdx = parts.findIndex((p) => p.id === nextPart.id); - - if (partIdx === -1) { - parts.push(nextPart); - } else { - parts[partIdx] = nextPart; - } - - copy[msgIdx] = { ...msg, parts }; - return copy; -} - -export function removePart(list: MessageWithParts[], messageID: string, partID: string) { - const msgIdx = list.findIndex((m) => m.info.id === messageID); - if (msgIdx === -1) return list; - - const copy = list.slice(); - const msg = copy[msgIdx]; - copy[msgIdx] = { ...msg, parts: msg.parts.filter((p) => p.id !== partID) }; - return copy; -} - export function normalizeSessionStatus(status: unknown) { if (!status || typeof status !== "object") return "idle"; const record = status as Record; diff --git a/apps/app/src/app/utils/persist.ts b/apps/app/src/app/utils/persist.ts index 9747465c2..830f5a922 100644 --- a/apps/app/src/app/utils/persist.ts +++ b/apps/app/src/app/utils/persist.ts @@ -99,22 +99,6 @@ export const Persist = { }, }; -export function removePersisted(target: { storage?: string; key: string }) { - const platform = usePlatform(); - const isDesktop = platform.platform === "desktop" && !!platform.storage; - - if (isDesktop) { - return platform.storage?.(target.storage)?.removeItem(target.key); - } - - if (!target.storage) { - localStorage.removeItem(target.key); - return; - } - - localStorageWithPrefix(target.storage).removeItem(target.key); -} - export function persisted( target: string | PersistTarget, store: [Store, SetStoreFunction], diff --git a/apps/app/src/app/utils/plugins.ts b/apps/app/src/app/utils/plugins.ts index 52ae4def5..653397f21 100644 --- a/apps/app/src/app/utils/plugins.ts +++ b/apps/app/src/app/utils/plugins.ts @@ -78,11 +78,6 @@ export function loadPluginsFromConfig( } } -export function parsePluginsFromConfig(config: OpencodeConfigFile | null) { - if (!config?.content) return [] as string[]; - return parsePluginListFromContent(config.content); -} - export function parsePluginListFromContent(content: string) { try { const parsed = parse(content) as Record | undefined; diff --git a/apps/story-book/src/new-layout.tsx b/apps/story-book/src/new-layout.tsx index 0c928cf5f..418a59591 100644 --- a/apps/story-book/src/new-layout.tsx +++ b/apps/story-book/src/new-layout.tsx @@ -8,7 +8,6 @@ import ModelPickerModal from "../../app/src/app/components/model-picker-modal"; import ShareWorkspaceModal from "../../app/src/app/components/share-workspace-modal"; import StatusBar from "../../app/src/app/components/status-bar"; import Composer from "../../app/src/app/components/session/composer"; -import InboxPanel from "../../app/src/app/components/session/inbox-panel"; import MessageList from "../../app/src/app/components/session/message-list"; import WorkspaceSessionList from "../../app/src/app/components/session/workspace-session-list"; import { MCP_QUICK_CONNECT, SUGGESTED_PLUGINS } from "../../app/src/app/constants"; @@ -1536,7 +1535,6 @@ export default function NewLayoutApp() { mcpServers={storyMcpServers()} mcpStatus="Story-book MCP sandbox ready." mcpLastUpdatedAt={now} - mcpStatuses={storyMcpStatuses()} mcpConnectingName={null} selectedMcp={selectedMcp()} setSelectedMcp={setSelectedMcp} @@ -1583,13 +1581,8 @@ export default function NewLayoutApp() { developerMode /> -
- setComposerToast(message)} - /> +
+ Remote inbox preview has been removed from the app shell.
@@ -1730,20 +1723,7 @@ export default function NewLayoutApp() { setSettingsTab("general"); setShowingSettings((prev) => !prev); }} - onOpenMessaging={() => { - setSettingsTab("messaging"); - setShowingSettings(true); - }} - onOpenProviders={() => { - setSettingsTab("general"); - setShowingSettings(true); - }} - onOpenMcp={() => { - setSettingsTab("extensions"); - setShowingSettings(true); - }} providerConnectedIds={["anthropic", "openai"]} - mcpStatuses={storyMcpStatuses()} statusLabel="Session Ready" /> diff --git a/apps/story-book/src/story-book.tsx b/apps/story-book/src/story-book.tsx index b6273c6af..80a5a7593 100644 --- a/apps/story-book/src/story-book.tsx +++ b/apps/story-book/src/story-book.tsx @@ -21,7 +21,6 @@ import ModelPickerModal from "../../app/src/app/components/model-picker-modal"; import ShareWorkspaceModal from "../../app/src/app/components/share-workspace-modal"; import StatusBar from "../../app/src/app/components/status-bar"; import Composer from "../../app/src/app/components/session/composer"; -import InboxPanel from "../../app/src/app/components/session/inbox-panel"; import MessageList from "../../app/src/app/components/session/message-list"; import WorkspaceSessionList from "../../app/src/app/components/session/workspace-session-list"; import { createWorkspaceShellLayout } from "../../app/src/app/lib/workspace-shell-layout"; @@ -858,13 +857,8 @@ export default function StoryBookApp() {
-
- setComposerToast(message)} - /> +
+ Remote inbox preview has been removed from the app shell.
@@ -1105,11 +1099,7 @@ export default function StoryBookApp() { if (!rightSidebarExpanded()) toggleRightSidebar(); setRightRailNav("advanced"); }} - onOpenMessaging={() => undefined} - onOpenProviders={() => undefined} - onOpenMcp={() => undefined} providerConnectedIds={["anthropic", "openai"]} - mcpStatuses={mcpStatuses} statusLabel="Session Ready" />