void })
function formatToolContent(raw: string): { name: string; detail: string; body: string; output: string } {
// Call is always on the first line; output follows after the newline.
- const nl = raw.indexOf('\n')
+ const nl = raw.indexOf("\n")
const callLine = nl === -1 ? raw : raw.slice(0, nl)
- const output = nl === -1 ? '' : raw.slice(nl + 1).trimEnd()
+ const output = nl === -1 ? "" : raw.slice(nl + 1).trimEnd()
const m = callLine.match(/^(\w+)\((.*)\)$/)
- if (!m) return { name: '', detail: '', body: raw, output: '' }
+ if (!m) return { name: "", detail: "", body: raw, output: "" }
const name = m[1]
const argsRaw = m[2]
try {
const obj = JSON.parse(argsRaw)
- let detail = ''
- if (obj.steps?.[0]?.tool) detail = obj.steps[0].tool
- else if (obj.steps?.[0]?.code) detail = obj.language ?? 'bash'
+ let detail = ""
+ if (name === "call_tool") {
+ detail = obj.calls?.[0]?.tool ?? ""
+ } else if (name === "pipe") {
+ const s = obj.stages?.[0]
+ detail = s?.tool ?? s?.language ?? "bash"
+ } else {
+ detail = obj.steps?.[0]?.language ?? "bash"
+ }
return { name, detail, body: JSON.stringify(obj, null, 2), output }
} catch {
- return { name, detail: '', body: argsRaw, output }
+ return { name, detail: "", body: argsRaw, output }
}
}
@@ -383,12 +389,37 @@ const TOOL_ICONS: Record
= {
task_check: '☑️',
task_clear: '☑️',
bash: '🖥️',
+ python3: '🐍',
+ perl: '🐪',
+ lua: '🌙',
+ awk: '🔧',
+ sed: '🔧',
+ jq: '🔧',
+ bc: '🔢',
}
function toolIcon(detail: string): string {
return TOOL_ICONS[detail] ?? '🖥️'
}
+function InfoMessage({ content }: { content: string }) {
+ const lines = content.split('\n')
+ const shellLines = lines.filter(l => l.startsWith('$ ')).map(l => l.slice(2))
+ if (shellLines.length === 0) return {content}
+ const cmd = shellLines[0]
+ const output = shellLines.slice(1).join('\n')
+ return (
+
+ )
+}
+
function ToolCall({ content }: { content: string }) {
const { name, detail, body, output } = formatToolContent(content)
const [open, setOpen] = useState(false)
diff --git a/src/style.css b/src/style.css
index 4246c72..a7f0046 100644
--- a/src/style.css
+++ b/src/style.css
@@ -797,6 +797,28 @@ details[open] > .tool-header::before {
[data-theme="acme"] .tool-body {
padding: 4px 10px;
}
+[data-theme="acme"] .message.info .msg-bubble {
+ width: 100%;
+ padding: 0;
+ margin: 4px 0;
+}
+[data-theme="acme"] .shell-block {
+ background: #fff;
+ border: 1px solid var(--border);
+ border-radius: var(--r-sm);
+}
+[data-theme="acme"] .shell-block .tool-header {
+ cursor: default;
+}
+[data-theme="acme"] .shell-block .tool-header::before {
+ display: none;
+}
+[data-theme="acme"] .shell-block .tool-output {
+ display: block;
+ color: var(--text);
+ font-style: normal;
+ padding: 8px 12px;
+}
[data-theme="acme"] .tool-header {
padding: 4px 10px;
}
diff --git a/vite.config.ts b/vite.config.ts
index d13024b..e8cf96b 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -3,6 +3,7 @@ import preact from '@preact/preset-vite'
export default defineConfig({
plugins: [preact()],
+ base: './',
server: {
proxy: {
'/s/': 'http://localhost:8080',