- {(resolved) => (
-
-
- {formatElapsedTime(resolved().duration)}
-
- · {formatReasonLabel(resolved().reason!)}
-
-
- )}
+ {(resolved) => {
+ const reason = resolved().reason;
+ const reasonLabel = reason && reason !== "completed" ? formatReasonLabel(reason) : null;
+ return (
+
+
+ {formatElapsedTime(resolved().duration)}
+
+ · {reasonLabel}
+
+
+ );
+ }}
-
diff --git a/packages/app/src/app/pages/session.tsx b/packages/app/src/app/pages/session.tsx
index 59d10b61..de7572b7 100644
--- a/packages/app/src/app/pages/session.tsx
+++ b/packages/app/src/app/pages/session.tsx
@@ -39,6 +39,7 @@ import Composer from "../components/session/composer";
import SessionSidebar, { type SidebarSectionState } from "../components/session/sidebar";
import ContextPanel from "../components/session/context-panel";
import FlyoutItem from "../components/flyout-item";
+import { formatElapsedTime } from "../utils";
export type SessionViewProps = {
selectedSessionId: string | null;
@@ -454,25 +455,6 @@ export default function SessionView(props: SessionViewProps) {
return Math.max(0, runTick() - start);
});
- const formatElapsedTime = (ms: number): string => {
- const seconds = Math.floor(ms / 1000);
- const minutes = Math.floor(seconds / 60);
- const hours = Math.floor(minutes / 60);
-
- if (hours > 0) {
- const remainingMinutes = minutes % 60;
- return remainingMinutes > 0 ? `${hours}h ${remainingMinutes}m` : `${hours}h`;
- }
- if (minutes > 0) {
- const remainingSeconds = seconds % 60;
- return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`;
- }
- if (seconds > 0) {
- return `${seconds}s`;
- }
- return `${ms}ms`;
- };
-
const runElapsedLabel = createMemo(() => formatElapsedTime(runElapsedMs()));
onMount(() => {
diff --git a/packages/app/src/app/utils/index.ts b/packages/app/src/app/utils/index.ts
index 38612a0c..fca16589 100644
--- a/packages/app/src/app/utils/index.ts
+++ b/packages/app/src/app/utils/index.ts
@@ -719,6 +719,12 @@ export function summarizeStep(part: Part): StepSummary {
return { title: "Thinking" };
}
+ if (part.type === "step-start" || part.type === "step-finish") {
+ return {
+ title: part.type === "step-start" ? "Step started" : "Step finished",
+ };
+ }
+
return { title: "Step" };
}
From c21ce06e1d792fbc215f8777f3b5a4ce6b7cbf47 Mon Sep 17 00:00:00 2001
From: Golenspade <2023004079@mails.cust.edu.cn>
Date: Mon, 2 Feb 2026 13:58:47 +0800
Subject: [PATCH 15/17] fix: resolve typecheck regressions after rebase
---
packages/app/src/app/app.tsx | 2 +-
packages/app/src/app/pages/settings.tsx | 6 ++++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/packages/app/src/app/app.tsx b/packages/app/src/app/app.tsx
index e5c3a28e..ff3e836c 100644
--- a/packages/app/src/app/app.tsx
+++ b/packages/app/src/app/app.tsx
@@ -4187,7 +4187,7 @@ export default function App() {
})),
selectSession: selectSession,
messages: activeMessages(),
- messageTimings: isDemoMode() ? {} : messageTimings(),
+ messageTimings: messageTimings(),
todos: activeTodos(),
busyLabel: busyLabel(),
developerMode: developerMode(),
diff --git a/packages/app/src/app/pages/settings.tsx b/packages/app/src/app/pages/settings.tsx
index 4c230f99..0aa6ef74 100644
--- a/packages/app/src/app/pages/settings.tsx
+++ b/packages/app/src/app/pages/settings.tsx
@@ -282,7 +282,8 @@ function OwpenbotSettings(props: {
setOwpenbotStatus(latestStatus);
}
const serverClient = openworkServerClient();
- const useRemote = Boolean(serverClient && props.openworkServerWorkspaceId);
+ const workspaceId = props.openworkServerWorkspaceId;
+ const useRemote = Boolean(serverClient && workspaceId);
debugOwpenbot("save-token:start", {
mode: props.mode ?? "unknown",
tauri: isTauriRuntime(),
@@ -299,6 +300,7 @@ function OwpenbotSettings(props: {
),
});
if (useRemote) {
+ if (!serverClient || !workspaceId) return;
if (props.openworkServerStatus === "disconnected") {
setTelegramFeedback(
"error",
@@ -316,7 +318,7 @@ function OwpenbotSettings(props: {
setTelegramFeedback("checking", "Saving token on the host...");
try {
await serverClient.setOwpenbotTelegramToken(
- props.openworkServerWorkspaceId,
+ workspaceId,
token,
latestStatus?.healthPort ?? owpenbotStatus()?.healthPort ?? null,
);
From 407ad67f50c76f8ef611c3ed04f30a29c17c0056 Mon Sep 17 00:00:00 2001
From: Golenspade <2023004079@mails.cust.edu.cn>
Date: Mon, 2 Feb 2026 14:06:23 +0800
Subject: [PATCH 16/17] test: stabilize engine path resolution
---
packages/desktop/src-tauri/src/engine/doctor.rs | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/packages/desktop/src-tauri/src/engine/doctor.rs b/packages/desktop/src-tauri/src/engine/doctor.rs
index 433e3b6c..4a40e7a5 100644
--- a/packages/desktop/src-tauri/src/engine/doctor.rs
+++ b/packages/desktop/src-tauri/src/engine/doctor.rs
@@ -2,9 +2,8 @@ use std::ffi::OsStr;
use std::path::Path;
use crate::engine::paths::{
- resolve_opencode_env_override,
- resolve_opencode_executable,
- resolve_opencode_executable_without_override,
+ resolve_opencode_env_override, resolve_opencode_executable,
+ resolve_opencode_executable_without_override,
};
use crate::platform::command_for_program;
use crate::utils::truncate_output;
@@ -144,6 +143,12 @@ mod tests {
std::env::set_var(key, value);
Self { key, original }
}
+
+ fn unset(key: &'static str) -> Self {
+ let original = std::env::var(key).ok();
+ std::env::remove_var(key);
+ Self { key, original }
+ }
}
impl Drop for EnvVarGuard {
@@ -194,6 +199,8 @@ mod tests {
#[test]
#[cfg(not(windows))]
fn resolve_engine_path_prefers_sidecar() {
+ let _lock = ENV_LOCK.lock().expect("lock env");
+ let _guard = EnvVarGuard::unset("OPENCODE_BIN_PATH");
let dir = unique_temp_dir("engine-path-test");
std::fs::create_dir_all(&dir).expect("create temp dir");
@@ -228,7 +235,9 @@ mod tests {
let (resolved, _in_path, notes) =
resolve_engine_path(true, None, Some(sidecar_dir.as_path()));
assert_eq!(resolved.as_ref(), Some(&override_path));
- assert!(notes.iter().any(|note| note.contains("Using OPENCODE_BIN_PATH")));
+ assert!(notes
+ .iter()
+ .any(|note| note.contains("Using OPENCODE_BIN_PATH")));
let _ = std::fs::remove_dir_all(&override_dir);
let _ = std::fs::remove_dir_all(&sidecar_dir);
From cfdbc6ccfc185a3b6cc3090984caa3892da596ec Mon Sep 17 00:00:00 2001
From: Golenspade <2023004079@mails.cust.edu.cn>
Date: Mon, 2 Feb 2026 14:13:50 +0800
Subject: [PATCH 17/17] ci: install bun for linux desktop build
---
.github/workflows/build-desktop.yml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/.github/workflows/build-desktop.yml b/.github/workflows/build-desktop.yml
index 52f5bfc5..a41b06ed 100644
--- a/.github/workflows/build-desktop.yml
+++ b/.github/workflows/build-desktop.yml
@@ -26,6 +26,11 @@ jobs:
with:
version: 10.27.0
+ - name: Setup Bun
+ uses: oven-sh/setup-bun@v1
+ with:
+ bun-version: "1.3.6"
+
- name: Install dependencies
run: pnpm install --frozen-lockfile