feat: hooks

This commit is contained in:
Gab
2026-03-27 14:00:04 +11:00
parent 8e05565e84
commit c39a97bb7d
12 changed files with 208 additions and 10 deletions

View File

@@ -0,0 +1,78 @@
import { useQuery } from "@tanstack/solid-query"
import { Component, createMemo, Show } from "solid-js"
import { useSDK } from "@/context/sdk"
import { useDialog } from "@opencode-ai/ui/context/dialog"
import { Dialog } from "@opencode-ai/ui/dialog"
import { List } from "@opencode-ai/ui/list"
import { useLanguage } from "@/context/language"
import { useLocal } from "@/context/local"
import { usePrompt, type Prompt } from "@/context/prompt"
import type { AppPromptsResponse } from "@opencode-ai/sdk/v2"
export const DialogSelectPrompt: Component = () => {
const sdk = useSDK()
const dialog = useDialog()
const language = useLanguage()
const local = useLocal()
const prompt = usePrompt()
const promptsQuery = useQuery(() => ({
queryKey: ["prompts"],
queryFn: async () => {
const result = await sdk.client.app.prompts()
return result.data as AppPromptsResponse
},
}))
const currentAgent = createMemo(() => local.agent.current())
const tfAgentId = createMemo(() => currentAgent()?.options?.tf_agent_id as string | undefined)
const prompts = createMemo(() => {
const all = promptsQuery.data ?? []
const agentId = tfAgentId()
if (!agentId) return []
return all.filter((p) => p.available_to_agents?.includes(agentId))
})
const applyPrompt = (p: { interpolation_string: string }) => {
const text = p.interpolation_string
const parts: Prompt = [{ type: "text", content: text, start: 0, end: text.length }]
prompt.set(parts, text.length)
dialog.close()
}
return (
<Dialog
title={language.t("dialog.prompt.title")}
description={language.t("dialog.prompt.description", {
agent: currentAgent()?.name ?? "",
})}
>
<Show
when={!promptsQuery.isLoading}
fallback={<div class="p-4 text-center">{language.t("common.loading.ellipsis")}</div>}
>
<List
search={{ placeholder: language.t("common.search.placeholder"), autofocus: true }}
emptyMessage={language.t("dialog.prompt.empty")}
key={(x) => x?.id ?? ""}
items={prompts}
filterKeys={["label", "description"]}
sortBy={(a, b) => a.label.localeCompare(b.label)}
onSelect={(x) => {
if (x) applyPrompt(x)
}}
>
{(i) => (
<div class="w-full flex flex-col gap-0.5 min-w-0">
<span class="truncate text-13-medium">{i.label}</span>
<Show when={i.description}>
<span class="text-11-regular text-text-weaker truncate">{i.description}</span>
</Show>
</div>
)}
</List>
</Show>
</Dialog>
)
}

View File

@@ -69,6 +69,8 @@ export const dict = {
"command.agent.cycle.description": "Switch to the next agent",
"command.agent.cycle.reverse": "Cycle agent backwards",
"command.agent.cycle.reverse.description": "Switch to the previous agent",
"command.prompts.select": "Select prompt",
"command.prompts.select.description": "Select a ToothFairyAI prompt for the current agent",
"command.model.variant.cycle": "Cycle thinking effort",
"command.model.variant.cycle.description": "Switch to the next effort level",
"command.prompt.mode.shell": "Shell",
@@ -296,6 +298,10 @@ export const dict = {
"dialog.mcp.description": "{{enabled}} of {{total}} enabled",
"dialog.mcp.empty": "No MCPs configured",
"dialog.prompt.title": "Select prompt",
"dialog.prompt.description": "Prompts for {{agent}}",
"dialog.prompt.empty": "No prompts available for this agent",
"dialog.lsp.empty": "LSPs auto-detected from file types",
"dialog.plugins.empty": "Plugins configured in opencode.json",

View File

@@ -14,6 +14,7 @@ import { useTerminal } from "@/context/terminal"
import { DialogSelectFile } from "@/components/dialog-select-file"
import { DialogSelectModel } from "@/components/dialog-select-model"
import { DialogSelectMcp } from "@/components/dialog-select-mcp"
import { DialogSelectPrompt } from "@/components/dialog-select-prompt"
import { DialogFork } from "@/components/dialog-fork"
import { showToast } from "@opencode-ai/ui/toast"
import { findLast } from "@opencode-ai/util/array"
@@ -376,6 +377,13 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
keybind: "shift+mod+.",
onSelect: () => local.agent.move(-1),
}),
agentCommand({
id: "prompts.select",
title: language.t("command.prompts.select"),
description: language.t("command.prompts.select.description"),
slash: "prompts",
onSelect: () => dialog.show(() => <DialogSelectPrompt />),
}),
modelCommand({
id: "model.variant.cycle",
title: language.t("command.model.variant.cycle"),