mirror of
http://10.0.2.1:3031/sauer/claude-code.git
synced 2026-06-30 15:36:57 +10:00
125 lines
17 KiB
TypeScript
125 lines
17 KiB
TypeScript
|
|
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>;
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIk1lc3NhZ2VSZXNwb25zZSIsIlRleHQiLCJ0cnVuY2F0ZVRvV2lkdGgiLCJNQ1BUb29sUmVzdWx0IiwiQ3VUb29sSW5wdXQiLCJSZWNvcmQiLCJjb29yZGluYXRlIiwic3RhcnRfY29vcmRpbmF0ZSIsInRleHQiLCJhcHBzIiwiQXJyYXkiLCJkaXNwbGF5TmFtZSIsInJlZ2lvbiIsImRpcmVjdGlvbiIsImFtb3VudCIsImR1cmF0aW9uIiwiZm10Q29vcmQiLCJjIiwiUkVTVUxUX1NVTU1BUlkiLCJSZWFkb25seSIsIlBhcnRpYWwiLCJzY3JlZW5zaG90Iiwiem9vbSIsInJlcXVlc3RfYWNjZXNzIiwibGVmdF9jbGljayIsInJpZ2h0X2NsaWNrIiwibWlkZGxlX2NsaWNrIiwiZG91YmxlX2NsaWNrIiwidHJpcGxlX2NsaWNrIiwidHlwZSIsImtleSIsImhvbGRfa2V5Iiwic2Nyb2xsIiwibGVmdF9jbGlja19kcmFnIiwib3Blbl9hcHBsaWNhdGlvbiIsImdldENvbXB1dGVyVXNlTUNQUmVuZGVyaW5nT3ZlcnJpZGVzIiwidG9vbE5hbWUiLCJ1c2VyRmFjaW5nTmFtZSIsInJlbmRlclRvb2xVc2VNZXNzYWdlIiwiaW5wdXQiLCJvcHRpb25zIiwidmVyYm9zZSIsIlJlYWN0Tm9kZSIsInJlbmRlclRvb2xSZXN1bHRNZXNzYWdlIiwib3V0cHV0IiwicHJvZ3Jlc3NNZXNzYWdlcyIsImZpbHRlciIsIkJvb2xlYW4iLCJqb2luIiwiciIsImlzQXJyYXkiLCJsZW5ndGgiLCJidW5kbGVfaWQiLCJTdHJpbmciLCJuYW1lcyIsIm1hcCIsImEiLCJhY3Rpb25zIiwiX3Byb2dyZXNzIiwic3VtbWFyeSJdLCJzb3VyY2VzIjpbInRvb2xSZW5kZXJpbmcudHN4Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgTWVzc2FnZVJlc3BvbnNlIH0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy9NZXNzYWdlUmVzcG9uc2UuanMnXG5pbXBvcnQgeyBUZXh0IH0gZnJvbSAnLi4vLi4vaW5rLmpzJ1xuaW1wb3J0IHsgdHJ1bmNhdGVUb1dpZHRoIH0gZnJvbSAnLi4vZm9ybWF0LmpzJ1xuaW1wb3J0IHR5cGUgeyBNQ1BUb29sUmVzdWx0IH0gZnJvbSAnLi4vbWNwVmFsaWRhdGlvbi5qcydcblxudHlwZSBDdVRvb2xJbnB1dCA9IFJlY29yZDxzdHJpbmcsIHVua25vd24+ICYge1xuICBjb29yZGluYXRlPzogW251bWJlciwgbnVtYmVyXVxuICBzdGFydF9jb29yZGluYXRlPzogW251bWJlciwgbnVtYmVyXVxuICB0ZXh0Pzogc3RyaW5nXG4gIGFwcHM/OiBBcnJheTx7IGRpc3BsYXlOYW1lPzogc3RyaW5nIH0+XG4gIHJlZ2lvbj86IFtudW1iZXIsIG51bWJlciwgbnVtYmVyLCBudW1iZXJdXG4gIGRpcmVjdGlvbj86IHN0cmluZ1xuICBhbW91bnQ/OiBudW1iZXJcbiAgZHVyYXRpb24/OiBudW1iZXJcbn1cblxuZnVuY3Rpb24gZm10Q29vcmQoYzogW251bWJlciwgbnVtYmVyXSB8IHVuZGVmaW5lZCk6IHN0cmluZyB7XG4gIHJldHVybiBjID8gYCgke2NbMF19LCAke2NbMV19KWAgOiAnJ1xufVxuXG5jb25zdCBSRVNVTFRfU1VNTUFSWTogUmVhZG9ubHk8UGFydGlhbDxSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+Pj4gPSB7XG4gIHNjcmVlbnNob3Q6ICdDYXB0dXJlZCcsXG4gIHpvb206ICdDYXB0dXJlZCcsXG4gIHJlcXVlc3RfYWNjZXNzOiAnQWNjZXNzIHVwZGF0ZWQnLFxuICBsZWZ0X2NsaWNrOiAnQ2xpY2tlZCcsXG4gIHJpZ2h0X2NsaWNrOiAnQ2xpY2tlZCcsXG4gIG1pZGRsZV9jbGljazogJ0NsaWNrZWQnLFxuICBkb3VibGVfY2xpY2s6ICdDbGlja2VkJyxcbiAgdHJpcGxlX2NsaWNrOiAnQ2xpY2tlZCcsXG4gIHR5cGU6ICdUeXBlZCcsXG4gIGtleTogJ1ByZXNzZWQnLFxuICBob2xkX2tleTogJ1ByZXNzZWQnLFxuICBzY3JvbGw6ICdTY3JvbGxlZCcsXG4gIGxlZnRfY2xpY2tfZHJhZzogJ0RyYWdnZWQnLFxuICBvcGVuX2FwcGxpY2F0aW9uOiAnT3BlbmVkJyxcbn1cblxuLyoqXG4gKiBSZW5kZXJpbmcgb3ZlcnJpZGVzIGZvciBgbWNwX19jb21wdXRlci11c2VfXypgIHRvb2xzLiBTcHJlYWQgaW50byB0aGUgTUNQXG4gKiB0b29sIG9iamVjdCBpbiBgY2xpZW50LnRzYCBhZnRlciB0aGUgZGVmYXVsdCBgdXNlckZhY2luZ05hbWVgLCBzbyB0aGVzZSB3aW4uXG4gKiBNaXJyb3Igb2YgYGdldENsYXVkZUluQ2hyb21lTUNQVG9vbE92ZXJyaWRlc2AuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRDb21wdXRlclVzZU1DUFJlbmRlcmluZ092ZXJyaWRlcyh0b29sTmFtZTogc3RyaW5nKToge1xuICB1c2VyRmFjaW5nTmFtZTogKCkgPT4gc3RyaW5nXG4gIHJlbmRlclRvb2xVc2VNZXNzYWdlOiAoXG4gICAgaW5wdXQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICAgIG9wdGlvbnM6IHsgdmVyYm9zZTogYm9vbGVhbiB9LFxuICApID0+IFJlYWN0LlJlYWN0Tm9kZVxuICByZW5kZXJUb29sUmVzdWx0TWVzc2FnZTogKFxuICAgIG91dHB1dDogTUNQVG9vbFJlc3VsdCxcbiAgICBwcm9ncmVzc01lc3NhZ2VzOiB1bmtub3duW10sXG4gICAgb3B0aW9uczogeyB2ZXJib3NlOiBib29sZWFuIH0sXG4gICkgPT4gUmVhY3QuUmVhY3ROb2RlXG59IHtcbiAgcmV0dXJuIHtcbiAgICB1c2VyRmFjaW5nTmFtZSgpIHtcbiAgICAgIHJldHVybiBgQ29tcHV0ZXIgVXNlWyR7dG9vbE5hbWV9XWBcbiAgICB9LFxuXG4gICAgLy8gQXNzaXN0YW50VG9vbFVzZU1lc3NhZ2UudHN4IGNvbnRyYWN0OiBudWxsIGhpZGVzIHRoZSBFTlRJUkUgcm93LCAnJyBzaG93c1xuICAgIC8vIHRoZSB0b29sIG5hbWUgd2l0aG91dCBcIihhcmdzKVwiLiBFdmVyeSBwYXRoIGJlbG93IHJldHVybnMgJycgd2hlbiB0aGVyZSdzXG4gICAgLy8gbm90aGluZyB0byBzaG93IOKAlCBuZXZlciBudWxsLlxuICAgIHJlbmRlclRvb2xVc2VNZXNzYWdlKGlucHV0OiBDdVRvb2xJbnB1dCkge1xuICAgICAgc3dpdGNoICh0b29sTmFtZSkge1xuICAgICAgICBjYXNlICdzY3JlZW5zaG90JzpcbiAgICAgICAgY2FzZSAnbGVmdF9tb3VzZV9kb3duJzpcbiAgICAgICAgY2FzZSAnbGVmdF9tb3VzZV91cCc6XG4gICAgICAgIGNhc2UgJ2N1cnNvcl9wb3NpdGlvbic6XG4gICAgICAgIGNhc2UgJ2xpc3RfZ3JhbnRlZF9
|