opencode-top 3.1.0 → 3.1.2
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/package.json +1 -1
- package/src/ui/App.tsx +14 -1
- package/src/ui/components/MessagesPanel.tsx +22 -17
package/package.json
CHANGED
package/src/ui/App.tsx
CHANGED
|
@@ -29,6 +29,19 @@ export function App({ refreshInterval = 2000 }: AppProps) {
|
|
|
29
29
|
const terminalHeight = stdout?.rows ?? 24;
|
|
30
30
|
const terminalWidth = stdout?.columns ?? 80;
|
|
31
31
|
|
|
32
|
+
// Enter alternate screen buffer on mount — prevents Ink's clearTerminal flash.
|
|
33
|
+
// Ink triggers \x1b[2J\x1b[3J\x1b[H whenever outputHeight >= stdout.rows.
|
|
34
|
+
// Alt screen (\x1b[?1049h) moves rendering to a separate buffer so the main
|
|
35
|
+
// screen is never touched, eliminating the black flash entirely.
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
stdout?.write("\x1b[?1049h"); // enter alt screen
|
|
38
|
+
stdout?.write("\x1b[?25l"); // hide cursor
|
|
39
|
+
return () => {
|
|
40
|
+
stdout?.write("\x1b[?25h"); // restore cursor
|
|
41
|
+
stdout?.write("\x1b[?1049l"); // leave alt screen
|
|
42
|
+
};
|
|
43
|
+
}, [stdout]);
|
|
44
|
+
|
|
32
45
|
const [workflows, setWorkflows] = useState<Workflow[]>([]);
|
|
33
46
|
const [screen, setScreen] = useState<ScreenId>("sessions");
|
|
34
47
|
const [error, setError] = useState<string | null>(null);
|
|
@@ -108,7 +121,7 @@ export function App({ refreshInterval = 2000 }: AppProps) {
|
|
|
108
121
|
const contentHeight = terminalHeight - 3;
|
|
109
122
|
|
|
110
123
|
return (
|
|
111
|
-
<Box flexDirection="column" width={terminalWidth} height={terminalHeight}>
|
|
124
|
+
<Box flexDirection="column" width={terminalWidth} height={terminalHeight - 1}>
|
|
112
125
|
<TabBar activeScreen={screen} lastRefresh={lastRefresh} />
|
|
113
126
|
<Box width={terminalWidth} height={contentHeight}>
|
|
114
127
|
{screen === "sessions" && (
|
|
@@ -10,11 +10,11 @@ interface MessagesPanelProps {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
type MsgLine =
|
|
13
|
-
| { kind: "header"; modelId: string; agent: string | null; duration: string; time: string }
|
|
14
|
-
| { kind: "tool"; callId: string; icon: string; iconColor: string; name: string; title: string; right: string; expanded: boolean }
|
|
15
|
-
| { kind: "tool-detail"; label: string; value: string; isSection: boolean }
|
|
16
|
-
| { kind: "text"; text: string }
|
|
17
|
-
| { kind: "reasoning"; text: string };
|
|
13
|
+
| { id: string; kind: "header"; modelId: string; agent: string | null; duration: string; time: string }
|
|
14
|
+
| { id: string; kind: "tool"; callId: string; icon: string; iconColor: string; name: string; title: string; right: string; expanded: boolean }
|
|
15
|
+
| { id: string; kind: "tool-detail"; label: string; value: string; isSection: boolean }
|
|
16
|
+
| { id: string; kind: "text"; text: string }
|
|
17
|
+
| { id: string; kind: "reasoning"; text: string };
|
|
18
18
|
|
|
19
19
|
function buildLines(session: Session, contentWidth: number, expandedIds: Set<string>): MsgLine[] {
|
|
20
20
|
const lines: MsgLine[] = [];
|
|
@@ -27,6 +27,7 @@ function buildLines(session: Session, contentWidth: number, expandedIds: Set<str
|
|
|
27
27
|
: "";
|
|
28
28
|
|
|
29
29
|
lines.push({
|
|
30
|
+
id: `h-${interaction.id}`,
|
|
30
31
|
kind: "header",
|
|
31
32
|
modelId: interaction.modelId,
|
|
32
33
|
agent: interaction.agent ?? null,
|
|
@@ -45,6 +46,7 @@ function buildLines(session: Session, contentWidth: number, expandedIds: Set<str
|
|
|
45
46
|
const expanded = expandedIds.has(p.callId);
|
|
46
47
|
|
|
47
48
|
lines.push({
|
|
49
|
+
id: `t-${p.callId}`,
|
|
48
50
|
kind: "tool",
|
|
49
51
|
callId: p.callId,
|
|
50
52
|
icon,
|
|
@@ -58,29 +60,32 @@ function buildLines(session: Session, contentWidth: number, expandedIds: Set<str
|
|
|
58
60
|
if (expanded) {
|
|
59
61
|
const inputKeys = Object.keys(p.input);
|
|
60
62
|
if (inputKeys.length > 0) {
|
|
61
|
-
lines.push({ kind: "tool-detail", label: "input", value: "", isSection: true });
|
|
63
|
+
lines.push({ id: `td-${p.callId}-in`, kind: "tool-detail", label: "input", value: "", isSection: true });
|
|
62
64
|
for (const key of inputKeys) {
|
|
63
65
|
const val = formatParamValue(p.input[key], contentWidth - key.length - 6);
|
|
64
|
-
lines.push({ kind: "tool-detail", label: key, value: val, isSection: false });
|
|
66
|
+
lines.push({ id: `td-${p.callId}-in-${key}`, kind: "tool-detail", label: key, value: val, isSection: false });
|
|
65
67
|
}
|
|
66
68
|
}
|
|
67
69
|
if (p.output?.trim()) {
|
|
68
|
-
lines.push({ kind: "tool-detail", label: "output", value: "", isSection: true });
|
|
70
|
+
lines.push({ id: `td-${p.callId}-out`, kind: "tool-detail", label: "output", value: "", isSection: true });
|
|
69
71
|
const outLines = p.output.trim().split("\n").slice(0, 40);
|
|
72
|
+
let outIdx = 0;
|
|
70
73
|
for (const ol of outLines) {
|
|
71
74
|
for (const wrapped of wrapText(ol === "" ? " " : ol, contentWidth - 5)) {
|
|
72
|
-
lines.push({ kind: "tool-detail", label: "", value: wrapped, isSection: false });
|
|
75
|
+
lines.push({ id: `td-${p.callId}-out-${outIdx++}`, kind: "tool-detail", label: "", value: wrapped, isSection: false });
|
|
73
76
|
}
|
|
74
77
|
}
|
|
75
78
|
}
|
|
76
79
|
}
|
|
77
80
|
} else if (part.type === "text" && part.text.trim()) {
|
|
81
|
+
let txtIdx = 0;
|
|
78
82
|
for (const row of wrapText(part.text.trim(), contentWidth - 3)) {
|
|
79
|
-
lines.push({ kind: "text", text: row });
|
|
83
|
+
lines.push({ id: `tx-${interaction.id}-${txtIdx++}`, kind: "text", text: row });
|
|
80
84
|
}
|
|
81
85
|
} else if (part.type === "reasoning" && part.text.trim()) {
|
|
86
|
+
let rIdx = 0;
|
|
82
87
|
for (const row of wrapText(part.text.trim(), contentWidth - 5)) {
|
|
83
|
-
lines.push({ kind: "reasoning", text: row });
|
|
88
|
+
lines.push({ id: `r-${interaction.id}-${rIdx++}`, kind: "reasoning", text: row });
|
|
84
89
|
}
|
|
85
90
|
}
|
|
86
91
|
}
|
|
@@ -251,7 +256,7 @@ function MessagesPanelInner({ session, maxHeight, isActive }: MessagesPanelProps
|
|
|
251
256
|
switch (line.kind) {
|
|
252
257
|
case "header":
|
|
253
258
|
return (
|
|
254
|
-
<Box key={
|
|
259
|
+
<Box key={line.id} flexDirection="row" height={1}>
|
|
255
260
|
<Text color={isCursor ? colors.accent : colors.textDim}>{isCursor ? "›" : " "}</Text>
|
|
256
261
|
<Text color={isCursor ? colors.accent : colors.purple} bold>◆ </Text>
|
|
257
262
|
<Text color={isCursor ? colors.accent : colors.info}>{truncate(line.modelId, 26)}</Text>
|
|
@@ -264,7 +269,7 @@ function MessagesPanelInner({ session, maxHeight, isActive }: MessagesPanelProps
|
|
|
264
269
|
|
|
265
270
|
case "tool":
|
|
266
271
|
return (
|
|
267
|
-
<Box key={
|
|
272
|
+
<Box key={line.id} flexDirection="row" height={1} paddingLeft={1}>
|
|
268
273
|
<Text color={isCursor ? colors.accent : colors.textDim}>{isCursor ? "›" : " "}</Text>
|
|
269
274
|
<Text color={line.iconColor}>{line.icon} </Text>
|
|
270
275
|
<Text color={isCursor ? colors.accent : colors.text} bold={isCursor}>{line.name}</Text>
|
|
@@ -278,14 +283,14 @@ function MessagesPanelInner({ session, maxHeight, isActive }: MessagesPanelProps
|
|
|
278
283
|
case "tool-detail":
|
|
279
284
|
if (line.isSection) {
|
|
280
285
|
return (
|
|
281
|
-
<Box key={
|
|
286
|
+
<Box key={line.id} height={1} paddingLeft={3}>
|
|
282
287
|
<Text color={isCursor ? colors.accent : colors.textDim}>{isCursor ? "›" : " "}</Text>
|
|
283
288
|
<Text color={colors.purple}>── {line.label} </Text>
|
|
284
289
|
</Box>
|
|
285
290
|
);
|
|
286
291
|
}
|
|
287
292
|
return (
|
|
288
|
-
<Box key={
|
|
293
|
+
<Box key={line.id} height={1} paddingLeft={4}>
|
|
289
294
|
<Text color={isCursor ? colors.accent : colors.textDim}>{isCursor ? "›" : " "}</Text>
|
|
290
295
|
{line.label
|
|
291
296
|
? <><Text color={colors.cyan}>{line.label}</Text><Text color={colors.textDim}>: </Text><Text color={isCursor ? colors.accent : colors.text}>{line.value}</Text></>
|
|
@@ -296,7 +301,7 @@ function MessagesPanelInner({ session, maxHeight, isActive }: MessagesPanelProps
|
|
|
296
301
|
|
|
297
302
|
case "text":
|
|
298
303
|
return (
|
|
299
|
-
<Box key={
|
|
304
|
+
<Box key={line.id} flexDirection="row" height={1} paddingLeft={1}>
|
|
300
305
|
<Text color={isCursor ? colors.accent : colors.textDim}>{isCursor ? "›" : " "}</Text>
|
|
301
306
|
<Text color={isCursor ? colors.accent : colors.text}> {line.text}</Text>
|
|
302
307
|
</Box>
|
|
@@ -304,7 +309,7 @@ function MessagesPanelInner({ session, maxHeight, isActive }: MessagesPanelProps
|
|
|
304
309
|
|
|
305
310
|
case "reasoning":
|
|
306
311
|
return (
|
|
307
|
-
<Box key={
|
|
312
|
+
<Box key={line.id} flexDirection="row" height={1} paddingLeft={1}>
|
|
308
313
|
<Text color={isCursor ? colors.accent : colors.textDim}>{isCursor ? "›" : " "}</Text>
|
|
309
314
|
<Text color={isCursor ? colors.accent : colors.accentDim}> ⚡ {line.text}</Text>
|
|
310
315
|
</Box>
|