|
1 | 1 | import { useEffect, useMemo, useState } from "react"; |
2 | 2 | import { spawn } from "node:child_process"; |
3 | 3 | import { Box, Text, useInput, useStdout } from "ink"; |
4 | | -import type { AgentSummary, RunSummary } from "@codex-workflows/schemas"; |
5 | | -import { nowIso, RunStore } from "@codex-workflows/runtime"; |
| 4 | +import type { AgentSummary, RunSummary, StorageScope } from "@codex-workflows/schemas"; |
| 5 | +import { defaultStoreRoot, nowIso, RunStore } from "@codex-workflows/runtime"; |
6 | 6 | import { formatCount, formatDuration, truncateMiddle } from "./format.js"; |
7 | 7 |
|
8 | 8 | export interface DashboardProps { |
9 | 9 | cwd: string; |
10 | 10 | runId: string; |
| 11 | + storageScope?: StorageScope; |
| 12 | + storeRoot?: string; |
11 | 13 | exitOnComplete?: boolean; |
12 | 14 | onExit?: () => void; |
13 | 15 | } |
@@ -117,6 +119,18 @@ export function DashboardFrame({ |
117 | 119 | </Text> |
118 | 120 | </Box> |
119 | 121 | <Text color="gray">{summary.description}</Text> |
| 122 | + <Box justifyContent="space-between"> |
| 123 | + <Text color={summary.status === "failed" ? "red" : summary.status === "completed" ? "green" : "gray"}> |
| 124 | + {summary.status} |
| 125 | + {summary.error ? ` · ${truncateMiddle(summary.error, Math.max(20, width - 72))}` : ""} |
| 126 | + </Text> |
| 127 | + <Text color="gray"> |
| 128 | + {summary.requestedAdapter ?? "auto"} → {summary.actualAdapter ?? "pending"} |
| 129 | + </Text> |
| 130 | + </Box> |
| 131 | + {summary.finalReportPath ? ( |
| 132 | + <Text color="gray">Report: {truncateMiddle(summary.finalReportPath, width - 8)}</Text> |
| 133 | + ) : null} |
120 | 134 | <Box marginTop={1} borderStyle="single" borderColor="gray"> |
121 | 135 | <Box width={sidebarWidth} flexDirection="column" borderStyle="single" borderTop={false} borderBottom={false} borderLeft={false}> |
122 | 136 | <Text>Phases</Text> |
@@ -198,8 +212,19 @@ export function DashboardFrame({ |
198 | 212 | ); |
199 | 213 | } |
200 | 214 |
|
201 | | -export function RunDashboard({ cwd, runId, exitOnComplete = false, onExit }: DashboardProps) { |
202 | | - const store = useMemo(() => new RunStore(cwd), [cwd]); |
| 215 | +export function RunDashboard({ |
| 216 | + cwd, |
| 217 | + runId, |
| 218 | + storageScope = "codex-home", |
| 219 | + storeRoot, |
| 220 | + exitOnComplete = false, |
| 221 | + onExit |
| 222 | +}: DashboardProps) { |
| 223 | + const resolvedStoreRoot = storeRoot ?? defaultStoreRoot(cwd, storageScope); |
| 224 | + const store = useMemo( |
| 225 | + () => new RunStore(cwd, { storageScope, storeRoot: resolvedStoreRoot }), |
| 226 | + [cwd, resolvedStoreRoot, storageScope] |
| 227 | + ); |
203 | 228 | const [summary, setSummary] = useState<RunSummary | null>(null); |
204 | 229 | const [selectedPhaseId, setSelectedPhaseId] = useState<string | undefined>(); |
205 | 230 | const [selectedAgentId, setSelectedAgentId] = useState<string | undefined>(); |
@@ -313,7 +338,18 @@ export function RunDashboard({ cwd, runId, exitOnComplete = false, onExit }: Das |
313 | 338 | if (input === "r" && selectedAgentId) { |
314 | 339 | const child = spawn( |
315 | 340 | process.execPath, |
316 | | - [process.argv[1] ?? "", "restart-agent", runId, selectedAgentId, "--cwd", cwd], |
| 341 | + [ |
| 342 | + process.argv[1] ?? "", |
| 343 | + "restart-agent", |
| 344 | + runId, |
| 345 | + selectedAgentId, |
| 346 | + "--cwd", |
| 347 | + cwd, |
| 348 | + "--storage-scope", |
| 349 | + storageScope, |
| 350 | + "--store-root", |
| 351 | + resolvedStoreRoot |
| 352 | + ], |
317 | 353 | { stdio: "ignore", detached: true } |
318 | 354 | ); |
319 | 355 | child.unref(); |
|
0 commit comments