diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 923fa3a21..986fbf144 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -8,7 +8,8 @@ "typecheck": "tsc --noEmit", "test": "bun test", "build": "./script/build.ts", - "dev": "bun run --conditions=browser ./src/index.ts" + "dev": "bun run --conditions=browser ./src/index.ts", + "random": "echo 'This is a random script'" }, "bin": { "opencode": "./bin/opencode" 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 44e623654..5577047b0 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -224,15 +224,17 @@ export function Autocomplete(props: { if (e.name === "escape") hide() if (e.name === "return") select() } - if (!store.visible && e.name === "@") { - const last = props.value.at(-1) - if (last === " " || last === undefined) { - show("@") + if (!store.visible) { + if (e.name === "@") { + const last = props.value.at(-1) + if (last === " " || last === undefined) { + show("@") + } } - } - if (!store.visible && e.name === "/") { - if (props.input().cursorPosition === 0) show("/") + if (e.name === "/") { + if (props.input().cursorPosition === 0) show("/") + } } }, }) 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 53e3a61f5..be165498e 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -33,7 +33,6 @@ export function Prompt(props: PromptProps) { let anchor: BoxRenderable let autocomplete: AutocompleteRef - const keybind = useKeybind() const local = useLocal() const sdk = useSDK() @@ -42,6 +41,11 @@ export function Prompt(props: PromptProps) { const status = createMemo(() => (props.sessionID ? sync.session.status(props.sessionID) : "idle")) const history = usePromptHistory() + createEffect(() => { + if (props.disabled) input.cursorColor = Theme.backgroundElement + if (!props.disabled) input.cursorColor = Theme.primary + }) + const [store, setStore] = createStore({ input: "", parts: [], @@ -129,6 +133,10 @@ export function Prompt(props: PromptProps) { }} value={store.input} onKeyDown={async (e) => { + if (props.disabled) { + e.preventDefault() + return + } autocomplete.onKeyDown(e) if (!autocomplete.visible) { if (e.name === "up" || e.name === "down") { @@ -166,6 +174,7 @@ export function Prompt(props: PromptProps) { }, 0) }} onSubmit={async () => { + if (props.disabled) return if (autocomplete.visible) return if (!store.input) return const sessionID = props.sessionID 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 5f849ca8b..e63582049 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -177,7 +177,8 @@ export function Session() { value: "session.redo", keybind: "messages_redo", category: "Session", - onSelect: () => { + onSelect: (dialog) => { + dialog.clear() const messageID = session().revert?.messageID if (!messageID) return const message = messages().find((x) => x.role === "user" && x.id > messageID) @@ -295,7 +296,7 @@ export function Session() { + onMouseUp={() => dialog.replace(() => ) } message={message as UserMessage} @@ -327,6 +328,7 @@ export function Session() { (prompt = r)} + disabled={permissions().length > 0} onSubmit={() => { toBottom() }} @@ -347,7 +349,7 @@ const MIME_BADGE: Record = { "application/pdf": "pdf", } -function UserMessage(props: { message: UserMessage; parts: Part[]; onMouseDown: () => void }) { +function UserMessage(props: { message: UserMessage; parts: Part[]; onMouseUp: () => void }) { const text = createMemo(() => props.parts.flatMap((x) => (x.type === "text" && !x.synthetic ? [x] : []))[0]) const files = createMemo(() => props.parts.flatMap((x) => (x.type === "file" ? [x] : []))) const sync = useSync() @@ -361,7 +363,7 @@ function UserMessage(props: { message: UserMessage; parts: Part[]; onMouseDown: onMouseOut={() => { setHover(false) }} - onMouseDown={props.onMouseDown} + onMouseUp={props.onMouseUp} border={["left"]} paddingTop={1} paddingBottom={1} diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx index 3e6091913..6224f03ee 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog.tsx @@ -99,7 +99,7 @@ function init() { refocus() }, replace(input: any, onClose?: () => void) { - focus = renderer.currentFocusedRenderable + if (store.stack.length === 0) focus = renderer.currentFocusedRenderable for (const item of store.stack) { if (item.onClose) item.onClose() }