Files
claude-code/src/utils/computerUse/toolRendering.tsx
T
claude-code-best 5b1a52b8e0 更新大量 tsx 原始文件; 已经迁移 login panel; 部分 (#121)
* style(B1-1): 格式化 ink/buddy/cli/context/screens/tasks/services/keybindings/state (43 files)

纯格式化:移除分号、React Compiler import、import 多行展开。
修复了 Box.tsx 和 ScrollBox.tsx 中无效的 global.d.ts import。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style(B1-2): 格式化 commands (79 files)

纯格式化:移除分号、React Compiler import、import 多行展开。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style(B1-3): 格式化 components/messages,permissions,mcp,sandbox,shell (104 files)

纯格式化:移除分号、React Compiler import、import 多行展开。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style(B1-4): 格式化 components/PromptInput,FeedbackSurvey,tasks,agents,skills,design-system,wizard (73 files)

纯格式化:移除分号、React Compiler import、import 多行展开。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style(B1-5): 格式化 components其余 + hooks + tools (232 files)

纯格式化:移除分号、React Compiler import、import 多行展开。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style(B1-6): 格式化 main/entrypoints/utils/moreright (21 files)

纯格式化:移除分号、React Compiler import、import 多行展开。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: 更新 README,新增 Run.ps1/TODO.md,删除 V6.md

- README.md: 大幅重写,更详细版本历史和配置示例
- Run.ps1: 新增 Windows 启动脚本
- TODO.md: 新增包完成清单
- V6.md: 删除(架构重构规划已不适用)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 修复以前的问题

* fix: 修复 login 面板的问题

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 23:24:27 +08:00

158 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import * as React from 'react'
import { MessageResponse } from '../../components/MessageResponse.js'
import { Text } from '../../ink.js'
import { truncateToWidth } from '../format.js'
import type { MCPToolResult } from '../mcpValidation.js'
type CuToolInput = Record<string, unknown> & {
coordinate?: [number, number]
start_coordinate?: [number, number]
text?: string
apps?: Array<{ displayName?: string }>
region?: [number, number, number, number]
direction?: string
amount?: number
duration?: number
}
function fmtCoord(c: [number, number] | undefined): string {
return c ? `(${c[0]}, ${c[1]})` : ''
}
const RESULT_SUMMARY: Readonly<Partial<Record<string, string>>> = {
screenshot: 'Captured',
zoom: 'Captured',
request_access: 'Access updated',
left_click: 'Clicked',
right_click: 'Clicked',
middle_click: 'Clicked',
double_click: 'Clicked',
triple_click: 'Clicked',
type: 'Typed',
key: 'Pressed',
hold_key: 'Pressed',
scroll: 'Scrolled',
left_click_drag: 'Dragged',
open_application: 'Opened',
}
/**
* Rendering overrides for `mcp__computer-use__*` tools. Spread into the MCP
* tool object in `client.ts` after the default `userFacingName`, so these win.
* Mirror of `getClaudeInChromeMCPToolOverrides`.
*/
export function getComputerUseMCPRenderingOverrides(toolName: string): {
userFacingName: () => string
renderToolUseMessage: (
input: Record<string, unknown>,
options: { verbose: boolean },
) => React.ReactNode
renderToolResultMessage: (
output: MCPToolResult,
progressMessages: unknown[],
options: { verbose: boolean },
) => React.ReactNode
} {
return {
userFacingName() {
return `Computer Use[${toolName}]`
},
// AssistantToolUseMessage.tsx contract: null hides the ENTIRE row, '' shows
// the tool name without "(args)". Every path below returns '' when there's
// nothing to show — never null.
renderToolUseMessage(input: CuToolInput) {
switch (toolName) {
case 'screenshot':
case 'left_mouse_down':
case 'left_mouse_up':
case 'cursor_position':
case 'list_granted_applications':
case 'read_clipboard':
return ''
case 'left_click':
case 'right_click':
case 'middle_click':
case 'double_click':
case 'triple_click':
case 'mouse_move':
return fmtCoord(input.coordinate)
case 'left_click_drag':
return input.start_coordinate
? `${fmtCoord(input.start_coordinate)} → ${fmtCoord(input.coordinate)}`
: `to ${fmtCoord(input.coordinate)}`
case 'type':
return typeof input.text === 'string'
? `"${truncateToWidth(input.text, 40)}"`
: ''
case 'key':
case 'hold_key':
return typeof input.text === 'string' ? input.text : ''
case 'scroll':
return [
input.direction,
input.amount && `×${input.amount}`,
input.coordinate && `at ${fmtCoord(input.coordinate)}`,
]
.filter(Boolean)
.join(' ')
case 'zoom': {
const r = input.region
return Array.isArray(r) && r.length === 4
? `[${r[0]}, ${r[1]}, ${r[2]}, ${r[3]}]`
: ''
}
case 'wait':
return typeof input.duration === 'number' ? `${input.duration}s` : ''
case 'write_clipboard':
return typeof input.text === 'string'
? `"${truncateToWidth(input.text, 40)}"`
: ''
case 'open_application':
return typeof input.bundle_id === 'string'
? String(input.bundle_id)
: ''
case 'request_access': {
const apps = input.apps
if (!Array.isArray(apps)) return ''
const names = apps
.map(a => (typeof a?.displayName === 'string' ? a.displayName : ''))
.filter(Boolean)
return names.join(', ')
}
case 'computer_batch': {
const actions = input.actions
return Array.isArray(actions) ? `${actions.length} actions` : ''
}
default:
return ''
}
},
renderToolResultMessage(output, _progress, { verbose }) {
if (verbose || typeof output !== 'object' || output === null) return null
// Non-verbose: one-line dim summary, like Chrome's pattern.
const summary = RESULT_SUMMARY[toolName]
if (!summary) return null
return (
<MessageResponse height={1}>
<Text dimColor>{summary}</Text>
</MessageResponse>
)
},
}
}