fix(tui): support expanding bash command while running (#1004)

Render the command in the in-flight Bash card body so it is visible while the command runs, and let Ctrl+O expand the full command before the result arrives.
This commit is contained in:
liruifengv 2026-06-23 15:28:49 +08:00 committed by GitHub
parent ea1b33b674
commit d70c3a8c01
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 63 additions and 0 deletions

View file

@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": patch
---
Show the command in running Bash tool cards and allow expanding it with Ctrl+O before the result arrives.

View file

@ -1852,6 +1852,20 @@ export class ToolCallComponent extends Container {
for (const line of lines) {
this.addChild(new Text(line, 2, 0));
}
} else if (name === 'Bash' && this.result === undefined) {
// While a long-running Bash call is in-flight (args finalized, no result
// yet), surface its command in the body so the user can see what is
// running and expand it with ctrl+o. Once the result lands, buildContent's
// shellExecutionResultRenderer takes over command rendering.
const command = str(this.toolCall.args['command']);
if (command.length === 0) return;
this.addChild(
new ShellExecutionComponent({
command,
showCommand: true,
commandPreviewLines: this.expanded ? undefined : COMMAND_PREVIEW_LINES,
}),
);
}
}

View file

@ -214,6 +214,50 @@ describe('ToolCallComponent', () => {
expect(out).not.toContain('streamed-only');
});
describe('in-flight Bash command preview (args finalized, no result yet)', () => {
const longCommand = Array.from({ length: 15 }, (_, i) => `echo step${String(i + 1)}`).join(
'\n',
);
it('shows the truncated command while running and reveals the rest when expanded', () => {
const component = new ToolCallComponent(
{ id: 'call_bash_running', name: 'Bash', args: { command: longCommand } },
undefined,
);
const collapsed = strip(component.render(100).join('\n'));
expect(collapsed).toContain('Using Bash');
expect(collapsed).toContain('echo step1');
expect(collapsed).toContain('echo step10');
expect(collapsed).not.toContain('echo step11');
component.setExpanded(true);
const expanded = strip(component.render(100).join('\n'));
expect(expanded).toContain('echo step11');
expect(expanded).toContain('echo step15');
});
it('yields command rendering to the result renderer once the result lands', () => {
const component = new ToolCallComponent(
{ id: 'call_bash_done', name: 'Bash', args: { command: longCommand } },
undefined,
);
// Sanity: while running, the in-flight preview shows the command.
expect(strip(component.render(100).join('\n'))).toContain('$ echo step1');
component.setResult({ tool_call_id: 'call_bash_done', output: 'done', is_error: false });
// Collapsed result view delegates to shellExecutionResultRenderer, which
// hides the command — so the in-flight buildCallPreview preview must be
// gone, otherwise the command would render twice when expanded.
const out = strip(component.render(100).join('\n'));
expect(out).toContain('Used Bash');
expect(out).not.toContain('$ echo step1');
});
});
it('hides tool output bodies that start with a <system tag', () => {
const reminderOutput =
'<system-reminder>\nThe task tools have not been used recently.\n</system-reminder>';