buroventures-harald-code
Version:
Harald Code - AI-powered coding assistant CLI
123 lines • 7.15 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { Box, Text, useInput } from 'ink';
import { DiffRenderer } from './DiffRenderer.js';
import { Colors } from '../../colors.js';
import { ToolConfirmationOutcome, } from 'buroventures-harald-code-core';
import { RadioButtonSelect, } from '../shared/RadioButtonSelect.js';
import { MaxSizedBox } from '../shared/MaxSizedBox.js';
export const ToolConfirmationMessage = ({ confirmationDetails, isFocused = true, availableTerminalHeight, terminalWidth, }) => {
const { onConfirm } = confirmationDetails;
const childWidth = terminalWidth - 2; // 2 for padding
useInput((_, key) => {
if (!isFocused)
return;
if (key.escape) {
onConfirm(ToolConfirmationOutcome.Cancel);
}
});
const handleSelect = (item) => onConfirm(item);
let bodyContent = null; // Removed contextDisplay here
let question;
const options = new Array();
// Body content is now the DiffRenderer, passing filename to it
// The bordered box is removed from here and handled within DiffRenderer
function availableBodyContentHeight() {
if (options.length === 0) {
// This should not happen in practice as options are always added before this is called.
throw new Error('Options not provided for confirmation message');
}
if (availableTerminalHeight === undefined) {
return undefined;
}
// Calculate the vertical space (in lines) consumed by UI elements
// surrounding the main body content.
const PADDING_OUTER_Y = 2; // Main container has `padding={1}` (top & bottom).
const MARGIN_BODY_BOTTOM = 1; // margin on the body container.
const HEIGHT_QUESTION = 1; // The question text is one line.
const MARGIN_QUESTION_BOTTOM = 1; // Margin on the question container.
const HEIGHT_OPTIONS = options.length; // Each option in the radio select takes one line.
const surroundingElementsHeight = PADDING_OUTER_Y +
MARGIN_BODY_BOTTOM +
HEIGHT_QUESTION +
MARGIN_QUESTION_BOTTOM +
HEIGHT_OPTIONS;
return Math.max(availableTerminalHeight - surroundingElementsHeight, 1);
}
if (confirmationDetails.type === 'edit') {
if (confirmationDetails.isModifying) {
return (_jsxs(Box, { minWidth: "90%", borderStyle: "round", borderColor: Colors.Gray, justifyContent: "space-around", padding: 1, overflow: "hidden", children: [_jsx(Text, { children: "Modify in progress: " }), _jsx(Text, { color: Colors.AccentGreen, children: "Save and close external editor to continue" })] }));
}
question = `Apply this change?`;
options.push({
label: 'Yes, allow once',
value: ToolConfirmationOutcome.ProceedOnce,
}, {
label: 'Yes, allow always',
value: ToolConfirmationOutcome.ProceedAlways,
}, {
label: 'Modify with external editor',
value: ToolConfirmationOutcome.ModifyWithEditor,
}, {
label: 'No, suggest changes (esc)',
value: ToolConfirmationOutcome.Cancel,
});
bodyContent = (_jsx(DiffRenderer, { diffContent: confirmationDetails.fileDiff, filename: confirmationDetails.fileName, availableTerminalHeight: availableBodyContentHeight(), terminalWidth: childWidth }));
}
else if (confirmationDetails.type === 'exec') {
const executionProps = confirmationDetails;
question = `Allow execution of: '${executionProps.rootCommand}'?`;
options.push({
label: `Yes, allow once`,
value: ToolConfirmationOutcome.ProceedOnce,
}, {
label: `Yes, allow always ...`,
value: ToolConfirmationOutcome.ProceedAlways,
}, {
label: 'No, suggest changes (esc)',
value: ToolConfirmationOutcome.Cancel,
});
let bodyContentHeight = availableBodyContentHeight();
if (bodyContentHeight !== undefined) {
bodyContentHeight -= 2; // Account for padding;
}
bodyContent = (_jsx(Box, { flexDirection: "column", children: _jsx(Box, { paddingX: 1, marginLeft: 1, children: _jsx(MaxSizedBox, { maxHeight: bodyContentHeight, maxWidth: Math.max(childWidth - 4, 1), children: _jsx(Box, { children: _jsx(Text, { color: Colors.AccentCyan, children: executionProps.command }) }) }) }) }));
}
else if (confirmationDetails.type === 'info') {
const infoProps = confirmationDetails;
const displayUrls = infoProps.urls &&
!(infoProps.urls.length === 1 && infoProps.urls[0] === infoProps.prompt);
question = `Do you want to proceed?`;
options.push({
label: 'Yes, allow once',
value: ToolConfirmationOutcome.ProceedOnce,
}, {
label: 'Yes, allow always',
value: ToolConfirmationOutcome.ProceedAlways,
}, {
label: 'No, suggest changes (esc)',
value: ToolConfirmationOutcome.Cancel,
});
bodyContent = (_jsxs(Box, { flexDirection: "column", paddingX: 1, marginLeft: 1, children: [_jsx(Text, { color: Colors.AccentCyan, children: infoProps.prompt }), displayUrls && infoProps.urls && infoProps.urls.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { children: "URLs to fetch:" }), infoProps.urls.map((url) => (_jsxs(Text, { children: [" - ", url] }, url)))] }))] }));
}
else {
// mcp tool confirmation
const mcpProps = confirmationDetails;
bodyContent = (_jsxs(Box, { flexDirection: "column", paddingX: 1, marginLeft: 1, children: [_jsxs(Text, { color: Colors.AccentCyan, children: ["MCP Server: ", mcpProps.serverName] }), _jsxs(Text, { color: Colors.AccentCyan, children: ["Tool: ", mcpProps.toolName] })] }));
question = `Allow execution of MCP tool "${mcpProps.toolName}" from server "${mcpProps.serverName}"?`;
options.push({
label: 'Yes, allow once',
value: ToolConfirmationOutcome.ProceedOnce,
}, {
label: `Yes, always allow tool "${mcpProps.toolName}" from server "${mcpProps.serverName}"`,
value: ToolConfirmationOutcome.ProceedAlwaysTool, // Cast until types are updated
}, {
label: `Yes, always allow all tools from server "${mcpProps.serverName}"`,
value: ToolConfirmationOutcome.ProceedAlwaysServer,
}, {
label: 'No, suggest changes (esc)',
value: ToolConfirmationOutcome.Cancel,
});
}
return (_jsxs(Box, { flexDirection: "column", padding: 1, width: childWidth, children: [_jsx(Box, { flexGrow: 1, flexShrink: 1, overflow: "hidden", marginBottom: 1, children: bodyContent }), _jsx(Box, { marginBottom: 1, flexShrink: 0, children: _jsx(Text, { wrap: "truncate", children: question }) }), _jsx(Box, { flexShrink: 0, children: _jsx(RadioButtonSelect, { items: options, onSelect: handleSelect, isFocused: isFocused }) })] }));
};
//# sourceMappingURL=ToolConfirmationMessage.js.map