webui: Refactor tool calls
diff --git a/webui/src/web-components/sketch-tool-card-bash.ts b/webui/src/web-components/sketch-tool-card-bash.ts
new file mode 100644
index 0000000..75e65d9
--- /dev/null
+++ b/webui/src/web-components/sketch-tool-card-bash.ts
@@ -0,0 +1,119 @@
+import { LitElement, css, html } from "lit";
+import { customElement, property } from "lit/decorators.js";
+import { ToolCall } from "../types";
+
+// Common styles shared across all tool cards
+export const commonStyles = css`
+ pre {
+ background: rgb(236, 236, 236);
+ color: black;
+ padding: 0.5em;
+ border-radius: 4px;
+ white-space: pre-wrap;
+ word-break: break-word;
+ max-width: 100%;
+ width: 100%;
+ box-sizing: border-box;
+ overflow-wrap: break-word;
+ }
+ .summary-text {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ max-width: 100%;
+ font-family: monospace;
+ }
+`;
+
+@customElement("sketch-tool-card-bash")
+export class SketchToolCardBash extends LitElement {
+ @property() toolCall: ToolCall;
+ @property() open: boolean;
+
+ static styles = [
+ commonStyles,
+ css`
+ .input {
+ display: flex;
+ width: 100%;
+ flex-direction: column;
+ }
+ .input pre {
+ width: 100%;
+ margin-bottom: 0;
+ border-radius: 4px 4px 0 0;
+ box-sizing: border-box;
+ }
+ .result pre {
+ margin-top: 0;
+ color: #555;
+ border-radius: 0 0 4px 4px;
+ width: 100%;
+ box-sizing: border-box;
+ }
+ .result pre.scrollable-on-hover {
+ max-height: 300px;
+ overflow-y: auto;
+ }
+ .tool-call-result-container {
+ width: 100%;
+ position: relative;
+ }
+ .background-badge {
+ display: inline-block;
+ background-color: #6200ea;
+ color: white;
+ font-size: 10px;
+ font-weight: bold;
+ padding: 2px 6px;
+ border-radius: 10px;
+ margin-left: 8px;
+ vertical-align: middle;
+ }
+ .command-wrapper {
+ display: inline-block;
+ max-width: 100%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ `,
+ ];
+
+ render() {
+ const inputData = JSON.parse(this.toolCall?.input || "{}");
+ const isBackground = inputData?.background === true;
+ const backgroundIcon = isBackground ? "🔄 " : "";
+
+ return html` <sketch-tool-card
+ .open=${this.open}
+ .toolCall=${this.toolCall}
+ >
+ <span slot="summary" class="summary-text">
+ <div class="command-wrapper">
+ ${backgroundIcon}${inputData?.command}
+ </div>
+ </span>
+ <div slot="input" class="input">
+ <div class="tool-call-result-container">
+ <pre>${backgroundIcon}${inputData?.command}</pre>
+ </div>
+ </div>
+ ${this.toolCall?.result_message?.tool_result
+ ? html`<div slot="result" class="result">
+ <div class="tool-call-result-container">
+ <pre class="tool-call-result">
+${this.toolCall?.result_message.tool_result}</pre
+ >
+ </div>
+ </div>`
+ : ""}
+ </sketch-tool-card>`;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "sketch-tool-card-bash": SketchToolCardBash;
+ }
+}