Repository Turn Document

AI Alert Copilot UX

Upgraded the desktop Copilot result surface so generated analysis now reads like Islandflow content instead of raw terminal output. The alert panel can reuse session results by action, expose Regenerate after completion, show live running/cancel states, and request task cancellation through the desktop bridge.

Issueislandflow-xtg
Primary SurfaceAlert Copilot
Validation272 tests passed

Summary

Implemented the AI alert Copilot UX refinement: markdown rendering, in-place loading and cancellation, current-session task caching for alert actions, and regenerate controls for completed outputs.

Changes Made

  • Added react-markdown to the web app and replaced raw Copilot result pre output with safe markdown rendering.
  • Created reusable task-surface helpers for empty, running, completed, failed, and cancelled display decisions.
  • Added a compact spinner, status copy, and Cancel button for queued/running task states.
  • Added per-session alert task caching keyed by action kind and smart-money event context.
  • Added Regenerate for completed alert, replay, and screen compiler results.
  • Extended the desktop AI bridge, preload script, IPC constants, main process handler, and desktop service with cancelTask(taskId).
  • Added tests for cache selection, regenerate eligibility, task-surface states, and desktop cancellation behavior.

Context

The previous Copilot output surface showed model text as raw preformatted content. That made structured markdown harder to scan and gave users no way to interrupt a task once it started.

The plan treated persistence as current app-session persistence only, so the cache intentionally lives in panel state rather than disk or a global store.

Important Implementation Details

Relevant Diff Snippets

Patch-style snippets prepared for Diffs-style review. Reference: Diffs rendering docs.

Task result surface

@@ apps/web/app/desktop-ai-panels.tsx
+import ReactMarkdown from "react-markdown";
+
+export const getCopilotTaskSurfaceState = (...) => {
+  if (!task) return "empty";
+  if (RUNNING_TASK_STATUSES.includes(task.status)) return "running";
+  if (task.status === "completed") return "completed";
+  if (task.status === "failed") return "failed";
+  return "cancelled";
+};
+
+{surfaceState === "running" ? (
+  <div className="copilot-task-running-row">
+    <span className="copilot-spinner" aria-hidden="true" />
+    <p className="copilot-note">Generating analysis as deltas arrive.</p>
+    <button className="terminal-button" onClick={() => onCancel(task.taskId)}>Cancel</button>
+  </div>
+) : null}
+{task.text ? (
+  <div className="copilot-markdown">
+    <ReactMarkdown>{task.text}</ReactMarkdown>
+  </div>
+) : null}

Desktop cancellation bridge

@@ apps/desktop/src/desktop-ai-ipc.ts
+export const DESKTOP_AI_CANCEL_TASK = "islandflow:desktop-ai:cancel-task";

@@ apps/desktop/src/main.ts
+ipcMain.handle(DESKTOP_AI_CANCEL_TASK, async (event, taskId) => {
+  guard(event);
+  await service.cancelTask(String(taskId));
+});

@@ apps/desktop/src/desktop-ai.ts
+async cancelTask(taskId: string): Promise<void> {
+  const task = this.state.tasks.find((candidate) => candidate.taskId === taskId);
+  if (!task || (task.status !== "queued" && task.status !== "running")) return;
+  this.locallyCancelledTaskIds.add(taskId);
+  this.patchTask(taskId, { status: "cancelled", error: null });
+  if (task.threadId) {
+    this.activeTasksByThreadId.delete(task.threadId);
+    await this.client.request("turn/cancel", { threadId: task.threadId, turnId: task.turnId ?? undefined }).catch(() => undefined);
+  }
+}

Expected Impact for End-Users

Validation

Passed bun test

All 272 tests passed across 43 files.

Passed bun test apps/web/app/desktop-ai.test.ts apps/desktop/src/desktop-ai.test.ts

23 focused desktop AI tests passed after the final helper adjustment.

Blocked bun --cwd=apps/web run build

The production build compiled successfully, then failed during TypeScript on the known packages/types/src/desktop-ai.ts import-extension issue: ./events.ts requires allowImportingTsExtensions.

Issues, Limitations, and Mitigations

Follow-up Work