* Render a `shell_run` (background-process) result. The status line — status, * exit code, failure message, and the run `ref` — is always shown in full so a * head/tail cap can never hide whether the command failed or timed out; only * the stdout/stderr stream bodies are capped.
(
entry: MakaPiToolEntry,
content: Extract<ToolResultContent, { kind: 'shell_run' }>,
width: number,
)
| 630 | * the stdout/stderr stream bodies are capped. |
| 631 | */ |
| 632 | function renderShellRunResult( |
| 633 | entry: MakaPiToolEntry, |
| 634 | content: Extract<ToolResultContent, { kind: 'shell_run' }>, |
| 635 | width: number, |
| 636 | ): string[] { |
| 637 | const lines: string[] = []; |
| 638 | // The command/cwd live on the result. The Bash input summary shows only the |
| 639 | // command's first line (`command.split('\n')[0]`), so skip the result-side |
| 640 | // `$ cmd` only when the input already shows the whole command — a single-line |
| 641 | // command. A multiline command, or a ref-only StopBackgroundTask input, |
| 642 | // renders the full command here so none of it is lost. The cwd is in neither |
| 643 | // input summary, so show it once here. |
| 644 | const input = entry.input; |
| 645 | const command = |
| 646 | input !== null && typeof input === 'object' |
| 647 | ? (input as { command?: unknown }).command |
| 648 | : undefined; |
| 649 | const inputShowsFullCommand = |
| 650 | typeof command === 'string' && command.trim() !== '' && !command.includes('\n'); |
| 651 | if (!inputShowsFullCommand) { |
| 652 | lines.push(...renderIndented(ansi.dim(`$ ${content.cmd}`), width, 2)); |
| 653 | } |
| 654 | lines.push(...renderIndented(ansi.dim(`cwd: ${content.cwd}`), width, 2)); |
| 655 | const settled = !isActiveShellRunStatus(content.status) && content.status !== 'completed'; |
| 656 | const parts: string[] = [content.status]; |
| 657 | if (content.exitCode !== undefined) parts.push(`exit ${content.exitCode}`); |
| 658 | if (content.failureMessage) parts.push(content.failureMessage); |
| 659 | const head = parts.join(' · '); |
| 660 | // Keep the colored status and the dim ref as separate ansi spans; nesting one |
| 661 | // inside the other would let the inner reset terminate the outer color early. |
| 662 | const statusLine = `${settled ? ansi.red(head) : ansi.dim(head)} ${ansi.dim(`(${content.ref})`)}`; |
| 663 | lines.push(...renderIndented(statusLine, width, 2)); |
| 664 | if (content.output?.mode === 'pty') { |
| 665 | const hasTerminalView = ptyTuiTerminalRows(content.output).length > 0; |
| 666 | lines.push(...renderPtyTerminalRows(content.output, width)); |
| 667 | if (!hasTerminalView && (content.status === 'failed' || content.status === 'orphaned')) { |
| 668 | lines.push(...renderIndented(ansi.dim('No terminal view available'), width, 2)); |
| 669 | } |
| 670 | } else if (content.output?.mode === 'pipes') { |
| 671 | lines.push(...renderPipeShellOutput(content.output, width)); |
| 672 | } |
| 673 | return lines; |
| 674 | } |
| 675 | |
| 676 | function renderDiffResult(diff: string, width: number): string[] { |
| 677 | // The structural parse drops the `---`/`+++` file headers the card already |
no test coverage detected