Relevant Diff Snippets
These snippets are formatted as unified patches so they can be
consumed by Diffs’
parsePatchFiles or PatchDiff flows from
diffs.com/docs.
Settings state helpers and bridge recovery action
diff --git a/apps/web/app/desktop-ai-panels.tsx b/apps/web/app/desktop-ai-panels.tsx
@@
+export const getDesktopAiSettingsBridgeNotice = (shellAvailable, bridgeAvailable) => {
+ if (!shellAvailable) {
+ return {
+ title: "Desktop app required",
+ body: "Open Islandflow Desktop to connect ChatGPT, load managed models, and use native Copilot controls."
+ };
+ }
+ if (!bridgeAvailable) {
+ return {
+ title: "Bridge unavailable in this window",
+ body: "This Islandflow Desktop window is missing its native AI bridge, so login actions and model controls stay disabled until the bridge reconnects. Reload the window or restart Islandflow if this keeps happening."
+ };
+ }
+ return null;
+};
@@
- <button className="terminal-button terminal-button-primary">Browser login</button>
- <button className="terminal-button">Device code</button>
+ <button
+ className="terminal-button terminal-button-primary"
+ type="button"
+ onClick={() => window.location.reload()}
+ >
+ Reload window
+ </button>
@@
+ {bridgeNotice ? (
+ <div className="copilot-callout copilot-callout-warning">
+ <strong>{bridgeNotice.title}</strong>
+ <p className="copilot-note">{bridgeNotice.body}</p>
+ </div>
+ ) : null}
Model controls copy and empty states
diff --git a/apps/web/app/desktop-ai-panels.tsx b/apps/web/app/desktop-ai-panels.tsx
@@
+const modelSelectLabel = getDesktopAiModelSelectLabel(
+ shellAvailable,
+ bridgeAvailable,
+ state.account.loggedIn,
+ state.models.length
+);
+const modelListEmptyCopy = getDesktopAiModelListEmptyCopy(
+ shellAvailable,
+ bridgeAvailable,
+ state.account.loggedIn
+);
@@
- <option value="">Use server default</option>
+ <option value="">{modelSelectLabel}</option>
@@
- {state.models.map((model) => (
- <div className="copilot-model-row" key={model.id}>...</div>
- ))}
+ {state.models.length === 0 ? (
+ <p className="copilot-empty">{modelListEmptyCopy}</p>
+ ) : (
+ state.models.map((model) => (
+ <div className="copilot-model-row" key={model.id}>...</div>
+ ))
+ )}
Unit coverage and warning presentation
diff --git a/apps/web/app/desktop-ai.test.ts b/apps/web/app/desktop-ai.test.ts
@@
+describe("desktop ai settings copy", () => {
+ it("explains when the native bridge is missing from the desktop window", () => {
+ expect(getDesktopAiSettingsBridgeNotice(true, false)?.title).toBe(
+ "Bridge unavailable in this window"
+ );
+ });
+
+ it("keeps the model selector explicit while the bridge is disconnected", () => {
+ expect(getDesktopAiModelSelectLabel(true, false, false, 0)).toBe("Bridge unavailable");
+ expect(getDesktopAiModelListEmptyCopy(true, false, false)).toContain(
+ "native AI bridge reconnects"
+ );
+ });
+});
diff --git a/apps/web/app/globals.css b/apps/web/app/globals.css
@@
+.copilot-callout-warning {
+ border-color: oklch(0.74 0.08 68 / 0.42);
+ background: oklch(0.2 0.03 68 / 0.28);
+}