diff --git a/AGENTS.md b/AGENTS.md index 87d59d4c92..3138f6c5ec 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,4 @@ -- To test opencode in the `packages/opencode` directory you can run `bun dev` -- To regenerate the javascript SDK, run ./packages/sdk/js/script/build.ts +- To test opencode in `packages/opencode`, run `bun dev`. +- To regenerate the JavaScript SDK, run `./packages/sdk/js/script/build.ts`. - ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE. -- the default branch in this repo is `dev` +- The default branch in this repo is `dev`. diff --git a/STYLE_GUIDE.md b/STYLE_GUIDE.md index a46ce221fb..52d012fcb9 100644 --- a/STYLE_GUIDE.md +++ b/STYLE_GUIDE.md @@ -1,19 +1,16 @@ ## Style Guide -- Try to keep things in one function unless composable or reusable -- AVOID unnecessary destructuring of variables. instead of doing `const { a, b } -= obj` just reference it as obj.a and obj.b. this preserves context -- AVOID `try`/`catch` where possible -- AVOID using `any` type -- PREFER single word variable names where possible -- Use as many bun apis as possible like Bun.file() +- Keep things in one function unless composable or reusable +- Avoid unnecessary destructuring. Instead of `const { a, b } = obj`, use `obj.a` and `obj.b` to preserve context +- Avoid `try`/`catch` where possible +- Avoid using the `any` type +- Prefer single word variable names where possible +- Use Bun APIs when possible, like `Bun.file()` # Avoid let statements -we don't like let statements, especially combined with if/else statements. -prefer const - -This is bad: +We don't like `let` statements, especially combined with if/else statements. +Prefer `const`. Good: @@ -32,7 +29,7 @@ else foo = 2 # Avoid else statements -Prefer early returns or even using `iife` to avoid else statements +Prefer early returns or using an `iife` to avoid else statements. Good: 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 d5e0a0aa2a..9ad85d08f0 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -563,25 +563,27 @@ export function Prompt(props: PromptProps) { })), }) } else { - sdk.client.session.prompt({ - sessionID, - ...selectedModel, - messageID, - agent: local.agent.current().name, - model: selectedModel, - variant, - parts: [ - { - id: Identifier.ascending("part"), - type: "text", - text: inputText, - }, - ...nonTextParts.map((x) => ({ - id: Identifier.ascending("part"), - ...x, - })), - ], - }) + sdk.client.session + .prompt({ + sessionID, + ...selectedModel, + messageID, + agent: local.agent.current().name, + model: selectedModel, + variant, + parts: [ + { + id: Identifier.ascending("part"), + type: "text", + text: inputText, + }, + ...nonTextParts.map((x) => ({ + id: Identifier.ascending("part"), + ...x, + })), + ], + }) + .catch(() => {}) } history.append({ ...store.prompt, 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 f5b6badb58..c95b42260b 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx @@ -1,6 +1,6 @@ import { createStore } from "solid-js/store" import { createMemo, For, Match, Show, Switch } from "solid-js" -import { useKeyboard, useTerminalDimensions, type JSX } from "@opentui/solid" +import { Portal, useKeyboard, useRenderer, useTerminalDimensions, type JSX } from "@opentui/solid" import type { TextareaRenderable } from "@opentui/core" import { useKeybind } from "../../context/keybind" import { useTheme, selectedForeground } from "../../context/theme" @@ -11,6 +11,7 @@ import { useSync } from "../../context/sync" import { useTextareaKeybindings } from "../../component/textarea-keybindings" import path from "path" import { LANGUAGE_EXTENSIONS } from "@/lsp/language" +import { Keybind } from "@/util/keybind" import { Locale } from "@/util/locale" type PermissionStage = "permission" | "always" | "reject" @@ -32,7 +33,9 @@ function filetype(input?: string) { } function EditBody(props: { request: PermissionRequest }) { - const { theme, syntax } = useTheme() + const themeState = useTheme() + const theme = themeState.theme + const syntax = themeState.syntax const sync = useSync() const dimensions = useTerminalDimensions() @@ -54,7 +57,7 @@ function EditBody(props: { request: PermissionRequest }) { Edit {normalizePath(filepath())} - + - + ) @@ -172,86 +175,95 @@ export function PermissionPrompt(props: { request: PermissionRequest }) { message: message || undefined, }) }} - onCancel={() => setStore("stage", "permission")} + onCancel={() => { + setStore("stage", "permission") + }} /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - } - options={{ once: "Allow once", always: "Allow always", reject: "Reject" }} - escapeKey="reject" - onSelect={(option) => { - if (option === "always") { - setStore("stage", "always") - return - } - if (option === "reject") { - if (session()?.parentID) { - setStore("stage", "reject") - return + {(() => { + const body = ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } - sdk.client.permission.reply({ - reply: "reject", - requestID: props.request.id, - }) - } - sdk.client.permission.reply({ - reply: "once", - requestID: props.request.id, - }) - }} - /> + options={{ once: "Allow once", always: "Allow always", reject: "Reject" }} + escapeKey="reject" + fullscreen + onSelect={(option) => { + if (option === "always") { + setStore("stage", "always") + return + } + if (option === "reject") { + if (session()?.parentID) { + setStore("stage", "reject") + return + } + sdk.client.permission.reply({ + reply: "reject", + requestID: props.request.id, + }) + } + sdk.client.permission.reply({ + reply: "once", + requestID: props.request.id, + }) + }} + /> + ) + + return body + })()} ) @@ -327,14 +339,18 @@ function Prompt>(props: { body: JSX.Element options: T escapeKey?: keyof T + fullscreen?: boolean onSelect: (option: keyof T) => void }) { const { theme } = useTheme() const keybind = useKeybind() + const dimensions = useTerminalDimensions() const keys = Object.keys(props.options) as (keyof T)[] const [store, setStore] = createStore({ selected: keys[0], + expanded: false, }) + const diffKey = Keybind.parse("ctrl+f")[0] useKeyboard((evt) => { if (evt.name === "left" || evt.name == "h") { @@ -360,17 +376,36 @@ function Prompt>(props: { evt.preventDefault() props.onSelect(props.escapeKey) } + + if (props.fullscreen && diffKey && Keybind.match(diffKey, keybind.parse(evt))) { + evt.preventDefault() + evt.stopPropagation() + setStore("expanded", (v) => !v) + } }) - return ( + const hint = createMemo(() => (store.expanded ? "minimize" : "fullscreen")) + const renderer = useRenderer() + + const content = () => ( - - + + {"△"} {props.title} @@ -403,6 +438,11 @@ function Prompt>(props: { + + + {"ctrl+f"} {hint()} + + {"⇆"} select @@ -413,4 +453,10 @@ function Prompt>(props: { ) + + return ( + {content()}}> + {content()} + + ) }