From 7a32fec008fdfb5bc034ba3ce1bca365c1d342f5 Mon Sep 17 00:00:00 2001 From: Adam <2363879+adamdotdevin@users.noreply.github.com> Date: Mon, 3 Nov 2025 06:50:38 -0600 Subject: [PATCH] wip: desktop work --- .../src/components/message-progress.tsx | 172 ++++++++++++------ packages/desktop/src/pages/index.tsx | 78 +------- 2 files changed, 119 insertions(+), 131 deletions(-) diff --git a/packages/desktop/src/components/message-progress.tsx b/packages/desktop/src/components/message-progress.tsx index 5533ae41..4633a953 100644 --- a/packages/desktop/src/components/message-progress.tsx +++ b/packages/desktop/src/components/message-progress.tsx @@ -1,7 +1,7 @@ import { For, JSXElement, Match, Show, Switch, createEffect, createMemo, createSignal, onCleanup } from "solid-js" -import { Markdown, Part } from "@opencode-ai/ui" +import { Part } from "@opencode-ai/ui" import { useSync } from "@/context/sync" -import type { AssistantMessage as AssistantMessageType, Part as PartType, ToolPart } from "@opencode-ai/sdk" +import type { AssistantMessage as AssistantMessageType, ToolPart } from "@opencode-ai/sdk" import { Spinner } from "./spinner" export function MessageProgress(props: { assistantMessages: () => AssistantMessageType[]; done?: boolean }) { @@ -22,7 +22,6 @@ export function MessageProgress(props: { assistantMessages: () => AssistantMessa p.state.status === "running", ) as ToolPart, ) - const resolvedParts = createMemo(() => { let resolved = parts() const task = currentTask() @@ -32,20 +31,18 @@ export function MessageProgress(props: { assistantMessages: () => AssistantMessa } return resolved }) - const currentText = createMemo( - () => - resolvedParts().findLast((p) => p?.type === "text")?.text || - resolvedParts().findLast((p) => p?.type === "reasoning")?.text, - ) + // const currentText = createMemo( + // () => + // resolvedParts().findLast((p) => p?.type === "text")?.text || + // resolvedParts().findLast((p) => p?.type === "reasoning")?.text, + // ) const eligibleItems = createMemo(() => { - return resolvedParts().filter((p) => p?.type === "tool" && p.state.status === "completed") + return resolvedParts().filter((p) => p?.type === "tool" && p.state.status === "completed") as ToolPart[] }) - const finishedItems = createMemo<(JSXElement | PartType)[]>(() => [ + const finishedItems = createMemo<(JSXElement | ToolPart)[]>(() => [ +
,
,
, -
- Thinking... -
, ...eligibleItems(), ...(done() ? [
,
,
] : []), ]) @@ -71,57 +68,120 @@ export function MessageProgress(props: { assistantMessages: () => AssistantMessa return `-${(total - 2) * 40 - 8}px` }) + const lastPart = createMemo(() => resolvedParts().slice(-1)?.at(0)) + const rawStatus = createMemo(() => { + const defaultStatus = "Working..." + const last = lastPart() + if (!last) return defaultStatus + + if (last.type === "tool") { + switch (last.tool) { + case "task": + return "Delegating work..." + case "todowrite": + case "todoread": + return "Planning next steps..." + case "read": + return "Gathering context..." + case "list": + case "grep": + case "glob": + return "Searching the codebase..." + case "webfetch": + return "Searching the web..." + case "edit": + case "write": + return "Making edits..." + case "bash": + return "Running commands..." + default: + break + } + } else if (last.type === "reasoning") { + return "Thinking..." + } else if (last.type === "text") { + return "Gathering thoughts..." + } + return defaultStatus + }) + + const [status, setStatus] = createSignal(rawStatus()) + let lastStatusChange = Date.now() + let statusTimeout: number | undefined + + createEffect(() => { + const newStatus = rawStatus() + if (newStatus === status()) return + + const timeSinceLastChange = Date.now() - lastStatusChange + + if (timeSinceLastChange >= 1000) { + setStatus(newStatus) + lastStatusChange = Date.now() + if (statusTimeout) { + clearTimeout(statusTimeout) + statusTimeout = undefined + } + } else { + if (statusTimeout) clearTimeout(statusTimeout) + statusTimeout = setTimeout(() => { + setStatus(rawStatus()) + lastStatusChange = Date.now() + statusTimeout = undefined + }, 1000 - timeSinceLastChange) as unknown as number + } + }) + return (
-
*/} + {/* */} + {/*
*/} + {/* )} */} + {/* */} +
+ {status()} +
+ 0}> +
-
- - {(part) => { - if (part && typeof part === "object" && "type" in part) { - const message = createMemo(() => sync.data.message[part.sessionID].find((m) => m.id === part.messageID)) - return ( -
- - - {(p) => ( -
- )} - - - {(p) => } - - - {(p) => } - - -
- ) - } - return
{part}
- }} - -
-
- - {(text) => (
- + + {(part) => ( + + + {(p) => { + const part = p() as ToolPart + const message = createMemo(() => + sync.data.message[part.sessionID].find((m) => m.id === part.messageID), + ) + return ( +
+ +
+ ) + }} +
+ +
{part as JSXElement}
+
+
+ )} +
- )} +
) diff --git a/packages/desktop/src/pages/index.tsx b/packages/desktop/src/pages/index.tsx index badd0009..eebfc436 100644 --- a/packages/desktop/src/pages/index.tsx +++ b/packages/desktop/src/pages/index.tsx @@ -548,77 +548,6 @@ export default function Page() { {(message) => { const diffs = createMemo(() => message.summary?.diffs ?? []) const working = createMemo(() => !message.summary?.body) - const assistantMessages = createMemo(() => { - return sync.data.message[activeSession().id]?.filter( - (m) => m.role === "assistant" && m.parentID == message.id, - ) as AssistantMessageType[] - }) - const parts = createMemo(() => - assistantMessages().flatMap((m) => sync.data.part[m.id]), - ) - const lastPart = createMemo(() => parts().slice(-1)?.at(0)) - const rawStatus = createMemo(() => { - const defaultStatus = "Working..." - const last = lastPart() - if (!last) return defaultStatus - - if (last.type === "tool") { - switch (last.tool) { - case "task": - return "Delegating work..." - case "todowrite": - case "todoread": - return "Planning next steps..." - case "read": - return "Gathering context..." - case "list": - case "grep": - case "glob": - return "Searching the codebase..." - case "webfetch": - return "Searching the web..." - case "edit": - case "write": - return "Making edits..." - case "bash": - return "Running commands..." - default: - break - } - } else if (last.type === "reasoning") { - return "Thinking..." - } else if (last.type === "text") { - return "Gathering thoughts..." - } - return defaultStatus - }) - - const [status, setStatus] = createSignal(rawStatus()) - let lastStatusChange = Date.now() - let statusTimeout: number | undefined - - createEffect(() => { - const newStatus = rawStatus() - if (newStatus === status()) return - - const timeSinceLastChange = Date.now() - lastStatusChange - - if (timeSinceLastChange >= 1000) { - setStatus(newStatus) - lastStatusChange = Date.now() - if (statusTimeout) { - clearTimeout(statusTimeout) - statusTimeout = undefined - } - } else { - if (statusTimeout) clearTimeout(statusTimeout) - statusTimeout = setTimeout(() => { - setStatus(rawStatus()) - lastStatusChange = Date.now() - statusTimeout = undefined - }, 1000 - timeSinceLastChange) as unknown as number - } - }) return (
  • @@ -641,10 +570,9 @@ export default function Page() { "text-text-weak data-[active=true]:text-text-strong group-hover/li:text-text-base": true, }} > - - {status()} - {message.summary?.title} - + + {message.summary?.title} +