{/* @ Mention dropdown */}
@@ -471,7 +472,20 @@ function MarqueeText({ text, className }: { text: string; className?: string })
)
}
-function AgentStatusBar({ todos, room, workingFiles = [] }: { todos: TodoItem[]; room?: { status: string; activeAgent?: string; action?: string; master: string }; workingFiles?: { agent: string; filename: string; title?: string }[] }) {
+function ElapsedTimer({ startedAt }: { startedAt: number }) {
+ const [, setTick] = useState(0)
+ useEffect(() => {
+ const id = setInterval(() => setTick(t => t + 1), 1000)
+ return () => clearInterval(id)
+ }, [])
+ const elapsed = Math.floor((Date.now() - startedAt) / 1000)
+ const m = Math.floor(elapsed / 60)
+ const s = elapsed % 60
+ const text = m > 0 ? `${m}m${s.toString().padStart(2, '0')}s` : `${s}s`
+ return
{text}
+}
+
+function AgentStatusBar({ todos, room, workingFiles = [], startedAt }: { todos: TodoItem[]; room?: { status: string; activeAgent?: string; action?: string; master: string }; workingFiles?: { agent: string; filename: string; title?: string }[]; startedAt?: number }) {
// 只在 master 本人是活跃 agent 或正在思考时显示 master 状态
const showMaster = room && (
room.status === 'thinking' ||
@@ -481,6 +495,7 @@ function AgentStatusBar({ todos, room, workingFiles = [] }: { todos: TodoItem[];
return (
+ {startedAt &&
}
{/* 文件生成状态 */}
{workingFiles.map(f => (
fileReaders: Record
>
workingFiles: Record
+ workStartedAt: Record // roomId -> timestamp (ms)
setTheme: (theme: 'light' | 'dark') => void
toggleTheme: () => void
@@ -83,6 +84,7 @@ export const useStore = create((set, get) => {
todoItems: {},
fileReaders: {},
workingFiles: {},
+ workStartedAt: {},
setTheme: (theme) => {
applyTheme(theme)
@@ -257,6 +259,13 @@ export const useStore = create((set, get) => {
: t
)
}
+ // 记录工作开始时间(thinking/working 时设置,pending 时清除)
+ const workStartedAt = { ...s.workStartedAt }
+ if (ev.status === 'pending') {
+ delete workStartedAt[roomId]
+ } else if (!workStartedAt[roomId]) {
+ workStartedAt[roomId] = Date.now()
+ }
// pending 时:清理所有残留 streaming 消息,只在所有任务都 done 后清空 todos
if (ev.status === 'pending') {
const cleanMsgs = (s.messages[roomId] || []).map(m =>
@@ -273,6 +282,7 @@ export const useStore = create((set, get) => {
messages: { ...s.messages, [roomId]: cleanMsgs },
todoItems: { ...s.todoItems, [roomId]: todos },
workingFiles: { ...s.workingFiles, [roomId]: [] },
+ workStartedAt,
}
}
return {
@@ -280,6 +290,7 @@ export const useStore = create((set, get) => {
? { ...r, status: ev.status, activeAgent: ev.active_agent, action: ev.action }
: r),
todoItems: { ...s.todoItems, [roomId]: todos },
+ workStartedAt,
}
})
} else if (ev.type === 'tasks_update') {