diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx index 0c158a39a..e3d93822c 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -105,17 +105,28 @@ export function Autocomplete(props: { const agents = createMemo(() => { if (store.index !== 0) return [] const agents = sync.data.agent - return agents.map( - (agent): AutocompleteOption => ({ - display: "@" + agent.name, - onSelect: () => { - props.setPrompt((draft) => { - const append = "@" + agent.name + " " - draft.input = append - }) - }, - }), - ) + return agents + .filter((agent) => !agent.builtIn && agent.mode !== "primary") + .map( + (agent): AutocompleteOption => ({ + display: "@" + agent.name, + onSelect: () => { + props.setPrompt((draft) => { + const append = "@" + agent.name + " " + draft.input = append + draft.parts.push({ + type: "agent", + source: { + start: store.index, + end: store.index + agent.name.length + 1, + value: "@" + agent.name, + }, + name: agent.name, + }) + }) + }, + }), + ) }) const session = createMemo(() => (props.sessionID ? sync.session.get(props.sessionID) : undefined)) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/history.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/history.tsx index d1fe6f4dc..6e1b6d63d 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/history.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/history.tsx @@ -5,11 +5,11 @@ import { createStore, produce } from "solid-js/store" import { clone } from "remeda" import { createSimpleContext } from "../../context/helper" import { appendFile } from "fs/promises" -import type { FilePart } from "@opencode-ai/sdk" +import type { AgentPart, FilePart } from "@opencode-ai/sdk" export type PromptInfo = { input: string - parts: Omit[] + parts: (Omit | Omit)[] } export const { use: usePromptHistory, provider: PromptHistoryProvider } = createSimpleContext({ diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index be165498e..ed1883b99 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -12,6 +12,7 @@ import { useKeybind } from "@tui/context/keybind" import { Clipboard } from "@/util/clipboard" import { usePromptHistory, type PromptInfo } from "./history" import { type AutocompleteRef, Autocomplete } from "./autocomplete" +import { iife } from "@/util/iife" export type PromptProps = { sessionID?: string @@ -113,17 +114,17 @@ export function Prompt(props: PromptProps) { for (let i = 0; i < draft.parts.length; i++) { const part = draft.parts[i] if (!part.source) continue - if (part.source.text.start >= input.cursorPosition) { - part.source.text.start += diff - part.source.text.end += diff + const source = part.type === "agent" ? part.source : part.source.text + if (source.start >= input.cursorPosition) { + source.start += diff + source.end += diff } - const sliced = draft.input.slice(part.source.text.start, part.source.text.end) - if (sliced != part.source.text.value && diff < 0) { - diff -= part.source.text.value.length - draft.input = - draft.input.slice(0, part.source.text.start) + draft.input.slice(part.source.text.end) + const sliced = draft.input.slice(source.start, source.end) + if (sliced != source.value && diff < 0) { + diff -= source.value.length + draft.input = draft.input.slice(0, source.start) + draft.input.slice(source.end) draft.parts.splice(i, 1) - input.cursorPosition = Math.max(0, part.source.text.start - 1) + input.cursorPosition = Math.max(0, source.start - 1) i-- } } @@ -160,13 +161,18 @@ export function Prompt(props: PromptProps) { const position = input.cursorPosition const direction = Math.sign(old - position) for (const part of store.parts) { - if (part.source && part.source.type === "file") { - if (position >= part.source.text.start && position < part.source.text.end) { + const source = iife(() => { + if (part.type === "agent") return part.source + if (part.type === "file") return part.source?.text + return + }) + if (source) { + if (position >= source.start && position < source.end) { if (direction === 1) { - input.cursorPosition = Math.max(0, part.source.text.start - 1) + input.cursorPosition = Math.max(0, source.start - 1) } if (direction === -1) { - input.cursorPosition = part.source.text.end + input.cursorPosition = source.end } } }