@synergenius/flow-weaver-pack-weaver 0.9.200 → 0.9.201
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-chat-provider.js +5 -5
- package/dist/ai-chat-provider.js.map +1 -1
- package/dist/bot/acceptance-merge.d.ts +21 -0
- package/dist/bot/acceptance-merge.d.ts.map +1 -0
- package/dist/bot/acceptance-merge.js +46 -0
- package/dist/bot/acceptance-merge.js.map +1 -0
- package/dist/bot/ai-client.d.ts +14 -2
- package/dist/bot/ai-client.d.ts.map +1 -1
- package/dist/bot/ai-client.js +71 -24
- package/dist/bot/ai-client.js.map +1 -1
- package/dist/bot/assistant-tools.js +3 -3
- package/dist/bot/assistant-tools.js.map +1 -1
- package/dist/bot/audit-logger.d.ts.map +1 -1
- package/dist/bot/audit-logger.js +34 -14
- package/dist/bot/audit-logger.js.map +1 -1
- package/dist/bot/audit-trail.d.ts +67 -0
- package/dist/bot/audit-trail.d.ts.map +1 -0
- package/dist/bot/audit-trail.js +153 -0
- package/dist/bot/audit-trail.js.map +1 -0
- package/dist/bot/behavior-defaults.d.ts +1 -1
- package/dist/bot/behavior-defaults.d.ts.map +1 -1
- package/dist/bot/behavior-defaults.js +7 -3
- package/dist/bot/behavior-defaults.js.map +1 -1
- package/dist/bot/capability-registry.d.ts +9 -0
- package/dist/bot/capability-registry.d.ts.map +1 -1
- package/dist/bot/capability-registry.js +81 -27
- package/dist/bot/capability-registry.js.map +1 -1
- package/dist/bot/capability-types.d.ts +10 -0
- package/dist/bot/capability-types.d.ts.map +1 -1
- package/dist/bot/cli-provider.d.ts.map +1 -1
- package/dist/bot/cli-provider.js +8 -7
- package/dist/bot/cli-provider.js.map +1 -1
- package/dist/bot/preflight.d.ts +48 -0
- package/dist/bot/preflight.d.ts.map +1 -0
- package/dist/bot/preflight.js +247 -0
- package/dist/bot/preflight.js.map +1 -0
- package/dist/bot/provider-shim.d.ts +74 -0
- package/dist/bot/provider-shim.d.ts.map +1 -0
- package/dist/bot/provider-shim.js +176 -0
- package/dist/bot/provider-shim.js.map +1 -0
- package/dist/bot/runner.d.ts +2 -0
- package/dist/bot/runner.d.ts.map +1 -1
- package/dist/bot/runner.js +60 -17
- package/dist/bot/runner.js.map +1 -1
- package/dist/bot/step-executor.d.ts.map +1 -1
- package/dist/bot/step-executor.js +72 -115
- package/dist/bot/step-executor.js.map +1 -1
- package/dist/bot/swarm-controller.d.ts +2 -0
- package/dist/bot/swarm-controller.d.ts.map +1 -1
- package/dist/bot/swarm-controller.js +92 -20
- package/dist/bot/swarm-controller.js.map +1 -1
- package/dist/bot/task-create-handler.d.ts +37 -0
- package/dist/bot/task-create-handler.d.ts.map +1 -0
- package/dist/bot/task-create-handler.js +124 -0
- package/dist/bot/task-create-handler.js.map +1 -0
- package/dist/bot/task-store.d.ts +1 -0
- package/dist/bot/task-store.d.ts.map +1 -1
- package/dist/bot/task-store.js +61 -0
- package/dist/bot/task-store.js.map +1 -1
- package/dist/bot/types.d.ts +1 -1
- package/dist/bot/types.d.ts.map +1 -1
- package/dist/bot/weaver-tools.d.ts.map +1 -1
- package/dist/bot/weaver-tools.js +7 -39
- package/dist/bot/weaver-tools.js.map +1 -1
- package/dist/node-types/agent-execute.d.ts +25 -8
- package/dist/node-types/agent-execute.d.ts.map +1 -1
- package/dist/node-types/agent-execute.js +89 -23
- package/dist/node-types/agent-execute.js.map +1 -1
- package/dist/node-types/bot-report.d.ts.map +1 -1
- package/dist/node-types/bot-report.js +24 -3
- package/dist/node-types/bot-report.js.map +1 -1
- package/dist/node-types/plan-task.d.ts +8 -17
- package/dist/node-types/plan-task.d.ts.map +1 -1
- package/dist/node-types/plan-task.js +217 -256
- package/dist/node-types/plan-task.js.map +1 -1
- package/dist/node-types/review-result.js +8 -6
- package/dist/node-types/review-result.js.map +1 -1
- package/dist/palindrome.d.ts +9 -0
- package/dist/palindrome.d.ts.map +1 -0
- package/dist/palindrome.js +14 -0
- package/dist/palindrome.js.map +1 -0
- package/dist/ui/approval-card.js +91 -82
- package/dist/ui/bot-activity.js +73 -56
- package/dist/ui/bot-config.js +48 -31
- package/dist/ui/bot-dashboard.js +52 -36
- package/dist/ui/bot-panel.js +230 -228
- package/dist/ui/bot-slot-card.js +100 -90
- package/dist/ui/bot-status.js +37 -15
- package/dist/ui/budget-bar.js +57 -31
- package/dist/ui/capability-editor.js +447 -378
- package/dist/ui/chat-task-result.js +78 -71
- package/dist/ui/decision-log.js +68 -81
- package/dist/ui/genesis-block.js +86 -95
- package/dist/ui/instance-stream-view.js +722 -0
- package/dist/ui/profile-card.js +96 -221
- package/dist/ui/profile-editor.js +532 -575
- package/dist/ui/settings-section.js +41 -45
- package/dist/ui/swarm-controls.js +212 -135
- package/dist/ui/swarm-dashboard.js +3992 -2715
- package/dist/ui/task-detail-view.js +415 -521
- package/dist/ui/task-editor.js +339 -390
- package/dist/ui/task-pool-list.js +60 -55
- package/dist/workflows/src/palindrome.d.ts +11 -0
- package/dist/workflows/src/palindrome.d.ts.map +1 -0
- package/dist/workflows/src/palindrome.js +16 -0
- package/dist/workflows/src/palindrome.js.map +1 -0
- package/dist/workflows/tests/palindrome.test.d.ts +2 -0
- package/dist/workflows/tests/palindrome.test.d.ts.map +1 -0
- package/dist/workflows/tests/palindrome.test.js +41 -0
- package/dist/workflows/tests/palindrome.test.js.map +1 -0
- package/dist/workflows/weaver-bot-batch.js +1 -1
- package/dist/workflows/weaver-bot-batch.js.map +1 -1
- package/dist/workflows/weaver-bot.js +1 -1
- package/dist/workflows/weaver-bot.js.map +1 -1
- package/flowweaver.manifest.json +1 -1
- package/package.json +8 -2
- package/src/ai-chat-provider.ts +5 -5
- package/src/bot/acceptance-merge.ts +62 -0
- package/src/bot/ai-client.ts +77 -21
- package/src/bot/assistant-tools.ts +3 -3
- package/src/bot/audit-logger.ts +42 -14
- package/src/bot/audit-trail.ts +211 -0
- package/src/bot/behavior-defaults.ts +7 -2
- package/src/bot/capability-registry.ts +84 -28
- package/src/bot/capability-types.ts +11 -0
- package/src/bot/cli-provider.ts +8 -7
- package/src/bot/preflight.ts +285 -0
- package/src/bot/provider-shim.ts +218 -0
- package/src/bot/runner.ts +68 -20
- package/src/bot/step-executor.ts +69 -127
- package/src/bot/swarm-controller.ts +94 -20
- package/src/bot/task-create-handler.ts +164 -0
- package/src/bot/task-store.ts +76 -0
- package/src/bot/types.ts +4 -1
- package/src/bot/weaver-tools.ts +7 -45
- package/src/node-types/agent-execute.ts +102 -16
- package/src/node-types/bot-report.ts +24 -3
- package/src/node-types/plan-task.ts +238 -280
- package/src/node-types/review-result.ts +8 -6
- package/src/palindrome.ts +14 -0
- package/src/ui/approval-card.tsx +78 -62
- package/src/ui/bot-activity.tsx +12 -10
- package/src/ui/bot-config.tsx +12 -10
- package/src/ui/bot-dashboard.tsx +13 -11
- package/src/ui/bot-panel.tsx +189 -171
- package/src/ui/bot-slot-card.tsx +125 -70
- package/src/ui/bot-status.tsx +4 -4
- package/src/ui/budget-bar.tsx +86 -25
- package/src/ui/capability-editor.tsx +392 -257
- package/src/ui/chat-task-result.tsx +81 -78
- package/src/ui/decision-log.tsx +76 -73
- package/src/ui/genesis-block.tsx +91 -61
- package/src/ui/instance-stream-view.tsx +861 -0
- package/src/ui/profile-card.tsx +195 -168
- package/src/ui/profile-editor.tsx +453 -370
- package/src/ui/settings-section.tsx +46 -39
- package/src/ui/swarm-controls.tsx +252 -123
- package/src/ui/swarm-dashboard.tsx +999 -466
- package/src/ui/task-detail-view.tsx +485 -428
- package/src/ui/task-editor.tsx +329 -271
- package/src/ui/task-pool-list.tsx +68 -62
- package/src/workflows/src/palindrome.ts +16 -0
- package/src/workflows/tests/palindrome.test.ts +49 -0
- package/src/workflows/weaver-bot-batch.ts +1 -1
- package/src/workflows/weaver-bot.ts +1 -1
- package/dist/ui/bot-constants.d.ts +0 -14
- package/dist/ui/bot-constants.d.ts.map +0 -1
- package/dist/ui/bot-constants.js +0 -189
- package/dist/ui/bot-constants.js.map +0 -1
- package/dist/ui/steer-api.d.ts +0 -7
- package/dist/ui/steer-api.d.ts.map +0 -1
- package/dist/ui/steer-api.js +0 -11
- package/dist/ui/steer-api.js.map +0 -1
- package/dist/ui/trace-to-timeline.d.ts +0 -91
- package/dist/ui/trace-to-timeline.d.ts.map +0 -1
- package/dist/ui/trace-to-timeline.js +0 -116
- package/dist/ui/trace-to-timeline.js.map +0 -1
- package/dist/ui/use-stream-timeline.d.ts +0 -50
- package/dist/ui/use-stream-timeline.d.ts.map +0 -1
- package/dist/ui/use-stream-timeline.js +0 -245
- package/dist/ui/use-stream-timeline.js.map +0 -1
|
@@ -9,12 +9,11 @@
|
|
|
9
9
|
* - Active run: live streaming via useEventStream
|
|
10
10
|
* - Back button to return to dashboard
|
|
11
11
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const {
|
|
12
|
+
import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
|
13
|
+
import {
|
|
15
14
|
Flex, Typography, ScrollArea, StatusIcon, Badge, Icon, IconButton, TaskBlock, Button,
|
|
16
15
|
Card, Chip, Checkbox, Table, Tabs, EmptyState, toast, usePackWorkspace, useEventStream,
|
|
17
|
-
}
|
|
16
|
+
} from '@fw/plugin-ui-kit';
|
|
18
17
|
|
|
19
18
|
import { useStreamTimeline } from './use-stream-timeline';
|
|
20
19
|
import { traceToTimeline } from './trace-to-timeline';
|
|
@@ -155,36 +154,42 @@ const subtaskRowHoverStyle: React.CSSProperties = {
|
|
|
155
154
|
|
|
156
155
|
function FileItemRow({ children }: { children: React.ReactNode }) {
|
|
157
156
|
const [hovered, setHovered] = useState(false);
|
|
158
|
-
return
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
157
|
+
return (
|
|
158
|
+
<Flex
|
|
159
|
+
variant="row-center-start-nowrap-0"
|
|
160
|
+
style={hovered ? fileItemHoverStyle : fileItemStyle}
|
|
161
|
+
onMouseEnter={() => setHovered(true)}
|
|
162
|
+
onMouseLeave={() => setHovered(false)}
|
|
163
|
+
>
|
|
164
|
+
{children}
|
|
165
|
+
</Flex>
|
|
166
|
+
);
|
|
164
167
|
}
|
|
165
168
|
|
|
166
169
|
function SubtaskRowItem({ sub, onBack }: { sub: Subtask; onBack: () => void }) {
|
|
167
170
|
const [hovered, setHovered] = useState(false);
|
|
168
|
-
return
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
171
|
+
return (
|
|
172
|
+
<Flex
|
|
173
|
+
variant="row-center-start-nowrap-8"
|
|
174
|
+
style={hovered ? subtaskRowHoverStyle : subtaskRowStyle}
|
|
175
|
+
onClick={() => onBack()}
|
|
176
|
+
onMouseEnter={() => setHovered(true)}
|
|
177
|
+
onMouseLeave={() => setHovered(false)}
|
|
178
|
+
>
|
|
179
|
+
<StatusIcon
|
|
180
|
+
status={statusToIcon[sub.status] || 'pending'}
|
|
181
|
+
size="sm"
|
|
182
|
+
/>
|
|
183
|
+
<Flex
|
|
184
|
+
variant="row-center-start-nowrap-0"
|
|
185
|
+
style={{ flex: 1, minWidth: 0 }}
|
|
186
|
+
>
|
|
187
|
+
<Typography variant="caption-regular" truncate={true}>{sub.title}</Typography>
|
|
188
|
+
</Flex>
|
|
189
|
+
{sub.assignedProfile && (
|
|
190
|
+
<Chip label={sub.assignedProfile} size="small" color="color-status-info" />
|
|
191
|
+
)}
|
|
192
|
+
</Flex>
|
|
188
193
|
);
|
|
189
194
|
}
|
|
190
195
|
|
|
@@ -197,13 +202,13 @@ function TaskDetailView({ taskId, onBack, onEdit }: TaskDetailViewProps) {
|
|
|
197
202
|
const { callTool } = ctx;
|
|
198
203
|
const packId = ctx.packId;
|
|
199
204
|
|
|
200
|
-
//
|
|
205
|
+
// -- Task data --
|
|
201
206
|
const [task, setTask] = useState<Task | null>(null);
|
|
202
207
|
const [subtasks, setSubtasks] = useState<Subtask[]>([]);
|
|
203
208
|
const [history, setHistory] = useState<HistoricalRun[]>([]);
|
|
204
209
|
const [loading, setLoading] = useState(true);
|
|
205
210
|
|
|
206
|
-
//
|
|
211
|
+
// -- Fetch task data --
|
|
207
212
|
const fetchTask = useCallback(async () => {
|
|
208
213
|
try {
|
|
209
214
|
const raw = await callTool('fw_weaver_task_get', { id: taskId });
|
|
@@ -284,7 +289,7 @@ function TaskDetailView({ taskId, onBack, onEdit }: TaskDetailViewProps) {
|
|
|
284
289
|
return () => clearInterval(interval);
|
|
285
290
|
}, [task?.status, fetchTask, fetchHistory]);
|
|
286
291
|
|
|
287
|
-
//
|
|
292
|
+
// -- Live streaming for active run --
|
|
288
293
|
const stream = useEventStream();
|
|
289
294
|
const {
|
|
290
295
|
timeline: liveTimeline,
|
|
@@ -306,10 +311,10 @@ function TaskDetailView({ taskId, onBack, onEdit }: TaskDetailViewProps) {
|
|
|
306
311
|
return () => stream.stop();
|
|
307
312
|
}, [isLive, activeRunId, packId]);
|
|
308
313
|
|
|
309
|
-
//
|
|
314
|
+
// -- Detail tab state --
|
|
310
315
|
const [detailTab, setDetailTab] = useState('runs');
|
|
311
316
|
|
|
312
|
-
//
|
|
317
|
+
// -- Action state --
|
|
313
318
|
const [actionLoading, setActionLoading] = useState<string | null>(null);
|
|
314
319
|
const [availableProfiles, setAvailableProfiles] = useState<Array<{ id: string; name: string; icon?: string; color?: string }>>([]);
|
|
315
320
|
|
|
@@ -372,7 +377,7 @@ function TaskDetailView({ taskId, onBack, onEdit }: TaskDetailViewProps) {
|
|
|
372
377
|
} catch { /* non-fatal */ }
|
|
373
378
|
}, [callTool, taskId, task, fetchTask]);
|
|
374
379
|
|
|
375
|
-
//
|
|
380
|
+
// -- Run expansion state --
|
|
376
381
|
const [expandedRunId, setExpandedRunId] = useState<string | null>(null);
|
|
377
382
|
const [liveExpanded, setLiveExpanded] = useState(true);
|
|
378
383
|
|
|
@@ -380,14 +385,14 @@ function TaskDetailView({ taskId, onBack, onEdit }: TaskDetailViewProps) {
|
|
|
380
385
|
setExpandedRunId((prev: string | null) => (prev === id ? null : id));
|
|
381
386
|
}, []);
|
|
382
387
|
|
|
383
|
-
//
|
|
388
|
+
// -- Auto-scroll --
|
|
384
389
|
const scrollRef = useRef<HTMLDivElement>(null);
|
|
385
390
|
useEffect(() => {
|
|
386
391
|
const el = scrollRef.current;
|
|
387
392
|
if (el) el.scrollTop = el.scrollHeight;
|
|
388
393
|
}, [liveTimeline.length, stream.events.length]);
|
|
389
394
|
|
|
390
|
-
//
|
|
395
|
+
// -- Approval handling --
|
|
391
396
|
const [approvalStatus, setApprovalStatus] = useState<'pending' | 'approved' | 'rejected' | null>(null);
|
|
392
397
|
const [approvalLoading, setApprovalLoading] = useState(false);
|
|
393
398
|
|
|
@@ -423,7 +428,7 @@ function TaskDetailView({ taskId, onBack, onEdit }: TaskDetailViewProps) {
|
|
|
423
428
|
setApprovalLoading(false);
|
|
424
429
|
}, [callTool]);
|
|
425
430
|
|
|
426
|
-
//
|
|
431
|
+
// -- Build run timeline entries from history --
|
|
427
432
|
const runItems = useMemo(() => {
|
|
428
433
|
return history.map((run: HistoricalRun) => ({
|
|
429
434
|
run,
|
|
@@ -431,24 +436,19 @@ function TaskDetailView({ taskId, onBack, onEdit }: TaskDetailViewProps) {
|
|
|
431
436
|
}));
|
|
432
437
|
}, [history]);
|
|
433
438
|
|
|
434
|
-
//
|
|
435
|
-
// The run.instruction may be a raw markdown prompt ("## Task: Title\n\n...")
|
|
436
|
-
// or a plain string. Extract just the title for display.
|
|
439
|
+
// -- Extract instruction from run --
|
|
437
440
|
function extractInstruction(run: HistoricalRun): string {
|
|
438
441
|
if (run.instruction) {
|
|
439
442
|
const text = run.instruction;
|
|
440
|
-
// Extract title from markdown prompt format: "## Task: Title\n\n..."
|
|
441
443
|
const titleMatch = text.match(/^##\s*Task:\s*(.+)/m);
|
|
442
444
|
if (titleMatch) {
|
|
443
445
|
const title = titleMatch[1].trim();
|
|
444
446
|
return title.length > 120 ? title.slice(0, 117) + '...' : title;
|
|
445
447
|
}
|
|
446
|
-
// Extract from "Task: Title | ..." pipe-separated summary
|
|
447
448
|
if (text.startsWith('Task:')) {
|
|
448
449
|
const title = text.split('|')[0].replace('Task:', '').trim();
|
|
449
450
|
return title.length > 120 ? title.slice(0, 117) + '...' : title;
|
|
450
451
|
}
|
|
451
|
-
// Plain instruction — use first line only
|
|
452
452
|
const firstLine = text.split('\n')[0].trim();
|
|
453
453
|
return firstLine.length > 120 ? firstLine.slice(0, 117) + '...' : firstLine;
|
|
454
454
|
}
|
|
@@ -463,58 +463,49 @@ function TaskDetailView({ taskId, onBack, onEdit }: TaskDetailViewProps) {
|
|
|
463
463
|
}
|
|
464
464
|
return summary.length > 120 ? summary.slice(0, 117) + '...' : summary;
|
|
465
465
|
}
|
|
466
|
-
// Fall back to task title if available
|
|
467
466
|
return task?.title ?? 'Bot run';
|
|
468
467
|
}
|
|
469
468
|
|
|
470
|
-
//
|
|
469
|
+
// -- Loading state --
|
|
471
470
|
if (loading && !task) {
|
|
472
|
-
return
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
variant
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
React.createElement(Typography, { variant: 'caption-regular', color: 'color-text-subtle' },
|
|
490
|
-
'Loading task...',
|
|
491
|
-
),
|
|
492
|
-
),
|
|
471
|
+
return (
|
|
472
|
+
<Flex
|
|
473
|
+
variant="column-stretch-start-nowrap-0"
|
|
474
|
+
style={{ width: '100%', height: '100%', overflow: 'hidden' }}
|
|
475
|
+
>
|
|
476
|
+
<Flex variant="column-stretch-start-nowrap-8" style={headerStyle}>
|
|
477
|
+
<Button variant="ghost" size="sm" onClick={onBack}>
|
|
478
|
+
<Icon name="arrowBack" size={16} />
|
|
479
|
+
{' Back'}
|
|
480
|
+
</Button>
|
|
481
|
+
</Flex>
|
|
482
|
+
<Flex variant="column-center-center-nowrap-0" style={{ flex: 1 }}>
|
|
483
|
+
<Typography variant="caption-regular" color="color-text-subtle">
|
|
484
|
+
Loading task...
|
|
485
|
+
</Typography>
|
|
486
|
+
</Flex>
|
|
487
|
+
</Flex>
|
|
493
488
|
);
|
|
494
489
|
}
|
|
495
490
|
|
|
496
491
|
if (!task) {
|
|
497
|
-
return
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
variant
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
React.createElement(Typography, { variant: 'caption-regular', color: 'color-text-subtle' },
|
|
515
|
-
'Task not found.',
|
|
516
|
-
),
|
|
517
|
-
),
|
|
492
|
+
return (
|
|
493
|
+
<Flex
|
|
494
|
+
variant="column-stretch-start-nowrap-0"
|
|
495
|
+
style={{ width: '100%', height: '100%', overflow: 'hidden' }}
|
|
496
|
+
>
|
|
497
|
+
<Flex variant="column-stretch-start-nowrap-8" style={headerStyle}>
|
|
498
|
+
<Button variant="ghost" size="sm" onClick={onBack}>
|
|
499
|
+
<Icon name="arrowBack" size={16} />
|
|
500
|
+
{' Back'}
|
|
501
|
+
</Button>
|
|
502
|
+
</Flex>
|
|
503
|
+
<Flex variant="column-center-center-nowrap-0" style={{ flex: 1 }}>
|
|
504
|
+
<Typography variant="caption-regular" color="color-text-subtle">
|
|
505
|
+
Task not found.
|
|
506
|
+
</Typography>
|
|
507
|
+
</Flex>
|
|
508
|
+
</Flex>
|
|
518
509
|
);
|
|
519
510
|
}
|
|
520
511
|
|
|
@@ -522,348 +513,414 @@ function TaskDetailView({ taskId, onBack, onEdit }: TaskDetailViewProps) {
|
|
|
522
513
|
const hasSubtasks = task.isParent && subtasks.length > 0;
|
|
523
514
|
const hasRuns = runItems.length > 0 || isLive;
|
|
524
515
|
|
|
525
|
-
return
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
{
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
516
|
+
return (
|
|
517
|
+
<Flex
|
|
518
|
+
variant="column-stretch-start-nowrap-0"
|
|
519
|
+
style={{ width: '100%', height: '100%', overflow: 'hidden' }}
|
|
520
|
+
>
|
|
521
|
+
{/* -- Header -- */}
|
|
522
|
+
<Flex
|
|
523
|
+
variant="column-stretch-start-nowrap-6"
|
|
524
|
+
style={{ ...headerStyle, padding: '12px 16px', borderBottom: '1px solid var(--color-border-default)' }}
|
|
525
|
+
>
|
|
526
|
+
{/* Top row: back + title + status + edit */}
|
|
527
|
+
<Flex variant="row-center-space-between-nowrap-8">
|
|
528
|
+
<Flex variant="row-center-start-nowrap-8" style={{ flex: 1, minWidth: 0 }}>
|
|
529
|
+
<IconButton
|
|
530
|
+
icon="back"
|
|
531
|
+
size="xs"
|
|
532
|
+
variant="clear"
|
|
533
|
+
onClick={onBack}
|
|
534
|
+
/>
|
|
535
|
+
<StatusIcon
|
|
536
|
+
status={statusToIcon[task.status] || 'pending'}
|
|
537
|
+
size="sm"
|
|
538
|
+
/>
|
|
539
|
+
<Typography
|
|
540
|
+
variant="caption-thick"
|
|
541
|
+
color="color-text-high"
|
|
542
|
+
style={{ flex: 1, minWidth: 0, wordBreak: 'break-word' }}
|
|
543
|
+
>
|
|
544
|
+
{task.title || 'Untitled Task'}
|
|
545
|
+
</Typography>
|
|
546
|
+
</Flex>
|
|
547
|
+
{onEdit && (
|
|
548
|
+
<IconButton
|
|
549
|
+
icon="edit"
|
|
550
|
+
size="xs"
|
|
551
|
+
variant="clear"
|
|
552
|
+
onClick={() => onEdit(taskId)}
|
|
553
|
+
title="Edit task"
|
|
554
|
+
/>
|
|
555
|
+
)}
|
|
556
|
+
</Flex>
|
|
557
|
+
|
|
558
|
+
{/* Meta row: status tag, assigned profile, priority, attempts */}
|
|
559
|
+
<Flex variant="row-center-start-wrap-6">
|
|
560
|
+
<Chip
|
|
561
|
+
label={statusToLabel[task.status as TaskStatus] || task.status || 'open'}
|
|
562
|
+
size="small"
|
|
563
|
+
color={task.status === 'done' ? 'color-status-positive'
|
|
564
|
+
: task.status === 'cancelled' ? 'color-status-negative'
|
|
565
|
+
: task.status === 'in-progress' ? 'color-status-info'
|
|
566
|
+
: 'color-brand-alt'}
|
|
567
|
+
/>
|
|
568
|
+
|
|
569
|
+
{task.assignedProfile && (
|
|
570
|
+
<Chip key={`profile-${task.assignedProfile}`} label={task.assignedProfile} size="small" color="color-status-info" />
|
|
571
|
+
)}
|
|
572
|
+
|
|
573
|
+
{task.priority > 0 && (
|
|
574
|
+
<Chip
|
|
575
|
+
label={`P${task.priority}`}
|
|
576
|
+
size="small"
|
|
577
|
+
color={task.priority >= 3 ? 'color-status-caution' : 'color-status-info'}
|
|
578
|
+
/>
|
|
579
|
+
)}
|
|
580
|
+
|
|
581
|
+
{(task.context?.runHistory?.length ?? 0) > 0 && (
|
|
582
|
+
<Typography variant="smallCaption-regular" color="color-text-subtle">
|
|
583
|
+
{`${task.context.runHistory.length} run${task.context.runHistory.length !== 1 ? 's' : ''}`}
|
|
584
|
+
</Typography>
|
|
585
|
+
)}
|
|
586
|
+
</Flex>
|
|
587
|
+
|
|
588
|
+
{/* Description */}
|
|
589
|
+
{task.description && (
|
|
590
|
+
<Typography variant="smallCaption-regular" color="color-text-medium">
|
|
591
|
+
{task.description}
|
|
592
|
+
</Typography>
|
|
593
|
+
)}
|
|
594
|
+
|
|
595
|
+
{/* Profile routing info */}
|
|
596
|
+
{task.assignedProfile && (
|
|
597
|
+
<Flex variant="column-stretch-start-nowrap-2">
|
|
598
|
+
<Typography variant="smallCaption-regular" color="color-text-medium">
|
|
599
|
+
{`Profile: ${task.assignedProfile}`}
|
|
600
|
+
</Typography>
|
|
601
|
+
{task.routingReason && (
|
|
602
|
+
<Typography variant="smallCaption-regular" color="color-text-subtle">
|
|
603
|
+
{task.routingReason}
|
|
604
|
+
</Typography>
|
|
605
|
+
)}
|
|
606
|
+
</Flex>
|
|
607
|
+
)}
|
|
608
|
+
</Flex>
|
|
609
|
+
|
|
610
|
+
{/* -- Tabs -- */}
|
|
611
|
+
<Tabs
|
|
612
|
+
tabs={[
|
|
613
|
+
{ id: 'runs', title: `Runs (${runItems.length}${isLive ? '+1' : ''})` },
|
|
614
|
+
...(hasSubtasks ? [{ id: 'subtasks', title: `Subtasks (${subtasks.filter((s: Subtask) => s.status === 'done').length}/${subtasks.length})` }] : []),
|
|
615
|
+
...(task.status !== 'done' && task.status !== 'cancelled' ? [{ id: 'actions', title: 'Actions' }] : []),
|
|
616
|
+
...(hasContext ? [{ id: 'context', title: 'Context' }] : []),
|
|
617
|
+
]}
|
|
618
|
+
activeTabId={detailTab}
|
|
619
|
+
onSelectTab={(id: string) => setDetailTab(id)}
|
|
620
|
+
size="sm"
|
|
621
|
+
/>
|
|
622
|
+
|
|
623
|
+
{/* -- Tab content -- */}
|
|
624
|
+
<ScrollArea ref={scrollRef} style={{ flex: 1 }}>
|
|
625
|
+
<Flex variant="column-stretch-start-nowrap-8" style={{ padding: '12px 16px' }}>
|
|
626
|
+
|
|
627
|
+
{/* -- Runs tab -- */}
|
|
628
|
+
{detailTab === 'runs' && (hasRuns || (task.context?.runHistory?.length ?? 0) > 0)
|
|
629
|
+
? (
|
|
630
|
+
<Flex variant="column-stretch-start-nowrap-8">
|
|
631
|
+
{/* Historical runs */}
|
|
632
|
+
{runItems.map(({ run, runTimeline }: { run: HistoricalRun; runTimeline: Array<Record<string, unknown>> }) => {
|
|
633
|
+
const runId = run.id;
|
|
634
|
+
const isExpanded = expandedRunId === runId;
|
|
635
|
+
const isSuccess = run.outcome === 'completed' || run.success === true;
|
|
636
|
+
return (
|
|
637
|
+
<TaskBlock
|
|
638
|
+
key={`run-${runId}`}
|
|
639
|
+
state={isSuccess ? 'completed' : 'failed'}
|
|
640
|
+
instruction={extractInstruction(run)}
|
|
641
|
+
timeline={runTimeline}
|
|
642
|
+
report={run.report ?? null}
|
|
643
|
+
cost={typeof run.cost === 'number' ? run.cost : ((run.costDetail?.totalCost as number) ?? null)}
|
|
644
|
+
plan={run.plan}
|
|
645
|
+
startedAt={run.startedAt}
|
|
646
|
+
durationMs={run.durationMs ?? run.duration}
|
|
647
|
+
expanded={isExpanded}
|
|
648
|
+
onToggleExpand={() => toggleExpand(runId)}
|
|
649
|
+
/>
|
|
650
|
+
);
|
|
651
|
+
})}
|
|
652
|
+
{/* Live run */}
|
|
653
|
+
{isLive && (
|
|
654
|
+
<TaskBlock
|
|
655
|
+
key="live-run"
|
|
656
|
+
state="running"
|
|
657
|
+
instruction={liveInstruction ?? task.title}
|
|
658
|
+
timeline={liveTimeline}
|
|
659
|
+
report={liveReport}
|
|
660
|
+
phase={livePhase}
|
|
661
|
+
elapsed={elapsed}
|
|
662
|
+
cost={liveCost}
|
|
663
|
+
plan={plan}
|
|
664
|
+
error={stream.error}
|
|
665
|
+
approval={approvalStatus ?? undefined}
|
|
666
|
+
approvalLoading={approvalLoading}
|
|
667
|
+
onApprove={handleApprove}
|
|
668
|
+
onReject={handleReject}
|
|
669
|
+
expanded={liveExpanded}
|
|
670
|
+
onToggleExpand={() => setLiveExpanded((v: boolean) => !v)}
|
|
671
|
+
/>
|
|
672
|
+
)}
|
|
673
|
+
</Flex>
|
|
660
674
|
)
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
)
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
675
|
+
: detailTab === 'runs' && (
|
|
676
|
+
<EmptyState
|
|
677
|
+
icon="smartToy"
|
|
678
|
+
message="No runs yet"
|
|
679
|
+
description="This task has not been executed yet."
|
|
680
|
+
/>
|
|
681
|
+
)}
|
|
682
|
+
|
|
683
|
+
{/* -- Subtasks tab -- */}
|
|
684
|
+
{detailTab === 'subtasks' && hasSubtasks && (
|
|
685
|
+
<Flex variant="column-stretch-start-nowrap-0">
|
|
686
|
+
{(subtasks ?? []).map((sub: Subtask) => (
|
|
687
|
+
<SubtaskRowItem
|
|
688
|
+
key={sub.id}
|
|
689
|
+
sub={sub}
|
|
690
|
+
onBack={onBack}
|
|
691
|
+
/>
|
|
692
|
+
))}
|
|
693
|
+
</Flex>
|
|
694
|
+
)}
|
|
695
|
+
|
|
696
|
+
{/* -- Actions tab -- */}
|
|
697
|
+
{detailTab === 'actions' && (
|
|
698
|
+
<Flex variant="column-stretch-start-nowrap-16">
|
|
699
|
+
{/* Status actions */}
|
|
700
|
+
<Flex variant="column-stretch-start-nowrap-8">
|
|
701
|
+
<Typography variant="caption-thick" color="color-text-medium">Status</Typography>
|
|
702
|
+
<Flex variant="row-center-start-nowrap-6">
|
|
703
|
+
{(task.status === 'open' && (task.context?.runHistory?.length ?? 0) > 0) && (
|
|
704
|
+
<Button
|
|
705
|
+
size="xs"
|
|
706
|
+
variant="fill"
|
|
707
|
+
color="primary"
|
|
708
|
+
onClick={handleRetry}
|
|
709
|
+
loading={actionLoading === 'retry'}
|
|
710
|
+
disabled={!!actionLoading}
|
|
711
|
+
>
|
|
712
|
+
Retry Task
|
|
713
|
+
</Button>
|
|
714
|
+
)}
|
|
715
|
+
|
|
716
|
+
{(task.status === 'open' || task.status === 'in-progress') && (
|
|
717
|
+
<Button
|
|
718
|
+
size="xs"
|
|
719
|
+
variant="outlined"
|
|
720
|
+
color="danger"
|
|
721
|
+
onClick={handleCancel}
|
|
722
|
+
loading={actionLoading === 'cancel'}
|
|
723
|
+
disabled={!!actionLoading}
|
|
724
|
+
>
|
|
725
|
+
Cancel Task
|
|
726
|
+
</Button>
|
|
727
|
+
)}
|
|
728
|
+
</Flex>
|
|
729
|
+
</Flex>
|
|
730
|
+
|
|
731
|
+
{/* Priority */}
|
|
732
|
+
<Flex variant="column-stretch-start-nowrap-8">
|
|
733
|
+
<Typography variant="caption-thick" color="color-text-medium">Priority</Typography>
|
|
734
|
+
<Flex variant="row-center-start-nowrap-8">
|
|
735
|
+
<IconButton
|
|
736
|
+
icon="expandLess"
|
|
737
|
+
size="xs"
|
|
738
|
+
variant="outlined"
|
|
739
|
+
onClick={() => handlePriorityChange(1)}
|
|
740
|
+
title="Increase priority"
|
|
741
|
+
/>
|
|
742
|
+
<Typography variant="smallCaption-regular" color="color-text-high">
|
|
743
|
+
{`P${task.priority ?? 0}`}
|
|
744
|
+
</Typography>
|
|
745
|
+
<IconButton
|
|
746
|
+
icon="expandMore"
|
|
747
|
+
size="xs"
|
|
748
|
+
variant="outlined"
|
|
749
|
+
onClick={() => handlePriorityChange(-1)}
|
|
750
|
+
title="Decrease priority"
|
|
751
|
+
/>
|
|
752
|
+
</Flex>
|
|
753
|
+
</Flex>
|
|
754
|
+
|
|
755
|
+
{/* Assign Profile */}
|
|
756
|
+
{availableProfiles.length > 0 && (
|
|
757
|
+
<Flex variant="column-stretch-start-nowrap-8">
|
|
758
|
+
<Typography variant="caption-thick" color="color-text-medium">Assign Profile</Typography>
|
|
759
|
+
<Table
|
|
760
|
+
size="compact"
|
|
761
|
+
getRowKey={(row: Record<string, unknown>) => row.id as string}
|
|
762
|
+
columns={[
|
|
763
|
+
{
|
|
764
|
+
key: 'icon',
|
|
765
|
+
header: '',
|
|
766
|
+
width: '30px',
|
|
767
|
+
render: (_: unknown, row: Record<string, unknown>) => (
|
|
768
|
+
<Icon
|
|
769
|
+
name={(row.icon as string) || 'smartToy'}
|
|
770
|
+
size={14}
|
|
771
|
+
color={(row.color as string) || 'color-text-medium'}
|
|
772
|
+
/>
|
|
773
|
+
),
|
|
774
|
+
},
|
|
775
|
+
{
|
|
776
|
+
key: 'name',
|
|
777
|
+
header: 'Profile',
|
|
778
|
+
},
|
|
779
|
+
{
|
|
780
|
+
key: 'capabilities',
|
|
781
|
+
header: 'Capabilities',
|
|
782
|
+
render: (_: unknown, row: Record<string, unknown>) => {
|
|
783
|
+
const caps = (row.capabilities as Array<{ name: string; description: string }>) || [];
|
|
784
|
+
if (caps.length === 0) return null;
|
|
785
|
+
return (
|
|
786
|
+
<Flex variant="row-center-start-wrap-4">
|
|
787
|
+
{caps.slice(0, 4).map((cap) => (
|
|
788
|
+
<span key={cap.name} title={cap.description}>
|
|
789
|
+
<Chip label={cap.name} size="small" color="color-brand-main" />
|
|
790
|
+
</span>
|
|
791
|
+
))}
|
|
792
|
+
{caps.length > 4 && (
|
|
793
|
+
<Typography variant="smallCaption-regular" color="color-text-subtle">
|
|
794
|
+
{`+${caps.length - 4}`}
|
|
795
|
+
</Typography>
|
|
796
|
+
)}
|
|
797
|
+
</Flex>
|
|
798
|
+
);
|
|
799
|
+
},
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
key: 'assigned',
|
|
803
|
+
header: 'Assign',
|
|
804
|
+
width: '50px',
|
|
805
|
+
align: 'right' as const,
|
|
806
|
+
render: (_: unknown, row: Record<string, unknown>) => {
|
|
807
|
+
const isAssigned = task.assignedProfile === (row.id as string);
|
|
808
|
+
return (
|
|
809
|
+
<Checkbox
|
|
810
|
+
checked={isAssigned}
|
|
811
|
+
onChange={() => handleAssignProfile(row.id as string)}
|
|
812
|
+
size="sm"
|
|
813
|
+
/>
|
|
814
|
+
);
|
|
815
|
+
},
|
|
816
|
+
},
|
|
817
|
+
]}
|
|
818
|
+
data={availableProfiles}
|
|
819
|
+
/>
|
|
820
|
+
</Flex>
|
|
821
|
+
)}
|
|
822
|
+
</Flex>
|
|
823
|
+
)}
|
|
824
|
+
|
|
825
|
+
{/* -- Context tab -- */}
|
|
826
|
+
{detailTab === 'context' && hasContext && (
|
|
827
|
+
<Flex variant="column-stretch-start-nowrap-12">
|
|
828
|
+
{/* Files */}
|
|
829
|
+
{(task.context?.files?.length ?? 0) > 0 && (
|
|
830
|
+
<Flex variant="column-stretch-start-nowrap-4">
|
|
831
|
+
<Typography variant="caption-thick" color="color-text-medium">Files</Typography>
|
|
832
|
+
{(task.context?.files ?? []).map((file: string) => (
|
|
833
|
+
<Typography
|
|
834
|
+
key={file}
|
|
835
|
+
variant="smallCaption-regular"
|
|
836
|
+
color="color-text-high"
|
|
837
|
+
style={{ fontFamily: 'var(--font-mono, monospace)' }}
|
|
838
|
+
>
|
|
839
|
+
{file}
|
|
840
|
+
</Typography>
|
|
841
|
+
))}
|
|
842
|
+
</Flex>
|
|
843
|
+
)}
|
|
844
|
+
|
|
845
|
+
{/* Notes */}
|
|
846
|
+
{task.context?.notes && (
|
|
847
|
+
<Flex variant="column-stretch-start-nowrap-4">
|
|
848
|
+
<Typography variant="caption-thick" color="color-text-medium">Notes</Typography>
|
|
849
|
+
<Typography
|
|
850
|
+
variant="smallCaption-regular"
|
|
851
|
+
color="color-text-high"
|
|
852
|
+
style={{ whiteSpace: 'pre-wrap' }}
|
|
853
|
+
>
|
|
854
|
+
{task.context.notes}
|
|
855
|
+
</Typography>
|
|
856
|
+
</Flex>
|
|
857
|
+
)}
|
|
858
|
+
|
|
859
|
+
{/* Run history (accumulated context) */}
|
|
860
|
+
{(task.context?.runHistory?.length ?? 0) > 0 && (
|
|
861
|
+
<Flex variant="column-stretch-start-nowrap-6">
|
|
862
|
+
<Typography variant="caption-thick" color="color-text-medium">Run History</Typography>
|
|
863
|
+
{(task.context?.runHistory ?? []).map((rs: Record<string, unknown>, i: number) => (
|
|
864
|
+
<Card
|
|
865
|
+
key={`rs-${i}`}
|
|
866
|
+
variant="bordered"
|
|
867
|
+
padding="compact"
|
|
868
|
+
style={{ gap: '4px' }}
|
|
869
|
+
>
|
|
870
|
+
<Flex variant="row-center-space-between-nowrap-8">
|
|
871
|
+
<Typography
|
|
872
|
+
variant="smallCaption-thick"
|
|
873
|
+
color={rs.outcome === 'success' ? 'color-status-positive' : 'color-status-negative'}
|
|
874
|
+
>
|
|
875
|
+
{`${rs.outcome === 'success' ? 'Success' : 'Failed'} (${(rs as Record<string, unknown>).botId ?? 'unknown bot'})`}
|
|
876
|
+
</Typography>
|
|
877
|
+
<Typography variant="smallCaption-regular" color="color-text-subtle">
|
|
878
|
+
{`${Math.round((rs.durationMs as number ?? 0) / 1000)}s · ${rs.tokensUsed ?? 0} tok · $${((rs.cost as number) ?? 0).toFixed(3)}`}
|
|
879
|
+
</Typography>
|
|
880
|
+
</Flex>
|
|
881
|
+
<Typography variant="smallCaption-regular" color="color-text-medium">
|
|
882
|
+
{rs.summary as string ?? ''}
|
|
883
|
+
</Typography>
|
|
884
|
+
{(rs.filesModified as string[] ?? []).length > 0 && (
|
|
885
|
+
<Typography
|
|
886
|
+
variant="smallCaption-regular"
|
|
887
|
+
color="color-text-subtle"
|
|
888
|
+
style={{ fontFamily: 'var(--font-mono, monospace)' }}
|
|
889
|
+
>
|
|
890
|
+
{`Files: ${(rs.filesModified as string[]).join(', ')}`}
|
|
891
|
+
</Typography>
|
|
892
|
+
)}
|
|
893
|
+
{rs.remainingWork && (
|
|
894
|
+
<Typography variant="smallCaption-regular" color="color-status-caution">
|
|
895
|
+
{`Remaining: ${rs.remainingWork}`}
|
|
896
|
+
</Typography>
|
|
897
|
+
)}
|
|
898
|
+
</Card>
|
|
899
|
+
))}
|
|
900
|
+
</Flex>
|
|
901
|
+
)}
|
|
902
|
+
|
|
903
|
+
{/* Budget */}
|
|
904
|
+
{(task.tokensUsed > 0 || task.costUsed > 0) && (
|
|
905
|
+
<Flex variant="column-stretch-start-nowrap-4">
|
|
906
|
+
<Typography variant="caption-thick" color="color-text-medium">Budget</Typography>
|
|
907
|
+
<Flex variant="row-center-start-nowrap-16">
|
|
908
|
+
<Typography variant="smallCaption-regular" color="color-text-high">
|
|
909
|
+
{`Tokens: ${task.tokensUsed?.toLocaleString() ?? 0}`}
|
|
910
|
+
</Typography>
|
|
911
|
+
<Typography variant="smallCaption-regular" color="color-text-high">
|
|
912
|
+
{`Cost: $${(task.costUsed ?? 0).toFixed(3)}${task.budgetCost ? ` / $${task.budgetCost.toFixed(2)}` : ''}`}
|
|
913
|
+
</Typography>
|
|
914
|
+
</Flex>
|
|
915
|
+
</Flex>
|
|
916
|
+
)}
|
|
917
|
+
</Flex>
|
|
918
|
+
)}
|
|
919
|
+
</Flex>
|
|
920
|
+
</ScrollArea>
|
|
921
|
+
</Flex>
|
|
864
922
|
);
|
|
865
923
|
}
|
|
866
924
|
|
|
867
925
|
export { TaskDetailView };
|
|
868
926
|
export default TaskDetailView;
|
|
869
|
-
module.exports = TaskDetailView;
|