add backend fetch
This commit is contained in:
@@ -68,6 +68,7 @@ import { createTuiAttention } from "@/cli/cmd/tui/attention"
|
||||
import { FormatError, FormatUnknownError } from "@/cli/error"
|
||||
import { CommandPaletteProvider, useCommandPalette } from "./context/command-palette"
|
||||
import { OpencodeKeymapProvider, registerOpencodeKeymap, useBindings, useOpencodeKeymap } from "./keymap"
|
||||
import { DiffViewer } from "./routes/diff"
|
||||
|
||||
import type { EventSource } from "./context/sdk"
|
||||
import { DialogVariant } from "./component/dialog-variant"
|
||||
@@ -102,6 +103,7 @@ const appBindingCommands = [
|
||||
"theme.switch",
|
||||
"theme.switch_mode",
|
||||
"theme.mode.lock",
|
||||
"diff.open",
|
||||
"help.show",
|
||||
"docs.open",
|
||||
"app.debug",
|
||||
@@ -352,6 +354,7 @@ function App(props: { onSnapshot?: () => Promise<string[]> }) {
|
||||
renderer.clearSelection()
|
||||
}
|
||||
const [terminalTitleEnabled, setTerminalTitleEnabled] = createSignal(kv.get("terminal_title_enabled", true))
|
||||
const [diffOpen, setDiffOpen] = createSignal(false)
|
||||
const [pasteSummaryEnabled, setPasteSummaryEnabled] = createSignal(
|
||||
kv.get("paste_summary_enabled", !sync.data.config.experimental?.disable_paste_summary),
|
||||
)
|
||||
@@ -663,6 +666,16 @@ function App(props: { onSnapshot?: () => Promise<string[]> }) {
|
||||
},
|
||||
category: "System",
|
||||
},
|
||||
{
|
||||
name: "diff.open",
|
||||
title: "Open diff viewer",
|
||||
slashName: "diff",
|
||||
run: () => {
|
||||
setDiffOpen(true)
|
||||
dialog.clear()
|
||||
},
|
||||
category: "VCS",
|
||||
},
|
||||
{
|
||||
name: "help.show",
|
||||
title: "Help",
|
||||
@@ -962,6 +975,9 @@ function App(props: { onSnapshot?: () => Promise<string[]> }) {
|
||||
<TuiPluginRuntime.Slot name="app_bottom" />
|
||||
</box>
|
||||
<TuiPluginRuntime.Slot name="app" />
|
||||
<Show when={diffOpen()}>
|
||||
<DiffViewer onClose={() => setDiffOpen(false)} />
|
||||
</Show>
|
||||
</Show>
|
||||
<StartupLoading ready={ready} />
|
||||
</box>
|
||||
|
||||
@@ -67,6 +67,7 @@ export const Definitions = {
|
||||
sidebar_toggle: keybind("<leader>b", "Toggle sidebar"),
|
||||
scrollbar_toggle: keybind("none", "Toggle session scrollbar"),
|
||||
status_view: keybind("<leader>s", "View status"),
|
||||
diff_open: keybind("<leader>d", "Open diff viewer"),
|
||||
|
||||
session_export: keybind("<leader>x", "Export session to editor"),
|
||||
session_copy: keybind("none", "Copy session transcript"),
|
||||
@@ -251,6 +252,7 @@ export const CommandMap = {
|
||||
sidebar_toggle: "session.sidebar.toggle",
|
||||
scrollbar_toggle: "session.toggle.scrollbar",
|
||||
status_view: "opencode.status",
|
||||
diff_open: "diff.open",
|
||||
session_export: "session.export",
|
||||
session_copy: "session.copy",
|
||||
session_new: "session.new",
|
||||
|
||||
@@ -152,6 +152,12 @@ const ScriptActionSchema = z.union([
|
||||
|
||||
const ScriptSchema = z.union([z.array(ScriptActionSchema), z.object({ actions: z.array(ScriptActionSchema) })])
|
||||
const TargetSchema = z.union([z.string(), z.array(z.string()).min(1), z.literal("all")])
|
||||
const BackendFetchSchema = z.object({
|
||||
url: z.string(),
|
||||
method: z.string().optional(),
|
||||
headers: z.record(z.string(), z.string()).optional(),
|
||||
body: z.unknown().optional(),
|
||||
})
|
||||
const remoteInstances = new Map<string, RemoteInstance>()
|
||||
|
||||
function currentBuffer(renderer: CliRenderer): RenderBuffer {
|
||||
@@ -264,6 +270,27 @@ async function control(options: Options, method: string, pathname: string, body?
|
||||
throw new Error(typeof data?.error === "string" ? data.error : `Simulation control request failed: ${response.status}`)
|
||||
}
|
||||
|
||||
async function backendFetch(options: Options, input: z.infer<typeof BackendFetchSchema>) {
|
||||
const running = current(options)
|
||||
const headers = new Headers(input.headers)
|
||||
const body =
|
||||
input.body === undefined ? undefined : typeof input.body === "string" ? input.body : JSON.stringify(input.body)
|
||||
if (body !== undefined && !headers.has("content-type") && typeof input.body !== "string") headers.set("content-type", "application/json")
|
||||
|
||||
const response = await (running.controlFetch ?? fetch)(new URL(input.url, running.controlUrl), {
|
||||
method: input.method ?? (body === undefined ? "GET" : "POST"),
|
||||
headers,
|
||||
body,
|
||||
})
|
||||
return {
|
||||
url: response.url,
|
||||
status: response.status,
|
||||
ok: response.ok,
|
||||
headers: Object.fromEntries(response.headers.entries()),
|
||||
body: await response.text(),
|
||||
}
|
||||
}
|
||||
|
||||
async function mcpRequest(url: string, method: string, params: unknown, timeout = 500) {
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
@@ -431,6 +458,14 @@ function createServer(options: Options) {
|
||||
await current(options).harness.renderOnce()
|
||||
return toolResult(snapshot(options))
|
||||
})
|
||||
server.registerTool(
|
||||
"simulation_backend_fetch",
|
||||
{
|
||||
description: "Proxy one fetch request through the simulated backend and return the raw response.",
|
||||
inputSchema: BackendFetchSchema,
|
||||
},
|
||||
async (input) => toolResult(await backendFetch(options, input)),
|
||||
)
|
||||
server.registerTool(
|
||||
"simulation_action_execute",
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user