refactor(core): consolidate tool architecture

This commit is contained in:
Dax Raad 2026-07-26 20:08:55 -04:00
commit 8db7487c89
466 changed files with 9405 additions and 11071 deletions

View file

@ -9,7 +9,7 @@ import type {
TuiAttentionSoundName,
TuiAttentionSoundPack,
TuiAttentionSoundPackInfo,
} from "@opencode-ai/plugin/tui"
} from "@opencode-ai/plugin/v1/tui"
import { AttentionSoundName, type Config } from "./config"
import { Schema } from "effect"
import stripAnsi from "strip-ansi"

View file

@ -14,8 +14,8 @@ import type {
McpServer,
ModelInfo,
PermissionSavedInfo,
PermissionV2Request,
ProviderV2Info,
PermissionRequest,
ProviderInfo,
ReferenceInfo,
SessionMessageInfo,
SessionMessageAssistant,
@ -29,7 +29,7 @@ import type {
OpenCodeEvent,
WebSearchProvider,
} from "@opencode-ai/client"
import type { Plugin } from "@opencode-ai/plugin/v2/tui"
import type { Plugin } from "@opencode-ai/plugin/tui"
import { createStore, produce, reconcile } from "solid-js/store"
import { createSimpleContext } from "./helper"
import { useClient } from "./client"
@ -55,7 +55,7 @@ type LocationData = {
resource?: McpResource[]
}
model?: ModelInfo[]
provider?: ProviderV2Info[]
provider?: ProviderInfo[]
reference?: ReferenceInfo[]
websearch?: WebSearchProvider[]
// Currently running shell commands for this location, keyed by shell id. Entries are removed
@ -75,7 +75,7 @@ type Store = {
message: Record<string, SessionMessageInfo[]>
pending: Record<string, SessionPendingInfo[]>
input: Record<string, string[]>
permission: Record<string, PermissionV2Request[]>
permission: Record<string, PermissionRequest[]>
// Pending forms keyed by owner: a session ID or the temporary "global" elicitation sentinel.
form: Record<string, FormWithLocation[]>
}
@ -808,14 +808,14 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
message.append(draft, index, failed)
})
break
case "permission.v2.asked":
case "permission.asked":
if (store.session.permission[event.data.sessionID]?.some((request) => request.id === event.data.id)) break
setStore("session", "permission", event.data.sessionID, [
...(store.session.permission[event.data.sessionID] ?? []),
event.data,
])
break
case "permission.v2.replied":
case "permission.replied":
setStore(
"session",
"permission",

View file

@ -1,4 +1,4 @@
import type { KeymapCommand, KeymapLayer } from "@opencode-ai/plugin/v2/tui/context"
import type { KeymapCommand, KeymapLayer } from "@opencode-ai/plugin/tui/context"
import { InputRenderable, TextareaRenderable, type KeyEvent, type Renderable } from "@opentui/core"
import { stringifyKeyStroke, type Binding, type CommandContext } from "@opentui/keymap"
import {
@ -155,7 +155,7 @@ function Provider(props: ParentProps<{ config?: KeymapConfig }>) {
)
}
export type { KeymapCommand, KeymapLayer } from "@opencode-ai/plugin/v2/tui/context"
export type { KeymapCommand, KeymapLayer } from "@opencode-ai/plugin/tui/context"
export interface Keymap {
/** Dispatches a reachable command by ID. */

View file

@ -1,4 +1,4 @@
import type { TuiPlugin, TuiPluginApi, TuiPluginModule } from "@opencode-ai/plugin/tui"
import type { TuiPlugin, TuiPluginApi, TuiPluginModule } from "@opencode-ai/plugin/v1/tui"
import type { PluginRuntime } from "../plugin/runtime"
import Notifications from "./system/notifications"
import PluginManager from "./system/plugins"

View file

@ -1,4 +1,4 @@
import { Plugin } from "@opencode-ai/plugin/v2/tui"
import { Plugin } from "@opencode-ai/plugin/tui"
import { createMemo, Match, Show, Switch } from "solid-js"
import { useTerminalDimensions } from "@opentui/solid"
import { useTuiApp, useTuiPaths } from "../../context/runtime"

View file

@ -1,4 +1,4 @@
import { Plugin } from "@opencode-ai/plugin/v2/tui"
import { Plugin } from "@opencode-ai/plugin/tui"
import { createMemo, Show } from "solid-js"
import { useTheme } from "../../context/theme"
import { contextUsage } from "../../util/session"

View file

@ -1,4 +1,4 @@
import { Plugin } from "@opencode-ai/plugin/v2/tui"
import { Plugin } from "@opencode-ai/plugin/tui"
import { createMemo, Show } from "solid-js"
import { useTuiPaths } from "../../context/runtime"
import { useTheme } from "../../context/theme"

View file

@ -1,4 +1,4 @@
import { Plugin } from "@opencode-ai/plugin/v2/tui"
import { Plugin } from "@opencode-ai/plugin/tui"
import { useTheme } from "../../context/theme"
function View() {

View file

@ -1,4 +1,4 @@
import { Plugin } from "@opencode-ai/plugin/v2/tui"
import { Plugin } from "@opencode-ai/plugin/tui"
import { createMemo, For, Match, Show, Switch, createSignal } from "solid-js"
import { useTheme } from "../../context/theme"

View file

@ -1,7 +1,7 @@
/** @jsxImportSource @opentui/solid */
import type { FileDiffInfo } from "@opencode-ai/client"
import { Plugin } from "@opencode-ai/plugin/v2/tui"
import type { KeymapCommand, Route } from "@opencode-ai/plugin/v2/tui/context"
import { Plugin } from "@opencode-ai/plugin/tui"
import type { KeymapCommand, Route } from "@opencode-ai/plugin/tui/context"
import {
TextAttributes,
type BorderSides,

View file

@ -1,5 +1,5 @@
import type { OpenCodeEvent } from "@opencode-ai/client"
import type { TuiAttentionSoundName, TuiPlugin, TuiPluginApi } from "@opencode-ai/plugin/tui"
import type { TuiAttentionSoundName, TuiPlugin, TuiPluginApi } from "@opencode-ai/plugin/v1/tui"
import type { BuiltinTuiPlugin } from "../builtins"
const id = "internal:notifications"

View file

@ -1,4 +1,4 @@
import type { TuiPlugin, TuiPluginApi, TuiPluginStatus } from "@opencode-ai/plugin/tui"
import type { TuiPlugin, TuiPluginApi, TuiPluginStatus } from "@opencode-ai/plugin/v1/tui"
import type { BuiltinTuiPlugin } from "../builtins"
import { useTerminalDimensions } from "@opentui/solid"
import { fileURLToPath } from "url"

View file

@ -1,4 +1,4 @@
import { Plugin } from "@opencode-ai/plugin/v2/tui"
import { Plugin } from "@opencode-ai/plugin/tui"
import { useTerminalDimensions } from "@opentui/solid"
import { Keymap } from "../../context/keymap"
import { useTheme } from "../../context/theme"

View file

@ -4,7 +4,7 @@ import { useTerminalDimensions } from "@opentui/solid"
import { createEffect, createMemo, createSignal, For, Show } from "solid-js"
import { Keymap } from "../../context/keymap"
import type { ActiveKey } from "@opentui/keymap"
import type { TuiPlugin, TuiPluginApi } from "@opencode-ai/plugin/tui"
import type { TuiPlugin, TuiPluginApi } from "@opencode-ai/plugin/v1/tui"
import type { BuiltinTuiPlugin } from "../builtins"
const command = {

View file

@ -18,7 +18,7 @@
import type {
EventSubscribeOutput,
OpenCodeClient,
PermissionV2Request,
PermissionRequest,
SessionMessageAssistantTool,
SessionMessageInfo,
} from "@opencode-ai/client/promise"
@ -168,14 +168,14 @@ function sourceKey(messageID: string, callID: string) {
return `${messageID}\u0000${callID}`
}
function permissionTool(request: PermissionV2Request, tools: Map<string, SessionMessageAssistantTool>) {
function permissionTool(request: PermissionRequest, tools: Map<string, SessionMessageAssistantTool>) {
if (request.source?.type !== "tool") return request
const tool = tools.get(sourceKey(request.source.messageID, request.source.callID))
return tool ? { ...request, tool } : request
}
function blockerCategory(event: V2Event): "permission" | "form" | undefined {
if (event.type === "permission.v2.asked" || event.type === "permission.v2.replied") return "permission"
if (event.type === "permission.asked" || event.type === "permission.replied") return "permission"
if (event.type === "form.created" || event.type === "form.replied" || event.type === "form.cancelled") return "form"
}
@ -436,7 +436,7 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac
const resolvePermissionTools = async (
sdk: OpenCodeClient,
child: ChildState,
permissions: PermissionV2Request[],
permissions: PermissionRequest[],
epoch: number,
signal = input.signal,
) => {
@ -859,13 +859,13 @@ export function createSubagentTracker(input: SubagentTrackerInput): SubagentTrac
notifyDetail(child)
return
}
if (event.type === "permission.v2.asked") {
if (event.type === "permission.asked") {
if (!child.permissions.some((item) => item.id === event.data.id))
child.permissions.push(permissionTool(event.data, child.toolSources))
input.emit()
return
}
if (event.type === "permission.v2.replied") {
if (event.type === "permission.replied") {
child.permissions = child.permissions.filter((item) => item.id !== event.data.requestID)
input.emit()
return

View file

@ -3,7 +3,7 @@ import type {
FormInfo,
LocationRef,
OpenCodeClient,
PermissionV2Request,
PermissionRequest,
SessionMessageAssistantTool,
SessionMessageInfo,
SessionPendingInfo,
@ -295,7 +295,7 @@ function permissionSourceKey(messageID: string, callID: string) {
return streamPartKey(messageID, callID)
}
function permissionTool(request: PermissionV2Request, tools: Map<string, SessionMessageAssistantTool>) {
function permissionTool(request: PermissionRequest, tools: Map<string, SessionMessageAssistantTool>) {
if (request.source?.type !== "tool") return request
const tool = tools.get(permissionSourceKey(request.source.messageID, request.source.callID))
return tool ? { ...request, tool } : request
@ -715,7 +715,7 @@ export async function createSessionTransport(input: StreamInput): Promise<Sessio
const resolvePermissionSources = async (
client: OpenCodeClient,
permissions: PermissionV2Request[],
permissions: PermissionRequest[],
attempt: Attempt,
) => {
const pending = new Set(
@ -1098,13 +1098,13 @@ export async function createSessionTransport(input: StreamInput): Promise<Sessio
renderTool(event.data.assistantMessageID, item)
return
}
if (event.type === "permission.v2.asked") {
if (event.type === "permission.asked") {
if (!state.permissions.some((item) => item.id === event.data.id))
state.permissions.push(permissionTool(event.data, state.toolSources))
syncBlockers()
return
}
if (event.type === "permission.v2.replied") {
if (event.type === "permission.replied") {
state.permissions = state.permissions.filter((item) => item.id !== event.data.requestID)
pruneToolSources()
syncBlockers()

View file

@ -6,7 +6,7 @@
// the run footer + scrollback color model. Falls back to a hardcoded dark-mode
// palette if detection fails.
import { RGBA, SyntaxStyle, type CliRenderer, type ColorInput, type TerminalColors } from "@opentui/core"
import type { TuiThemeCurrent } from "@opencode-ai/plugin/tui"
import type { TuiThemeCurrent } from "@opencode-ai/plugin/v1/tui"
import { ansiToRgba } from "../theme/color"
import { resolveThemeColors } from "../theme/resolve"
import { terminalMode } from "../theme/system"

View file

@ -17,7 +17,7 @@ import type {
OpenCodeClient,
LocationGetOutput,
LocationRef,
PermissionV2Request,
PermissionRequest,
ReferenceListOutput,
SessionMessageAssistantTool,
} from "@opencode-ai/client/promise"
@ -254,7 +254,7 @@ export type MiniToolPart = {
state: MiniToolState
}
export type MiniPermissionRequest = PermissionV2Request & {
export type MiniPermissionRequest = PermissionRequest & {
tool?: SessionMessageAssistantTool
}

View file

@ -1,4 +1,4 @@
import type { TuiRouteDefinition } from "@opencode-ai/plugin/tui"
import type { TuiRouteDefinition } from "@opencode-ai/plugin/v1/tui"
import { createSignal } from "solid-js"
type RouteEntry = {

View file

@ -1,5 +1,5 @@
// Legacy `api.command` bridge for v1 plugins; remove in v2.
import type { TuiCommand, TuiPluginApi } from "@opencode-ai/plugin/tui"
import type { TuiCommand, TuiPluginApi } from "@opencode-ai/plugin/v1/tui"
import { TuiKeybind } from "../config/keybind"
import type { DialogContext } from "../ui/dialog"

View file

@ -1,4 +1,4 @@
import type { Plugin } from "@opencode-ai/plugin/v2/tui"
import type { Plugin } from "@opencode-ai/plugin/tui"
import {
batch,
createContext,
@ -13,7 +13,7 @@ import {
import path from "path"
import { stat } from "fs/promises"
import { fileURLToPath, pathToFileURL } from "url"
import type { Context, Page, Slot } from "@opencode-ai/plugin/v2/tui/context"
import type { Context, Page, Slot } from "@opencode-ai/plugin/tui/context"
import { createStore, produce, reconcile as reconcileStore } from "solid-js/store"
import { useConfig } from "../config"
import { useClient } from "../context/client"

View file

@ -3,7 +3,7 @@ import type {
TuiPluginInstallOptions,
TuiPluginInstallResult,
TuiPluginStatus,
} from "@opencode-ai/plugin/tui"
} from "@opencode-ai/plugin/v1/tui"
import { createContext, createSignal, useContext, type JSX, type ParentProps } from "solid-js"
import { createPluginRoutes } from "./api"
import { createSlots, type HostSlots } from "./slots"

View file

@ -1,4 +1,4 @@
import type { TuiPluginApi, TuiSlotContext, TuiSlotMap, TuiSlotProps } from "@opencode-ai/plugin/tui"
import type { TuiPluginApi, TuiSlotContext, TuiSlotMap, TuiSlotProps } from "@opencode-ai/plugin/v1/tui"
import { createSlot, createSolidSlotRegistry, type JSX, type SolidPlugin } from "@opentui/solid"
import { createSignal } from "solid-js"
import { isRecord } from "../util/record"

View file

@ -3,7 +3,7 @@ import { createMemo, For, Match, Show, Switch } from "solid-js"
import { Portal, useRenderer, useTerminalDimensions, type JSX } from "@opentui/solid"
import type { TextareaRenderable } from "@opentui/core"
import { useTheme } from "../../context/theme"
import type { PermissionV2Request } from "@opencode-ai/client"
import type { PermissionRequest } from "@opencode-ai/client"
import { useClient } from "../../context/client"
import { SplitBorder } from "../../ui/border"
import { useData } from "../../context/data"
@ -107,7 +107,7 @@ function EditBody(props: { file?: string; diff?: string; patch?: string }) {
)
}
export function PermissionPrompt(props: { request: PermissionV2Request; directory?: string }) {
export function PermissionPrompt(props: { request: PermissionRequest; directory?: string }) {
const client = useClient()
const data = useData()
const [store, setStore] = createStore({