Преглед изворни кода

tui: add escape key handling to permission dialogs for better keyboard navigation

Dax Raad пре 1 месец
родитељ
комит
4956ee3ebd

+ 11 - 1
packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx

@@ -1,6 +1,7 @@
 import { createStore } from "solid-js/store"
 import { createMemo, For, Match, Show, Switch } from "solid-js"
 import { useKeyboard, useTerminalDimensions, type JSX } from "@opentui/solid"
+import { useKeybind } from "../../context/keybind"
 import { useTheme } from "../../context/theme"
 import type { PermissionRequest } from "@opencode-ai/sdk/v2"
 import { useSDK } from "../../context/sdk"
@@ -145,6 +146,7 @@ export function PermissionPrompt(props: { request: PermissionRequest }) {
             </Switch>
           }
           options={{ confirm: "Confirm", cancel: "Cancel" }}
+          escapeKey="cancel"
           onSelect={(option) => {
             setStore("always", false)
             if (option === "cancel") return
@@ -199,7 +201,7 @@ export function PermissionPrompt(props: { request: PermissionRequest }) {
                 <TextBody icon="◇" title={`Exa Code Search "` + (input().query ?? "") + `"`} />
               </Match>
               <Match when={props.request.permission === "external_directory"}>
-                <TextBody icon="" title={`Access external directory ` + normalizePath(input().path as string)} />
+                <TextBody icon="" title={`Access external directory ` + normalizePath(input().path as string)} />
               </Match>
               <Match when={props.request.permission === "doom_loop"}>
                 <TextBody icon="⟳" title="Continue after repeated failures" />
@@ -210,6 +212,7 @@ export function PermissionPrompt(props: { request: PermissionRequest }) {
             </Switch>
           }
           options={{ once: "Allow once", always: "Allow always", reject: "Reject" }}
+          escapeKey="reject"
           onSelect={(option) => {
             if (option === "always") {
               setStore("always", true)
@@ -230,9 +233,11 @@ function Prompt<const T extends Record<string, string>>(props: {
   title: string
   body: JSX.Element
   options: T
+  escapeKey?: keyof T
   onSelect: (option: keyof T) => void
 }) {
   const { theme } = useTheme()
+  const keybind = useKeybind()
   const keys = Object.keys(props.options) as (keyof T)[]
   const [store, setStore] = createStore({
     selected: keys[0],
@@ -257,6 +262,11 @@ function Prompt<const T extends Record<string, string>>(props: {
       evt.preventDefault()
       props.onSelect(store.selected)
     }
+
+    if (props.escapeKey && (evt.name === "escape" || keybind.match("app_exit", evt))) {
+      evt.preventDefault()
+      props.onSelect(props.escapeKey)
+    }
   })
 
   return (

+ 1 - 30
packages/opencode/src/server/server.ts

@@ -2721,39 +2721,10 @@ export namespace Server {
         const response = await proxy(`https://app.opencode.ai${path}`, {
           ...c.req,
           headers: {
+            ...c.req.raw.headers,
             host: "app.opencode.ai",
           },
         })
-        // Cloudflare doesn't return Content-Type for static assets, so we need to add it
-        const mimeTypes: Record<string, string> = {
-          ".js": "application/javascript",
-          ".mjs": "application/javascript",
-          ".css": "text/css",
-          ".json": "application/json",
-          ".wasm": "application/wasm",
-          ".svg": "image/svg+xml",
-          ".png": "image/png",
-          ".jpg": "image/jpeg",
-          ".jpeg": "image/jpeg",
-          ".gif": "image/gif",
-          ".ico": "image/x-icon",
-          ".webp": "image/webp",
-          ".woff": "font/woff",
-          ".woff2": "font/woff2",
-          ".ttf": "font/ttf",
-          ".eot": "application/vnd.ms-fontobject",
-        }
-        for (const [ext, mime] of Object.entries(mimeTypes)) {
-          if (path.endsWith(ext)) {
-            const headers = new Headers(response.headers)
-            headers.set("Content-Type", mime)
-            return new Response(response.body, {
-              status: response.status,
-              statusText: response.statusText,
-              headers,
-            })
-          }
-        }
         return response
       }),
   )

+ 2 - 1
packages/opencode/src/tool/bash.ts

@@ -1,6 +1,7 @@
 import z from "zod"
 import { spawn } from "child_process"
 import { Tool } from "./tool"
+import path from "path"
 import DESCRIPTION from "./bash.txt"
 import { Log } from "../util/log"
 import { Instance } from "../project/instance"
@@ -136,7 +137,7 @@ export const BashTool = Tool.define("bash", async () => {
         await ctx.ask({
           permission: "external_directory",
           patterns: Array.from(directories),
-          always: Array.from(directories).map((x) => x + "*"),
+          always: Array.from(directories).map((x) => path.dirname(x) + "*"),
           metadata: {},
         })
       }