The web command row renders `title · summary` from one logged command lifecycle pair, and the two halves were written without knowing about each other: the title was the dispatched line rebuilt from `command/run` and the summary was `command/done`'s verbatim text, so every Access-chip pick read `/permission workspace-write · Permission preset: workspace-write.` — the command name twice and its argument twice. The title is now the bare command name (no `/`, no arguments — the summary already says what the command did), and a command handler's settlement text never repeats the command's own name, so `/permission` returns `preset workspace-write`. The row reads `permission · preset workspace-write`, and the TUI notice still names the preset that now applies. The log is unchanged: `command/run` keeps its structured name/args split for a richer registered row.
40 lines
1.7 KiB
TypeScript
40 lines
1.7 KiB
TypeScript
// GenericCommandCard: the default command row — a stripped-down
|
|
// GenericToolCard rendering the command name and its settlement text.
|
|
// Supplied by the chat view as the keyed commandview slot's render-site
|
|
// fallback (an unregistered command name lands here); registrants may compose
|
|
// it as a base, feeding the same owner payload through.
|
|
|
|
import { ToolRow } from './ToolRow.tsx'
|
|
import type { ToolRowState } from '../contract/tool-call-model.ts'
|
|
import type { CommandRowOwnerProps } from '../contract/slots.ts'
|
|
import { IconApiOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'
|
|
|
|
/** Node state → row state semantic (running while unsettled; outcome kind after). */
|
|
function stateOf(outcome: CommandRowOwnerProps['node']['outcome']): ToolRowState {
|
|
if (outcome === null) return 'running'
|
|
return outcome.kind === 'error' ? 'error' : 'ok'
|
|
}
|
|
|
|
export function GenericCommandCard({ node }: CommandRowOwnerProps) {
|
|
const text = node.outcome?.text
|
|
const summary = node.outcome === null
|
|
? '执行中…'
|
|
: text ?? (node.outcome.kind === 'error' ? '命令失败' : '已完成')
|
|
// Title is the bare command name: the row already reads `name · outcome`,
|
|
// and the dispatched line's own `/` and arguments only restate what the
|
|
// settlement text says (`permission · preset workspace-write`). A
|
|
// cross-window node whose run page fell out of the window has no name.
|
|
const title = node.name ?? '命令'
|
|
return (
|
|
<ToolRow
|
|
variant="others"
|
|
icon={<IconApiOutline14 size={16} />}
|
|
title={title}
|
|
summary={summary}
|
|
// Expandable only when the outcome text overflows a one-line summary.
|
|
body={text !== undefined && text.includes('\n') ? text : null}
|
|
state={stateOf(node.outcome)}
|
|
/>
|
|
)
|
|
}
|