Compare commits

...
Author SHA1 Message Date
Ryan Vogelandopencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> f32acba470 feat(tui): undo recent prompt with double escape
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
2026-07-12 17:48:37 +00:00
opencode-agent[bot]GitHubDaxopencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
34e5809059 feat(tui): show idle session directory (#36457)
Co-authored-by: Dax <mail@thdxr.com>
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
2026-07-11 20:31:57 +00:00
2db96c9b7e fix(core): disable unused fff content caches (#36453)
Co-authored-by: Dax Raad <d@ironbay.co>
2026-07-11 19:12:58 +00:00
4 changed files with 81 additions and 2 deletions
+2
View File
@@ -128,6 +128,8 @@ export const fffLayer = Layer.effect(
Fff.create({
basePath: location.directory,
aiMode: true,
disableMmapCache: true,
disableContentIndexing: true,
}),
catch: (cause) => cause,
}).pipe(
+33 -2
View File
@@ -56,6 +56,9 @@ import { useTuiConfig } from "../../config"
import { usePromptWorkspace } from "./workspace"
import { usePromptMove } from "./move"
import { readLocalAttachment } from "./local-attachment"
import { useLocation } from "../../context/location"
import { Identifier } from "@opencode-ai/core/id/id"
import { createQuickUndo } from "./quick-undo"
registerOpencodeSpinner()
@@ -148,6 +151,7 @@ export function Prompt(props: PromptProps) {
const local = useLocal()
const args = useArgs()
const paths = useTuiPaths()
const location = useLocation()
const terminalEnvironment = useTuiTerminalEnvironment()
const clipboard = useClipboard()
const sdk = useSDK()
@@ -294,6 +298,7 @@ export function Prompt(props: PromptProps) {
extmarkToPartIndex: new Map(),
interrupt: 0,
})
const quickUndo = createQuickUndo<PromptInfo>()
createEffect(
on(
@@ -392,7 +397,7 @@ export function Prompt(props: PromptProps) {
category: "Session",
hidden: true,
enabled: status().type !== "idle",
run: () => {
run: async () => {
if (auto()?.visible) return
if (!input.focused) return
// TODO: this should be its own command
@@ -402,6 +407,18 @@ export function Prompt(props: PromptProps) {
}
if (!props.sessionID) return
const recent = quickUndo.escape()
if (recent) {
await sdk.client.session.abort({ sessionID: props.sessionID }).catch(() => {})
await sdk.client.session.revert({ sessionID: props.sessionID, messageID: recent.messageID })
input.setText(recent.value.input)
setStore("prompt", recent.value)
restoreExtmarksFromParts(recent.value.parts)
input.gotoBufferEnd()
input.focus()
return
}
setStore("interrupt", store.interrupt + 1)
setTimeout(() => {
@@ -1087,11 +1104,17 @@ export function Prompt(props: PromptProps) {
parts: nonTextParts.filter((x) => x.type === "file"),
})
} else {
const messageID = Identifier.ascending("message")
quickUndo.submitted(messageID, {
input: store.prompt.input,
parts: [...unwrap(store.prompt.parts)],
})
move.startSubmit()
sdk.client.session
.prompt(
{
sessionID,
messageID,
...selectedModel,
agent: agent.name,
model: selectedModel,
@@ -1637,7 +1660,15 @@ export function Prompt(props: PromptProps) {
<text fg={theme.accent}>(new working copy)</text>
</box>
</Match>
<Match when={true}>{props.hint ?? <text />}</Match>
<Match when={true}>
{props.hint ?? (
<Show when={props.sessionID}>
<box marginLeft={1}>
<text fg={theme.textMuted}>{location()?.directory ?? paths.cwd}</text>
</box>
</Show>
)}
</Match>
</Switch>
<Show when={status().type !== "retry"}>
<box gap={2} flexDirection="row">
@@ -0,0 +1,21 @@
import { describe, expect, test } from "bun:test"
import { createQuickUndo } from "./quick-undo"
describe("quick undo", () => {
test("returns the submitted message on a second escape within two seconds", () => {
const undo = createQuickUndo<string>()
undo.submitted("msg_1", "hello", 1_000)
expect(undo.escape(1_500)).toBeUndefined()
expect(undo.escape(1_750)).toEqual({ messageID: "msg_1", value: "hello" })
expect(undo.escape(1_800)).toBeUndefined()
})
test("expires two seconds after submission", () => {
const undo = createQuickUndo<string>()
undo.submitted("msg_1", "hello", 1_000)
expect(undo.escape(2_500)).toBeUndefined()
expect(undo.escape(3_001)).toBeUndefined()
})
})
@@ -0,0 +1,25 @@
const WINDOW_MS = 2_000
export function createQuickUndo<T>() {
let submitted: { messageID: string; value: T; time: number } | undefined
let escapedAt: number | undefined
return {
submitted(messageID: string, value: T, time = Date.now()) {
submitted = { messageID, value, time }
escapedAt = undefined
},
escape(time = Date.now()) {
if (!submitted || time - submitted.time > WINDOW_MS) return
if (escapedAt === undefined || time - escapedAt > WINDOW_MS) {
escapedAt = time
return
}
const result = { messageID: submitted.messageID, value: submitted.value }
submitted = undefined
escapedAt = undefined
return result
},
}
}