diff --git a/opencode.json b/opencode.json index 7da874d36..4c757ce04 100644 --- a/opencode.json +++ b/opencode.json @@ -1,4 +1,10 @@ { "$schema": "https://opencode.ai/config.json", - "plugin": ["opencode-openai-codex-auth"] + "plugin": ["opencode-openai-codex-auth"], + "mcp": { + "weather": { + "type": "local", + "command": ["bun", "x", "@h1deya/mcp-server-weather"] + } + } } diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 11bd179f1..2bd5a7fe4 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -565,8 +565,7 @@ function ToolPart(props: { part: ToolPart; message: AssistantMessage }) { const sync = useSync() const [margin, setMargin] = createSignal(0) const component = createMemo(() => { - const ready = ToolRegistry.ready(props.part.tool) - if (!ready) return + const render = ToolRegistry.render(props.part.tool) ?? GenericTool const metadata = props.part.state.status === "pending" ? {} : (props.part.state.metadata ?? {}) const input = props.part.state.input @@ -620,8 +619,9 @@ function ToolPart(props: { part: ToolPart; message: AssistantMessage }) { }} > = { input: Partial> metadata: Partial> permission: Record + tool: string output?: string } +function GenericTool(props: ToolProps) { + return ( + + {props.tool} {input(props.input)} + + ) +} const ToolRegistry = (() => { - const state: Record> }> = {} + const state: Record> }> = {} function register(input: { name: string container: "inline" | "block" - ready?: Component> + render?: Component> }) { state[input.name] = input return input @@ -679,8 +687,8 @@ const ToolRegistry = (() => { container(name: string) { return state[name]?.container }, - ready(name: string) { - return state[name]?.ready + render(name: string) { + return state[name]?.render }, } })() @@ -698,7 +706,7 @@ function ToolTitle(props: { fallback: string; when: any; icon: string; children: ToolRegistry.register({ name: "bash", container: "block", - ready(props) { + render(props) { const output = createMemo(() => Bun.stripANSI(props.output?.trim() ?? "")) return ( <> @@ -721,11 +729,11 @@ ToolRegistry.register({ ToolRegistry.register({ name: "read", container: "inline", - ready(props) { + render(props) { return ( <> - Read {normalizePath(props.input.filePath!)} + Read {normalizePath(props.input.filePath!)} {input(props.input, ["filePath"])} ) @@ -735,7 +743,7 @@ ToolRegistry.register({ ToolRegistry.register({ name: "write", container: "block", - ready(props) { + render(props) { const lines = createMemo(() => { return props.input.content?.split("\n") ?? [] }) @@ -773,11 +781,12 @@ ToolRegistry.register({ ToolRegistry.register({ name: "glob", container: "inline", - ready(props) { + render(props) { return ( <> - Glob "{props.input.pattern}" ({props.metadata.count} matches) + Glob "{props.input.pattern}" in {normalizePath(props.input.path)} + ({props.metadata.count} matches) ) @@ -787,10 +796,11 @@ ToolRegistry.register({ ToolRegistry.register({ name: "grep", container: "inline", - ready(props) { + render(props) { return ( - Grep "{props.input.pattern}" + Grep "{props.input.pattern}" in {normalizePath(props.input.path)} + ({props.metadata.matches} matches) ) }, @@ -799,7 +809,7 @@ ToolRegistry.register({ ToolRegistry.register({ name: "list", container: "inline", - ready(props) { + render(props) { const dir = createMemo(() => { if (props.input.path) { return normalizePath(props.input.path) @@ -819,7 +829,7 @@ ToolRegistry.register({ ToolRegistry.register({ name: "task", container: "block", - ready(props) { + render(props) { return ( <> @@ -844,7 +854,7 @@ ToolRegistry.register({ ToolRegistry.register({ name: "webfetch", container: "inline", - ready(props) { + render(props) { return ( WebFetch {(props.input as any).url} @@ -856,7 +866,7 @@ ToolRegistry.register({ ToolRegistry.register({ name: "edit", container: "block", - ready(props) { + render(props) { const diff = createMemo(() => { const diff = props.metadata.diff ?? props.permission["diff"] if (!diff) return null @@ -923,7 +933,10 @@ ToolRegistry.register({ return ( <> - Edit {normalizePath(props.input.filePath!)} + Edit {normalizePath(props.input.filePath!)}{" "} + {input({ + replaceAll: props.input.replaceAll, + })} @@ -953,7 +966,7 @@ ToolRegistry.register({ ToolRegistry.register({ name: "patch", container: "block", - ready(props) { + render(props) { return ( <> @@ -972,7 +985,7 @@ ToolRegistry.register({ ToolRegistry.register({ name: "todowrite", container: "block", - ready(props) { + render(props) { return ( @@ -987,9 +1000,19 @@ ToolRegistry.register({ }, }) -function normalizePath(input: string) { +function normalizePath(input?: string) { + if (!input) return "" if (path.isAbsolute(input)) { return path.relative(process.cwd(), input) || "." } return input } + +function input(input: Record, omit?: string[]): string { + const primitives = Object.entries(input).filter(([key, value]) => { + if (omit?.includes(key)) return false + return typeof value === "string" || typeof value === "number" || typeof value === "boolean" + }) + if (primitives.length === 0) return "" + return `[${primitives.map(([key, value]) => `${key}=${value}`).join(", ")}]` +}