From 4be89cb0b8cc40c5ae6e6af31a83d7d9bc429afe Mon Sep 17 00:00:00 2001 From: iamnbutler Date: Thu, 22 Oct 2026 11:29:53 -0400 Subject: [PATCH 1/4] fix(app): settings, terminal, connection and composer say what they can and can't do Hide Add key while an environment variable overrides it; the terminal follows a live theme switch; a host that answers but refuses the web app gets its own message; a rename error clears on typing; Archive inactive in the section menu; an empty Move to says why; format buttons get labels and shortcut hints; a fifth image is refused; and voice input says why it stopped. --- apps/app/src/app.tsx | 30 +++++++++++++- apps/app/src/composer.tsx | 22 +++++++++- apps/app/src/layout/rename.tsx | 2 + apps/app/src/panels/terminal.tsx | 4 +- apps/app/src/settings.tsx | 3 +- packages/channel/src/protocol.ts | 5 ++- packages/channel/src/room.ts | 3 +- .../src/components/composer/chat-composer.tsx | 6 ++- .../components/composer/composer-toolbar.tsx | 40 ++++++++++++++----- .../session-item/session-item-actions.tsx | 7 +++- .../session-sidebar/session-options.tsx | 15 +++++-- .../session-sidebar/session-sidebar.tsx | 1 + packages/ui/src/hooks/use-dictation.ts | 23 +++++++++-- 13 files changed, 133 insertions(+), 28 deletions(-) diff --git a/apps/app/src/app.tsx b/apps/app/src/app.tsx index 54260b4b..330bba53 100644 --- a/apps/app/src/app.tsx +++ b/apps/app/src/app.tsx @@ -34,7 +34,7 @@ import { projectId, } from "@ace/host/protocol"; -import { chosen, deployed, remember } from "./address"; +import { chosen, deployed, gateway, remember } from "./address"; import { type Attention, glow, useAttention } from "./attention"; import { Channel, ChannelDetails, type ChannelDraft } from "./channel"; import { useCompute } from "./compute"; @@ -107,12 +107,38 @@ function ChannelsSidebar(props: SessionSidebarProps) { ); } +/** + * Whether the deployed app's host answers HTTP at all. A browser hides why a WebSocket failed, but + * an opaque no-cors response still proves the host is reachable, so its gateway refused this app. + */ +function useAnswers(): boolean | undefined { + const [answers, setAnswers] = useState(); + useEffect(() => { + if (!deployed || !gateway) return; + const url = new URL(gateway.replace(/^ws/, "http")); + url.pathname = "/"; + fetch(url, { mode: "no-cors", cache: "no-store" }).then( + () => setAnswers(true), + () => setAnswers(false), + ); + }, []); + return answers; +} + function Disconnected() { + const answers = useAnswers(); if (desktop) return <>Disconnected from Ace Helper. Open Settings → This Mac to start it.; if (!deployed) return <>Disconnected from your host. Reconnecting…; return ( <> - Can't reach {chosen}. Check that Tailscale is on.{" "} + {answers + ? ( + <> + {chosen} refused this web app. On that host, run{" "} + ace web {location.origin}, then reload. + + ) + : <>Can't reach {chosen}. Check that Tailscale is on.}{" "} )} - {!editing && ( + {/* A saved key would go unused while the environment overrides it. */} + {!editing && !provider.override && (