From f77e1d97343d004cfe7c7be70c7269c14f67c468 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Wed, 31 Dec 2025 12:01:57 -0500 Subject: [PATCH] sync --- .opencode/opencode.jsonc | 7 +- .../cli/cmd/tui/routes/session/permission.tsx | 33 ++++++- packages/opencode/src/session/prompt.ts | 94 +++++++++++-------- packages/opencode/src/tool/registry.ts | 1 - 4 files changed, 88 insertions(+), 47 deletions(-) diff --git a/.opencode/opencode.jsonc b/.opencode/opencode.jsonc index 28ac3c4f89..0833130012 100644 --- a/.opencode/opencode.jsonc +++ b/.opencode/opencode.jsonc @@ -11,7 +11,12 @@ "options": {}, }, }, - "mcp": {}, + "mcp": { + "context7": { + "type": "remote", + "url": "https://mcp.context7.com/mcp", + }, + }, "tools": { "github-triage": false, }, diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx index 9e944c330f..a9a2246278 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx @@ -75,14 +75,16 @@ function EditBody(props: { request: PermissionRequest }) { ) } -function TextBody(props: { title: string; description?: string; icon: string }) { +function TextBody(props: { title: string; description?: string; icon?: string }) { const { theme } = useTheme() return ( <> - - {props.icon} - + + + {props.icon} + + {props.title} @@ -113,12 +115,33 @@ export function PermissionPrompt(props: { request: PermissionRequest }) { return {} }) + const { theme } = useTheme() + return ( } + body={ + + + + + + + Applies to the following patterns + + {(pattern) => ( + + {"- "} + {pattern} + + )} + + + + + } options={{ confirm: "Confirm", cancel: "Cancel" }} onSelect={(option) => { if (option === "cancel") { diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index aa681bdbe1..b51c567fb7 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -9,7 +9,7 @@ import { SessionRevert } from "./revert" import { Session } from "." import { Agent } from "../agent/agent" import { Provider } from "../provider/provider" -import { type Tool as AITool, tool, jsonSchema } from "ai" +import { type Tool as AITool, tool, jsonSchema, type ToolCallOptions } from "ai" import { SessionCompaction } from "./compaction" import { Instance } from "../project/instance" import { Bus } from "../bus" @@ -596,6 +596,41 @@ export namespace SessionPrompt { }) { using _ = log.time("resolveTools") const tools: Record = {} + + const context = (args: any, options: ToolCallOptions): Tool.Context => ({ + sessionID: input.session.id, + abort: options.abortSignal!, + messageID: input.processor.message.id, + callID: options.toolCallId, + extra: { model: input.model }, + agent: input.agent.name, + metadata: async (val: { title?: string; metadata?: any }) => { + const match = input.processor.partFromToolCall(options.toolCallId) + if (match && match.state.status === "running") { + await Session.updatePart({ + ...match, + state: { + title: val.title, + metadata: val.metadata, + status: "running", + input: args, + time: { + start: Date.now(), + }, + }, + }) + } + }, + async ask(req) { + await PermissionNext.ask({ + ...req, + sessionID: input.session.parentID ?? input.session.id, + tool: { messageID: input.processor.message.id, callID: options.toolCallId }, + ruleset: input.agent.permission, + }) + }, + }) + for (const item of await ToolRegistry.tools(input.model.providerID)) { const schema = ProviderTransform.schema(input.model, z.toJSONSchema(item.parameters)) tools[item.id] = tool({ @@ -603,57 +638,25 @@ export namespace SessionPrompt { description: item.description, inputSchema: jsonSchema(schema as any), async execute(args, options) { + const ctx = context(args, options) await Plugin.trigger( "tool.execute.before", { tool: item.id, - sessionID: input.session.id, - callID: options.toolCallId, + sessionID: ctx.sessionID, + callID: ctx.callID, }, { args, }, ) - const ctx: Tool.Context = { - sessionID: input.session.id, - abort: options.abortSignal!, - messageID: input.processor.message.id, - callID: options.toolCallId, - extra: { model: input.model }, - agent: input.agent.name, - metadata: async (val: { title?: string; metadata?: any }) => { - const match = input.processor.partFromToolCall(options.toolCallId) - if (match && match.state.status === "running") { - await Session.updatePart({ - ...match, - state: { - title: val.title, - metadata: val.metadata, - status: "running", - input: args, - time: { - start: Date.now(), - }, - }, - }) - } - }, - async ask(req) { - await PermissionNext.ask({ - ...req, - sessionID: input.session.parentID ?? input.session.id, - tool: { messageID: input.processor.message.id, callID: options.toolCallId }, - ruleset: input.agent.permission, - }) - }, - } const result = await item.execute(args, ctx) await Plugin.trigger( "tool.execute.after", { tool: item.id, - sessionID: input.session.id, - callID: options.toolCallId, + sessionID: ctx.sessionID, + callID: ctx.callID, }, result, ) @@ -667,30 +670,41 @@ export namespace SessionPrompt { }, }) } + for (const [key, item] of Object.entries(await MCP.tools())) { const execute = item.execute if (!execute) continue // Wrap execute to add plugin hooks and format output item.execute = async (args, opts) => { + const ctx = context(args, opts) + await Plugin.trigger( "tool.execute.before", { tool: key, - sessionID: input.session.id, + sessionID: ctx.sessionID, callID: opts.toolCallId, }, { args, }, ) + + await ctx.ask({ + permission: key, + metadata: {}, + patterns: ["*"], + always: ["*"], + }) + const result = await execute(args, opts) await Plugin.trigger( "tool.execute.after", { tool: key, - sessionID: input.session.id, + sessionID: ctx.sessionID, callID: opts.toolCallId, }, result, diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts index 9a984db0aa..db51528474 100644 --- a/packages/opencode/src/tool/registry.ts +++ b/packages/opencode/src/tool/registry.ts @@ -2,7 +2,6 @@ import { BashTool } from "./bash" import { EditTool } from "./edit" import { GlobTool } from "./glob" import { GrepTool } from "./grep" -import { ListTool } from "./ls" import { BatchTool } from "./batch" import { ReadTool } from "./read" import { TaskTool } from "./task"