Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

86 lines
2.8 KiB
TypeScript

import { useMemo, useState, type JSX } from "react";
import { AgentToolScrollArea } from "../AgentToolScrollArea";
const MAX_OUTPUT_LINES = 200;
export function AgentTerminalBlock({
command,
stdout,
stderr,
status
}: {
command: string | null;
stdout: string;
stderr: string;
exitCode: number | null;
durationMs: number | null;
status: "running" | "completed" | "failed" | "unknown";
}): JSX.Element | null {
"use memo";
const [expanded, setExpanded] = useState(false);
const outputText = useMemo(
() => [stdout, stderr].filter(Boolean).join("\n"),
[stdout, stderr]
);
const outputLines = useMemo(
() => (outputText ? outputText.split("\n") : []),
[outputText]
);
const truncated = !expanded && outputLines.length > MAX_OUTPUT_LINES;
const visibleOutput = truncated
? outputLines.slice(0, MAX_OUTPUT_LINES).join("\n")
: outputText;
const failed = status === "failed";
const hasOutput = Boolean(visibleOutput);
const disclosureButton =
outputLines.length > MAX_OUTPUT_LINES ? (
<button
type="button"
className="mt-2 flex w-fit items-center border-0 bg-transparent p-0 text-left text-[11px] font-medium text-[var(--tutti-purple)] transition-colors hover:underline focus-visible:underline focus-visible:outline-none"
onClick={() => setExpanded((value) => !value)}
>
{expanded
? "Collapse output"
: `Show full output (${outputLines.length} lines)`}
</button>
) : null;
return (
<div className="workspace-agents-status-panel__detail-tool-terminal overflow-hidden rounded-[8px] border border-[var(--line-2)] bg-[var(--background-panel)]">
{command ? (
<div
className={`flex min-w-0 items-center gap-3 px-3 text-[11px] text-[var(--text-secondary)] ${
hasOutput
? "border-b border-[var(--line-2)] bg-[var(--transparency-block)] py-1.5"
: "bg-[var(--transparency-block)] py-2"
}`}
data-agent-terminal-command-row="true"
>
<span className="shrink-0 font-semibold text-[var(--tutti-purple)]">
$
</span>
<span
className="min-w-0 flex-1 whitespace-pre-wrap [overflow-wrap:anywhere]"
data-agent-terminal-command="true"
>
{command}
</span>
</div>
) : null}
{hasOutput ? (
<AgentToolScrollArea
maxHeightClassName="max-h-[160px]"
viewportClassName={`px-3 py-2 text-[11px] leading-5 ${
failed ? "text-[var(--state-danger)]" : "text-[var(--text-primary)]"
}`}
>
<pre className="m-0 min-w-0 max-w-full whitespace-pre-wrap [overflow-wrap:anywhere]">
<code>{visibleOutput}</code>
</pre>
{disclosureButton}
</AgentToolScrollArea>
) : null}
</div>
);
}