-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat(kimi-code): two-line collapsed tool cards with width-aware headers #3539
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b2d1ce8
b090435
6870f34
2f1ee91
44d8107
a332a8e
987e4c3
261f520
ac68756
779b39d
7f3a38f
c24562b
b5c0edf
481944d
8c8a170
261a440
341ebbb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@moonshot-ai/kimi-code": patch | ||
| --- | ||
|
|
||
| Collapse finished tool calls in the transcript to a header plus one marked outcome row: short output is shown whole, hidden output is counted (`N more lines`, `+N more`) and revealed by `Ctrl+O`, which the footer advertises while it is available. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,6 +34,9 @@ import { | |
| usagePercentFromRatio, | ||
| } from '#/utils/usage/usage-format'; | ||
|
|
||
| /** What the footer's fixed ctrl+o hint offers: expand collapsed tool output, or collapse it again. */ | ||
| export type ToolOutputExpandHint = 'expand' | 'collapse'; | ||
|
|
||
| const DEFAULT_STATUS_LINE_ITEMS = ['mode', 'goal', 'model', 'tasks', 'cwd', 'git'] as const; | ||
|
|
||
| const MAX_CWD_SEGMENTS = 3; | ||
|
|
@@ -196,6 +199,7 @@ export class FooterComponent implements Component { | |
| private gitCacheWorkDir: string; | ||
| private transientHint: string | null = null; | ||
| private warningHint: string | null = null; | ||
| private expandHintProvider: (() => ToolOutputExpandHint | null) | null = null; | ||
| private goalSnapshotKey: string | null = null; | ||
| private goalObservedAtMs = Date.now(); | ||
| private goalTimer: ReturnType<typeof setInterval> | null = null; | ||
|
|
@@ -271,6 +275,16 @@ export class FooterComponent implements Component { | |
| this.warningHint = hint; | ||
| } | ||
|
|
||
| /** | ||
| * Source of the fixed `ctrl+o expand` / `ctrl+o collapse` hint on line 1: | ||
| * `expand` while the transcript holds collapsed tool output ctrl+o can | ||
| * reveal, `collapse` once it is shown, `null` when there is nothing to | ||
| * toggle. Read on every render so it tracks the transcript exactly. | ||
| */ | ||
| setExpandHintProvider(provider: () => ToolOutputExpandHint | null): void { | ||
| this.expandHintProvider = provider; | ||
| } | ||
|
|
||
| /** | ||
| * Sync both background-task badges with live counts. Each non-zero | ||
| * count produces its own bracketed badge on line 1; zeros hide them | ||
|
|
@@ -311,26 +325,24 @@ export class FooterComponent implements Component { | |
| const leftLine = left.join(' '); | ||
| const leftWidth = visibleWidth(leftLine); | ||
|
|
||
| // Rotating hint tips stay on the right unless they were given an | ||
| // inline slot in items (rendered above at their configured position) | ||
| // or the user dropped 'tips' from items. | ||
| let tipText = ''; | ||
| // The right side holds the fixed ctrl+o hint (while the transcript has | ||
| // tool output to expand or collapse) and the rotating tips, unless the | ||
| // tips were given an inline slot in items or dropped from items. The | ||
| // hint never rotates and wins over a tip that no longer fits. | ||
| const tipsInline = order.includes('tips'); | ||
| const showTips = !tipsInline && (configured === null || configured.includes('tips')); | ||
| const tipCandidates: string[] = []; | ||
| if (showTips) { | ||
| const { primary, pair } = tipsForIndex(currentTipIndex()); | ||
| const gap = 2; | ||
| const remaining = Math.max(0, width - leftWidth - gap); | ||
| if (pair && visibleWidth(pair) <= remaining) { | ||
| tipText = pair; | ||
| } else if (primary && visibleWidth(primary) <= remaining) { | ||
| tipText = primary; | ||
| } | ||
| if (pair) tipCandidates.push(pair); | ||
| if (primary) tipCandidates.push(primary); | ||
| } | ||
| const remaining = Math.max(0, width - leftWidth - 2); | ||
| const rightText = this.buildRightText(tipCandidates, remaining, colors); | ||
|
Comment on lines
+340
to
+341
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Useful? React with 👍 / 👎. |
||
|
|
||
| if (tipText) { | ||
| const pad = width - leftWidth - visibleWidth(tipText); | ||
| line1 = leftLine + ' '.repeat(Math.max(0, pad)) + chalk.hex(colors.textMuted)(tipText); | ||
| if (rightText.length > 0) { | ||
| const pad = width - leftWidth - visibleWidth(rightText); | ||
| line1 = leftLine + ' '.repeat(Math.max(0, pad)) + rightText; | ||
| } else if (leftWidth <= width) { | ||
| line1 = leftLine; | ||
| } else { | ||
|
|
@@ -358,13 +370,43 @@ export class FooterComponent implements Component { | |
| ' '.repeat(pad) + | ||
| chalk.hex(colors.text)(contextText); | ||
| } else { | ||
| const leftPad = Math.max(0, width - contextWidth); | ||
| line2 = ' '.repeat(leftPad) + chalk.hex(colors.text)(contextText); | ||
| // A status_line.command owns line 1 outright, so the ctrl+o hint moves | ||
| // down here; the transient and warning hints above take precedence. | ||
| const shortcut = customLine !== null ? this.expandShortcut() : null; | ||
| const left = | ||
| shortcut !== null && visibleWidth(shortcut) + 1 + contextWidth <= width | ||
| ? chalk.hex(colors.textDim)(shortcut) | ||
| : ''; | ||
| const leftPad = Math.max(0, width - visibleWidth(left) - contextWidth); | ||
| line2 = left + ' '.repeat(leftPad) + chalk.hex(colors.text)(contextText); | ||
| } | ||
|
|
||
| return [truncateToWidth(line1, width), truncateToWidth(line2, width)]; | ||
| } | ||
|
|
||
| /** The fixed ctrl+o hint plus the first rotating tip that still fits beside it. */ | ||
| /** `ctrl+o expand` / `ctrl+o collapse`, or null when there is nothing to toggle. */ | ||
| private expandShortcut(): string | null { | ||
| const hint = this.expandHintProvider?.() ?? null; | ||
| return hint === null ? null : `ctrl+o ${hint}`; | ||
| } | ||
|
|
||
| private buildRightText(tips: readonly string[], remaining: number, colors: ColorPalette): string { | ||
| const shortcut = this.expandShortcut(); | ||
| if (shortcut === null) { | ||
| const tip = tips.find((candidate) => visibleWidth(candidate) <= remaining); | ||
| return tip === undefined ? '' : chalk.hex(colors.textMuted)(tip); | ||
| } | ||
| for (const tip of tips) { | ||
| if (visibleWidth(`${shortcut}${TIP_SEPARATOR}${tip}`) <= remaining) { | ||
| return ( | ||
| chalk.hex(colors.textDim)(shortcut) + chalk.hex(colors.textMuted)(`${TIP_SEPARATOR}${tip}`) | ||
| ); | ||
| } | ||
| } | ||
| return visibleWidth(shortcut) <= remaining ? chalk.hex(colors.textDim)(shortcut) : ''; | ||
| } | ||
|
|
||
| /** | ||
| * Rendered pieces per status-line slot. Empty-content slots (e.g. no goal, | ||
| * outside a git repo) yield an empty list so composition just skips them. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.