Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/cli/src/ui/components/GoalStatusPanel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ describe('buildGoalStatusLineForTests', () => {
})
expect(out).not.toBeNull()
expect(out!.label).toBe('scheduled')
expect(out!.line).toContain(' 2/5')
expect(out!.line).toContain('下轮 1s')
expect(out!.line).toContain('turn 2/5')
expect(out!.line).toContain('next 1s')
expect(out!.line).toContain('实现一个非常长')
})

Expand Down
12 changes: 8 additions & 4 deletions apps/cli/src/ui/components/GoalStatusPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ export function buildGoalStatusLineForTests(args: {

const progress =
goal.schedule.kind === 'interval'
? ` ${goal.activeRun?.turnCount ?? 0}/${goal.loop.maxIterations}`
? `turn ${goal.activeRun?.turnCount ?? 0}/${goal.loop.maxIterations}`
: goal.schedule.kind === 'once'
? ` ${goal.activeRun?.turnCount ?? 0}`
? `turn ${goal.activeRun?.turnCount ?? 0}`
: ''
const countdown = formatCountdown(
goal.schedule.kind === 'interval' ? goal.schedule.nextRunAt : null,
Expand All @@ -60,7 +60,7 @@ export function buildGoalStatusLineForTests(args: {
const parts = [
statusLabel(goal),
progress,
countdown ? `下轮 ${countdown}` : '',
countdown ? `next ${countdown}` : '',
].filter(Boolean)
const suffix = parts.length > 0 ? ` · ${parts.join(' · ')}` : ''
const line = `${truncate(goal.objective, Math.max(10, maxWidth - suffix.length))}${suffix}`
Expand Down Expand Up @@ -89,7 +89,11 @@ export function GoalStatusPanel({
const isRunning = goal!.status === 'running'
const glyph = isRunning ? '■' : '⏱'
const color =
goal!.status === 'awaiting_approval' ? theme.warning : theme.kode
goal!.status === 'running'
? theme.warning
: goal!.status === 'awaiting_approval'
? theme.warning
: theme.kode

return (
<Box
Expand Down
4 changes: 2 additions & 2 deletions apps/cli/src/ui/components/Logo.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ describe('Logo', () => {

expect(output).toContain(firstLogoPrefix)
expect(output).not.toContain(productNameFallback)
expect(output).toContain('/help')
expect(output).toContain('/config')
expect(output).toContain('MCP Servers')
expect(output).toContain('codegraph')
expect(output).not.toMatch(/(?:\n\s*){4,}/)
Expand Down Expand Up @@ -180,7 +180,7 @@ describe('Logo', () => {

expect(output).toContain(productNameFallback)
expect(output).not.toContain(firstLogoPrefix)
expect(output).toContain('/help')
expect(output).toContain('/config')
expect(output).toContain('MCP Servers:')
expect(output).toContain('codegraph')
expect(output.split(/\r?\n/).filter(Boolean)).toHaveLength(3)
Expand Down
37 changes: 21 additions & 16 deletions apps/cli/src/ui/components/Logo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ function LogoQuickActions({
columns >= 55
? commands
: columns >= 42
? commands.slice(1, 3)
: commands.slice(1, 2)
? commands.slice(0, 2)
: commands.slice(0, 1)

return (
<Text wrap="truncate-end">
Expand Down Expand Up @@ -168,22 +168,24 @@ export function Logo({
)}

{showMcpDetails ? (
<Text dimColor wrap="truncate-end">
<Text color={theme.secondaryText} wrap="truncate-end">
MCP Servers:{' '}
{mcpClients.length === 0 ? (
'none'
) : (
<>
{connected.map((c, index) => (
<React.Fragment key={c.name}>
{index > 0 ? <Text dimColor>, </Text> : null}
{index > 0 ? (
<Text color={theme.secondaryText}>, </Text>
) : null}
<Text color={theme.success}>{c.name}</Text>
</React.Fragment>
))}
{failed.map((c, index) => (
<React.Fragment key={c.name}>
{connected.length > 0 || index > 0 ? (
<Text dimColor>, </Text>
<Text color={theme.secondaryText}>, </Text>
) : null}
<Text color={theme.error}>{c.name}</Text>
</React.Fragment>
Expand All @@ -192,7 +194,7 @@ export function Logo({
)}
</Text>
) : rows >= SHORT_HELP_MIN_ROWS ? (
<Text dimColor wrap="truncate-end">
<Text color={theme.secondaryText} wrap="truncate-end">
MCP: {connected.length} connected
{failed.length > 0 ? `, ${failed.length} failed` : ''}
</Text>
Expand Down Expand Up @@ -237,14 +239,17 @@ export function Logo({

{/* MCP Servers section */}
<Box flexDirection="column" marginTop={isCompact ? 1 : 2}>
<Text dimColor>
<Text color={theme.secondaryText}>
{isCompact
? `MCP Servers ${separator}`
: `── MCP Servers ${separator}`}
</Text>
<Box marginTop={isCompact ? 0 : 1} paddingLeft={isCompact ? 1 : 3}>
{mcpClients.length === 0 ? (
<Text dimColor wrap={isCompact ? 'truncate-end' : 'wrap'}>
<Text
color={theme.secondaryText}
wrap={isCompact ? 'truncate-end' : 'wrap'}
>
{isCompact
? 'No servers configured'
: 'No servers configured - run: kode mcp add <name>'}
Expand All @@ -253,14 +258,16 @@ export function Logo({
<Text wrap="truncate-end">
{connected.map((c, index) => (
<React.Fragment key={c.name}>
{index > 0 ? <Text dimColor>, </Text> : null}
{index > 0 ? (
<Text color={theme.secondaryText}>, </Text>
) : null}
<Text color={theme.success}>{c.name}</Text>
</React.Fragment>
))}
{failed.map((c, index) => (
<React.Fragment key={c.name}>
{connected.length > 0 || index > 0 ? (
<Text dimColor>, </Text>
<Text color={theme.secondaryText}>, </Text>
) : null}
<Text color={theme.error}>{c.name}</Text>
</React.Fragment>
Expand All @@ -269,15 +276,13 @@ export function Logo({
) : (
<>
{connected.map(c => (
<Text key={c.name}>
<Text color={theme.success}>{c.name}</Text>
<Text dimColor> </Text>
<Text key={c.name} color={theme.success}>
{c.name}
</Text>
))}
{failed.map(c => (
<Text key={c.name}>
<Text color={theme.error}>{c.name}</Text>
<Text dimColor> </Text>
<Text key={c.name} color={theme.error}>
{c.name}
</Text>
))}
</>
Expand Down
4 changes: 2 additions & 2 deletions apps/cli/src/ui/components/ModeIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function ModeIndicator({
<Text color={indicator.color} wrap="truncate-end">
{indicator.mainText}
{indicator.shortcutHintText ? (
<Text dimColor>{indicator.shortcutHintText}</Text>
<Text color={theme.secondaryText}>{indicator.shortcutHintText}</Text>
) : null}
</Text>
{showTransitionCount && (
Expand Down Expand Up @@ -102,7 +102,7 @@ export function CompactModeIndicator() {
return (
<Text color={indicator.color} wrap="truncate-end">
{indicator.mainText}
<Text dimColor>{indicator.shortcutHintText}</Text>
<Text color={theme.secondaryText}>{indicator.shortcutHintText}</Text>
</Text>
)
}
11 changes: 11 additions & 0 deletions apps/cli/src/ui/components/ProjectOnboarding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,17 @@ export default function ProjectOnboarding({
)
}

items.unshift(
<React.Fragment key="config">
<OrderedList.Item>
<Text color={theme.secondaryText}>
Run <Text color={theme.text}>/config</Text> to set up
models, permissions, and MCP.
</Text>
</OrderedList.Item>
</React.Fragment>,
)

items.push(
<React.Fragment key="questions">
<OrderedList.Item>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ describe('__getPendingPromptLinesForTests', () => {
maxLinesPerMessage: 2,
})

expect(lines[0]).toBe('Next')
expect(lines.some(line => line.includes('›'))).toBe(true)
expect(lines.some(line => line.trim() === '…')).toBe(true)
})
Expand All @@ -26,7 +27,8 @@ describe('__getPendingPromptLinesForTests', () => {
maxMessages: 2,
})

expect(lines[0]).toContain('earlier')
expect(lines[0]).toContain('Next')
expect(lines.some(line => line.includes('earlier'))).toBe(true)
expect(lines.join('\n')).toContain('c')
expect(lines.join('\n')).toContain('d')
expect(lines.join('\n')).not.toContain('› a')
Expand Down
7 changes: 7 additions & 0 deletions apps/cli/src/ui/components/PromptInput/PendingPrompts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const FIRST_LINE_PREFIX = ' › '
const WRAPPED_LINE_PREFIX = ' '
const MORE_PENDING_PREFIX = ' … '
const ELLIPSIS_LINE = ' …'
export const PENDING_PROMPTS_HEADER = 'Next · sends after this turn'
export const PENDING_PROMPTS_HEADER_SHORT = 'Next'

export function __getPendingPromptLinesForTests(args: {
pendingPrompts: string[]
Expand Down Expand Up @@ -59,6 +61,11 @@ export function __getPendingPromptLinesForTests(args: {
}
}

if (lines.length === 0) return []

lines.unshift(
safeWidth >= 36 ? PENDING_PROMPTS_HEADER : PENDING_PROMPTS_HEADER_SHORT,
)
return lines
}

Expand Down
Loading