Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
281e58b
feat: add keybind support for custom slash commands
ariane-emory Dec 17, 2025
326718d
fix: handle undefined values in command keybind parsing
ariane-emory Dec 17, 2025
ac4ba7f
feat: preserve prompt text as command arguments in keybind execution
ariane-emory Dec 18, 2025
db95d88
Merge dev branch, resolving types.gen.ts conflict
ariane-emory Dec 18, 2025
0db39ae
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 19, 2025
271fa87
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 19, 2025
6fb751c
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 20, 2025
576aedf
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 20, 2025
7a283f5
fix: remove unused sdk variable in app.tsx
ariane-emory Dec 21, 2025
1a8503d
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 21, 2025
6945498
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 21, 2025
f125cdd
Merge branch 'dev' into feat/revise-keybindable-commands
ariane-emory Dec 24, 2025
69aaecc
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 24, 2025
1f55399
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 25, 2025
5e75dce
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 25, 2025
87fa148
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 25, 2025
894d6b4
Merge branch 'feat/keybindable-commands' of github.com:ariane-emory/o…
ariane-emory Dec 25, 2025
0c74d2e
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 25, 2025
c202342
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 26, 2025
d84172f
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 27, 2025
4e24e58
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 27, 2025
0f15eaf
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 27, 2025
3c88bd0
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 28, 2025
83bd58c
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 28, 2025
16e2c5c
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 28, 2025
d2fb915
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 28, 2025
43d5ba5
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 29, 2025
204e364
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 29, 2025
957efa5
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 29, 2025
3610824
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 29, 2025
57dd926
Merge branch 'feat/keybindable-commands' of github.com:ariane-emory/o…
ariane-emory Dec 29, 2025
0f1c159
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 29, 2025
de30a11
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 30, 2025
5ed8a2d
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 30, 2025
1af69d7
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 30, 2025
9b4f1d8
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 30, 2025
3ee1722
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 30, 2025
ea70b3b
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Dec 31, 2025
15dd7b4
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 1, 2026
5a1d2d3
Fix type compatibility for vercel provider after merge
ariane-emory Jan 1, 2026
05c365e
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 1, 2026
ffdb21d
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 1, 2026
7fdf121
revert a file
ariane-emory Jan 1, 2026
967b56f
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 2, 2026
436e498
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 3, 2026
b78d6a7
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 3, 2026
73b8aa0
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 4, 2026
af2d255
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 4, 2026
9d4e527
Fix type compatibility with Vercel AI SDK provider
ariane-emory Jan 4, 2026
1259bf7
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 4, 2026
12a6bbe
revert a file
ariane-emory Jan 4, 2026
f955d36
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 5, 2026
8b26298
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 5, 2026
b59a839
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 5, 2026
312703c
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 5, 2026
5f89e61
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 6, 2026
64c0e6b
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 6, 2026
7a19c02
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 6, 2026
da9cd02
fix: ensure 'name' isnt being sent in request body for custom agent
rekram1-node Jan 6, 2026
ad6afc2
test: fix test
rekram1-node Jan 6, 2026
ebf49f9
Merge remote-tracking branch 'origin/dev' into feat/keybindable-commands
ariane-emory Jan 6, 2026
eeff78f
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 6, 2026
4f91e4f
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 6, 2026
f8c4f44
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 7, 2026
b847a8f
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 7, 2026
717ba4c
Merge branch 'feat/keybindable-commands' of github.com:ariane-emory/o…
ariane-emory Jan 7, 2026
5431159
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 7, 2026
42d58e3
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 7, 2026
e6f8045
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 7, 2026
04ba91e
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 8, 2026
4047e52
Merge branch 'dev' into feat/keybindable-commands
ariane-emory Jan 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 54 additions & 1 deletion packages/opencode/src/cli/cmd/tui/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { DialogHelp } from "./ui/dialog-help"
import { CommandProvider, useCommandDialog } from "@tui/component/dialog-command"
import { DialogAgent } from "@tui/component/dialog-agent"
import { DialogSessionList } from "@tui/component/dialog-session-list"
import { KeybindProvider } from "@tui/context/keybind"
import { KeybindProvider, useKeybind } from "@tui/context/keybind"
import { ThemeProvider, useTheme } from "@tui/context/theme"
import { Home } from "@tui/routes/home"
import { Session } from "@tui/routes/session"
Expand All @@ -36,6 +36,7 @@ import { ArgsProvider, useArgs, type Args } from "./context/args"
import open from "open"
import { writeHeapSnapshot } from "v8"
import { PromptRefProvider, usePromptRef } from "./context/prompt"
import { Keybind } from "@/util/keybind"

async function getTerminalBackgroundColor(): Promise<"dark" | "light"> {
// can't set raw mode if not a TTY
Expand Down Expand Up @@ -195,6 +196,7 @@ function App() {
const sync = useSync()
const exit = useExit()
const promptRef = usePromptRef()
const keybind = useKeybind()

// Wire up console copy-to-clipboard via opentui's onCopySelection callback
renderer.console.onCopySelection = async (text: string) => {
Expand Down Expand Up @@ -540,6 +542,57 @@ function App() {
},
])

// Handle custom command keybinds
useKeyboard((evt) => {
if (command.suspended()) return
if (dialog.stack.length > 0) return
if (evt.defaultPrevented) return

const keybinds = sync.data.config.keybinds ?? {}
for (const [key, value] of Object.entries(keybinds)) {
if (!key.startsWith("/")) continue
if (!value) continue

const commandName = key.slice(1)
const commandKeybinds = Keybind.parse(value)
const parsed = keybind.parse(evt)

for (const kb of commandKeybinds) {
if (Keybind.match(kb, parsed)) {
evt.preventDefault()

// Find the command to verify it exists
const cmd = sync.data.command.find((c) => c.name === commandName)
if (!cmd) {
toast.show({
variant: "error",
message: `Command not found: ${commandName}`,
duration: 3000,
})
return
}

// Preserve existing prompt text as command arguments
const current = promptRef.current
if (current) {
const existingInput = current.current.input.trim()
const commandInput = existingInput
? `/${commandName} ${existingInput}`
: `/${commandName}`

current.set({
input: commandInput,
parts: current.current.parts,
})
current.submit()
}

return
}
}
}
})

createEffect(() => {
const currentModel = local.model.current()
if (!currentModel) return
Expand Down
2 changes: 1 addition & 1 deletion packages/opencode/src/cli/cmd/tui/context/keybind.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const { use: useKeybind, provider: KeybindProvider } = createSimpleContex
const keybinds = createMemo(() => {
return pipe(
sync.data.config.keybinds ?? {},
mapValues((value) => Keybind.parse(value)),
mapValues((value) => (value ? Keybind.parse(value) : [])),
)
})
const [store, setStore] = createStore({
Expand Down
2 changes: 1 addition & 1 deletion packages/opencode/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,7 @@ export namespace Config {
terminal_title_toggle: z.string().optional().default("none").describe("Toggle terminal title"),
tips_toggle: z.string().optional().default("<leader>h").describe("Toggle tips on home screen"),
})
.strict()
.catchall(z.string())
.meta({
ref: "KeybindsConfig",
})
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/js/src/v2/gen/types.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1253,6 +1253,7 @@ export type KeybindsConfig = {
* Toggle tips on home screen
*/
tips_toggle?: string
[key: string]: string | undefined
}

/**
Expand Down