mirror of
http://10.0.2.1:3031/sauer/claude-code.git
synced 2026-06-30 19:16:58 +10:00
185 lines
25 KiB
TypeScript
185 lines
25 KiB
TypeScript
|
|
import { c as _c } from "react/compiler-runtime";
|
||
|
|
import type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/index.mjs';
|
||
|
|
import * as React from 'react';
|
||
|
|
import { KeyboardShortcutHint } from '../../components/design-system/KeyboardShortcutHint.js';
|
||
|
|
import { FallbackToolUseErrorMessage } from '../../components/FallbackToolUseErrorMessage.js';
|
||
|
|
import { MessageResponse } from '../../components/MessageResponse.js';
|
||
|
|
import { ShellProgressMessage } from '../../components/shell/ShellProgressMessage.js';
|
||
|
|
import { Box, Text } from '../../ink.js';
|
||
|
|
import { useKeybinding } from '../../keybindings/useKeybinding.js';
|
||
|
|
import { useShortcutDisplay } from '../../keybindings/useShortcutDisplay.js';
|
||
|
|
import { useAppStateStore, useSetAppState } from '../../state/AppState.js';
|
||
|
|
import type { Tool } from '../../Tool.js';
|
||
|
|
import { backgroundAll } from '../../tasks/LocalShellTask/LocalShellTask.js';
|
||
|
|
import type { ProgressMessage } from '../../types/message.js';
|
||
|
|
import { env } from '../../utils/env.js';
|
||
|
|
import { isEnvTruthy } from '../../utils/envUtils.js';
|
||
|
|
import { getDisplayPath } from '../../utils/file.js';
|
||
|
|
import { isFullscreenEnvEnabled } from '../../utils/fullscreen.js';
|
||
|
|
import type { ThemeName } from '../../utils/theme.js';
|
||
|
|
import type { BashProgress, BashToolInput, Out } from './BashTool.js';
|
||
|
|
import BashToolResultMessage from './BashToolResultMessage.js';
|
||
|
|
import { extractBashCommentLabel } from './commentLabel.js';
|
||
|
|
import { parseSedEditCommand } from './sedEditParser.js';
|
||
|
|
|
||
|
|
// Constants for command display
|
||
|
|
const MAX_COMMAND_DISPLAY_LINES = 2;
|
||
|
|
const MAX_COMMAND_DISPLAY_CHARS = 160;
|
||
|
|
|
||
|
|
// Simple component to show background hint and handle ctrl+b
|
||
|
|
// When ctrl+b is pressed, backgrounds ALL running foreground commands
|
||
|
|
export function BackgroundHint(t0) {
|
||
|
|
const $ = _c(9);
|
||
|
|
let t1;
|
||
|
|
if ($[0] !== t0) {
|
||
|
|
t1 = t0 === undefined ? {} : t0;
|
||
|
|
$[0] = t0;
|
||
|
|
$[1] = t1;
|
||
|
|
} else {
|
||
|
|
t1 = $[1];
|
||
|
|
}
|
||
|
|
const {
|
||
|
|
onBackground
|
||
|
|
} = t1;
|
||
|
|
const store = useAppStateStore();
|
||
|
|
const setAppState = useSetAppState();
|
||
|
|
let t2;
|
||
|
|
if ($[2] !== onBackground || $[3] !== setAppState || $[4] !== store) {
|
||
|
|
t2 = () => {
|
||
|
|
backgroundAll(() => store.getState(), setAppState);
|
||
|
|
onBackground?.();
|
||
|
|
};
|
||
|
|
$[2] = onBackground;
|
||
|
|
$[3] = setAppState;
|
||
|
|
$[4] = store;
|
||
|
|
$[5] = t2;
|
||
|
|
} else {
|
||
|
|
t2 = $[5];
|
||
|
|
}
|
||
|
|
const handleBackground = t2;
|
||
|
|
let t3;
|
||
|
|
if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
|
||
|
|
t3 = {
|
||
|
|
context: "Task"
|
||
|
|
};
|
||
|
|
$[6] = t3;
|
||
|
|
} else {
|
||
|
|
t3 = $[6];
|
||
|
|
}
|
||
|
|
useKeybinding("task:background", handleBackground, t3);
|
||
|
|
const baseShortcut = useShortcutDisplay("task:background", "Task", "ctrl+b");
|
||
|
|
const shortcut = env.terminal === "tmux" && baseShortcut === "ctrl+b" ? "ctrl+b ctrl+b (twice)" : baseShortcut;
|
||
|
|
if (isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_BACKGROUND_TASKS)) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
let t4;
|
||
|
|
if ($[7] !== shortcut) {
|
||
|
|
t4 = <Box paddingLeft={5}><Text dimColor={true}><KeyboardShortcutHint shortcut={shortcut} action="run in background" parens={true} /></Text></Box>;
|
||
|
|
$[7] = shortcut;
|
||
|
|
$[8] = t4;
|
||
|
|
} else {
|
||
|
|
t4 = $[8];
|
||
|
|
}
|
||
|
|
return t4;
|
||
|
|
}
|
||
|
|
export function renderToolUseMessage(input: Partial<BashToolInput>, {
|
||
|
|
verbose,
|
||
|
|
theme: _theme
|
||
|
|
}: {
|
||
|
|
verbose: boolean;
|
||
|
|
theme: ThemeName;
|
||
|
|
}): React.ReactNode {
|
||
|
|
const {
|
||
|
|
command
|
||
|
|
} = input;
|
||
|
|
if (!command) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Render sed in-place edits like file edits (show file path only)
|
||
|
|
const sedInfo = parseSedEditCommand(command);
|
||
|
|
if (sedInfo) {
|
||
|
|
return verbose ? sedInfo.filePath : getDisplayPath(sedInfo.filePath);
|
||
|
|
}
|
||
|
|
if (!verbose) {
|
||
|
|
const lines = command.split('\n');
|
||
|
|
if (isFullscreenEnvEnabled()) {
|
||
|
|
const label = extractBashCommentLabel(command);
|
||
|
|
if (label) {
|
||
|
|
return label.length > MAX_COMMAND_DISPLAY_CHARS ? label.slice(0, MAX_COMMAND_DISPLAY_CHARS) + '…' : label;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
const needsLineTruncation = lines.length > MAX_COMMAND_DISPLAY_LINES;
|
||
|
|
const needsCharTruncation = command.length > MAX_COMMAND_DISPLAY_CHARS;
|
||
|
|
if (needsLineTruncation || needsCharTruncation) {
|
||
|
|
let truncated = command;
|
||
|
|
|
||
|
|
// First truncate by lines if needed
|
||
|
|
if (needsLineTruncation) {
|
||
|
|
truncated = lines.slice(0, MAX_COMMAND_DISPLAY_LINES).join('\n');
|
||
|
|
}
|
||
|
|
|
||
|
|
// Then truncate by chars if still too long
|
||
|
|
if (truncated.length > MAX_COMMAND_DISPLAY_CHARS) {
|
||
|
|
truncated = truncated.slice(0, MAX_COMMAND_DISPLAY_CHARS);
|
||
|
|
}
|
||
|
|
return <Text>{truncated.trim()}…</Text>;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return command;
|
||
|
|
}
|
||
|
|
export function renderToolUseProgressMessage(progressMessagesForMessage: ProgressMessage<BashProgress>[], {
|
||
|
|
verbose,
|
||
|
|
tools: _tools,
|
||
|
|
terminalSize: _terminalSize,
|
||
|
|
inProgressToolCallCount: _inProgressToolCallCount
|
||
|
|
}: {
|
||
|
|
tools: Tool[];
|
||
|
|
verbose: boolean;
|
||
|
|
terminalSize?: {
|
||
|
|
columns: number;
|
||
|
|
rows: number;
|
||
|
|
};
|
||
|
|
inProgressToolCallCount?: number;
|
||
|
|
}): React.ReactNode {
|
||
|
|
const lastProgress = progressMessagesForMessage.at(-1);
|
||
|
|
if (!lastProgress || !lastProgress.data) {
|
||
|
|
return <MessageResponse height={1}>
|
||
|
|
<Text dimColor>Running…</Text>
|
||
|
|
</MessageResponse>;
|
||
|
|
}
|
||
|
|
const data = lastProgress.data;
|
||
|
|
return <ShellProgressMessage fullOutput={data.fullOutput} output={data.output} elapsedTimeSeconds={data.elapsedTimeSeconds} totalLines={data.totalLines} totalBytes={data.totalBytes} timeoutMs={data.timeoutMs} taskId={data.taskId} verbose={verbose} />;
|
||
|
|
}
|
||
|
|
export function renderToolUseQueuedMessage(): React.ReactNode {
|
||
|
|
return <MessageResponse height={1}>
|
||
|
|
<Text dimColor>Waiting…</Text>
|
||
|
|
</MessageResponse>;
|
||
|
|
}
|
||
|
|
export function renderToolResultMessage(content: Out, progressMessagesForMessage: ProgressMessage<BashProgress>[], {
|
||
|
|
verbose,
|
||
|
|
theme: _theme,
|
||
|
|
tools: _tools,
|
||
|
|
style: _style
|
||
|
|
}: {
|
||
|
|
verbose: boolean;
|
||
|
|
theme: ThemeName;
|
||
|
|
tools: Tool[];
|
||
|
|
style?: 'condensed';
|
||
|
|
}): React.ReactNode {
|
||
|
|
const lastProgress = progressMessagesForMessage.at(-1);
|
||
|
|
const timeoutMs = lastProgress?.data?.timeoutMs;
|
||
|
|
return <BashToolResultMessage content={content} verbose={verbose} timeoutMs={timeoutMs} />;
|
||
|
|
}
|
||
|
|
export function renderToolUseErrorMessage(result: ToolResultBlockParam['content'], {
|
||
|
|
verbose,
|
||
|
|
progressMessagesForMessage: _progressMessagesForMessage,
|
||
|
|
tools: _tools
|
||
|
|
}: {
|
||
|
|
verbose: boolean;
|
||
|
|
progressMessagesForMessage: ProgressMessage<BashProgress>[];
|
||
|
|
tools: Tool[];
|
||
|
|
}): React.ReactNode {
|
||
|
|
return <FallbackToolUseErrorMessage result={result} verbose={verbose} />;
|
||
|
|
}
|
||
|
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJUb29sUmVzdWx0QmxvY2tQYXJhbSIsIlJlYWN0IiwiS2V5Ym9hcmRTaG9ydGN1dEhpbnQiLCJGYWxsYmFja1Rvb2xVc2VFcnJvck1lc3NhZ2UiLCJNZXNzYWdlUmVzcG9uc2UiLCJTaGVsbFByb2dyZXNzTWVzc2FnZSIsIkJveCIsIlRleHQiLCJ1c2VLZXliaW5kaW5nIiwidXNlU2hvcnRjdXREaXNwbGF5IiwidXNlQXBwU3RhdGVTdG9yZSIsInVzZVNldEFwcFN0YXRlIiwiVG9vbCIsImJhY2tncm91bmRBbGwiLCJQcm9ncmVzc01lc3NhZ2UiLCJlbnYiLCJpc0VudlRydXRoeSIsImdldERpc3BsYXlQYXRoIiwiaXNGdWxsc2NyZWVuRW52RW5hYmxlZCIsIlRoZW1lTmFtZSIsIkJhc2hQcm9ncmVzcyIsIkJhc2hUb29sSW5wdXQiLCJPdXQiLCJCYXNoVG9vbFJlc3VsdE1lc3NhZ2UiLCJleHRyYWN0QmFzaENvbW1lbnRMYWJlbCIsInBhcnNlU2VkRWRpdENvbW1hbmQiLCJNQVhfQ09NTUFORF9ESVNQTEFZX0xJTkVTIiwiTUFYX0NPTU1BTkRfRElTUExBWV9DSEFSUyIsIkJhY2tncm91bmRIaW50IiwidDAiLCIkIiwiX2MiLCJ0MSIsInVuZGVmaW5lZCIsIm9uQmFja2dyb3VuZCIsInN0b3JlIiwic2V0QXBwU3RhdGUiLCJ0MiIsImdldFN0YXRlIiwiaGFuZGxlQmFja2dyb3VuZCIsInQzIiwiU3ltYm9sIiwiZm9yIiwiY29udGV4dCIsImJhc2VTaG9ydGN1dCIsInNob3J0Y3V0IiwidGVybWluYWwiLCJwcm9jZXNzIiwiQ0xBVURFX0NPREVfRElTQUJMRV9CQUNLR1JPVU5EX1RBU0tTIiwidDQiLCJyZW5kZXJUb29sVXNlTWVzc2FnZSIsImlucHV0IiwiUGFydGlhbCIsInZlcmJvc2UiLCJ0aGVtZSIsIl90aGVtZSIsIlJlYWN0Tm9kZSIsImNvbW1hbmQiLCJzZWRJbmZvIiwiZmlsZVBhdGgiLCJsaW5lcyIsInNwbGl0IiwibGFiZWwiLCJsZW5ndGgiLCJzbGljZSIsIm5lZWRzTGluZVRydW5jYXRpb24iLCJuZWVkc0NoYXJUcnVuY2F0aW9uIiwidHJ1bmNhdGVkIiwiam9pbiIsInRyaW0iLCJyZW5kZXJUb29sVXNlUHJvZ3Jlc3NNZXNzYWdlIiwicHJvZ3Jlc3NNZXNzYWdlc0Zvck1lc3NhZ2UiLCJ0b29scyIsIl90b29scyIsInRlcm1pbmFsU2l6ZSIsIl90ZXJtaW5hbFNpemUiLCJpblByb2dyZXNzVG9vbENhbGxDb3VudCIsIl9pblByb2dyZXNzVG9vbENhbGxDb3VudCIsImNvbHVtbnMiLCJyb3dzIiwibGFzdFByb2dyZXNzIiwiYXQiLCJkYXRhIiwiZnVsbE91dHB1dCIsIm91dHB1dCIsImVsYXBzZWRUaW1lU2Vjb25kcyIsInRvdGFsTGluZXMiLCJ0b3RhbEJ5dGVzIiwidGltZW91dE1zIiwidGFza0lkIiwicmVuZGVyVG9vbFVzZVF1ZXVlZE1lc3NhZ2UiLCJyZW5kZXJUb29sUmVzdWx0TWVzc2FnZSIsImNvbnRlbnQiLCJzdHlsZSIsIl9zdHlsZSIsInJlbmRlclRvb2xVc2VFcnJvck1lc3NhZ2UiLCJyZXN1bHQiLCJfcHJvZ3Jlc3NNZXNzYWdlc0Zvck1lc3NhZ2UiXSwic291cmNlcyI6WyJVSS50c3giXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBUb29sUmVzdWx0QmxvY2tQYXJhbSB9IGZyb20gJ0BhbnRocm9waWMtYWkvc2RrL3Jlc291cmNlcy9pbmRleC5tanMnXG5pbXBvcnQgKiBhcyBSZWFjdCBmcm9tICdyZWFjdCdcbmltcG9ydCB7IEtleWJvYXJkU2hvcnRjdXRIaW50IH0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy9kZXNpZ24tc3lzdGVtL0tleWJvYXJkU2hvcnRjdXRIaW50LmpzJ1xuaW1wb3J0IHsgRmFsbGJhY2tUb29sVXNlRXJyb3JNZXNzYWdlIH0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy9GYWxsYmFja1Rvb2xVc2VFcnJvck1lc3NhZ2UuanMnXG5pbXBvcnQgeyBNZXNzYWdlUmVzcG9uc2UgfSBmcm9tICcuLi8uLi9jb21wb25lbnRzL01lc3NhZ2VSZXNwb25zZS5qcydcbmltcG9ydCB7IFNoZWxsUHJvZ3Jlc3NNZXNzYWdlIH0gZnJvbSAnLi4vLi4vY29tcG9uZW50cy9zaGVsbC9TaGVsbFByb2dyZXNzTWVzc2FnZS5qcydcbmltcG9ydCB7IEJveCwgVGV4dCB9IGZyb20gJy4uLy4uL2luay5qcydcbmltcG9ydCB7IHVzZUtleWJpbmRpbmcgfSBmcm9tICcuLi8uLi9rZXliaW5kaW5ncy91c2VLZXliaW5kaW5nLmpzJ1xuaW1wb3J0IHsgdXNlU2hvcnRjdXREaXNwbGF5IH0gZnJvbSAnLi4vLi4va2V5YmluZGluZ3MvdXNlU2hvcnRjdXREaXNwbGF5LmpzJ1xuaW1wb3J0IHsgdXNlQXBwU3RhdGVTdG9yZSwgdXNlU2V0QXBwU3RhdGUgfSBmcm9tICcuLi8uLi9zdGF0ZS9BcHBTdGF0ZS5qcydcbmltcG9ydCB0eXBlIHsgVG9vbCB9IGZyb20gJy4uLy4uL1Rvb2wuanMnXG5pbXBvcnQgeyBiYWNrZ3JvdW5kQWxsIH0gZnJvbSAnLi4vLi4vdGFza3MvTG9jYWxTaGVsbFRhc2svTG9jYWxTaGVsbFRhc2suanMnXG5pbXBvcnQgdHlwZSB7IFByb2dyZXNzTWVzc2FnZSB9IGZyb20gJy4uLy4uL3R5cGVzL21lc3NhZ2UuanMnXG5pbXBvcnQgeyBlbnYgfSBmcm9tICcuLi8uLi91dGlscy9lbnYuanMnXG5pbXBvcnQgeyBpc0VudlRydXRoeSB9IGZyb20gJy4uLy4uL3V0aWxzL2VudlV0aWxzLmpzJ1xuaW1wb3J0IHsgZ2V0RGlzcGxheVBhdGggfSBmcm9tICcuLi8uLi91dGlscy9maWxlLmpzJ1xuaW1wb3J0IHsgaXNGdWxsc2NyZWVuRW52RW5hYmxlZCB9IGZyb20gJy4uLy4uL3V0aWxzL2Z1bGxzY3JlZW4uanMnXG5pbXBvcnQgdHlwZSB7IFRoZW1lTmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzL3RoZW1lLmpzJ1xuaW1wb3J0IHR5cGUgeyBCYXNoUHJvZ3Jlc3MsIEJhc2hUb29sSW5wdXQsIE91dCB9IGZyb20gJy4vQmFzaFRvb2wuanMnXG5pbXBvcnQgQmFzaFRvb2xSZXN1bHRNZXNzYWdlIGZyb20gJy4vQmFzaFRvb2xSZXN1bHRNZXNzYWdlLmpzJ1xuaW1wb3J0IHsgZXh0cmFjdEJhc2hDb21tZW50TGFiZWwgfSBmcm9tICcuL2NvbW1lbnRMYWJlbC5qcydcbmltcG9ydCB7IHBhcnNlU2VkRWRpdENvbW1hbmQgfSBmcm9tICcuL3NlZEVkaXRQYXJzZXIuanMnXG5cbi8vIENvbnN0YW50cyBmb3IgY29tbWFuZCBkaXNwbGF5XG5jb25zdCBNQVhfQ09NTUFORF9ESVNQTEFZX0xJTkVTID0gMlxuY29uc3QgTUFYX0NPTU1BTkRfRElTUExBWV9DSEFSUyA9IDE2MFxuXG4vLyBTaW1wbGU
|