Просмотр исходного кода

feat: add skill dialog for selecting and inserting skills (#11547)

Dax 3 недель назад
Родитель
Сommit
5b784871f0

+ 34 - 0
packages/opencode/src/cli/cmd/tui/component/dialog-skill.tsx

@@ -0,0 +1,34 @@
+import { DialogSelect, type DialogSelectOption } from "@tui/ui/dialog-select"
+import { createResource, createMemo } from "solid-js"
+import { useDialog } from "@tui/ui/dialog"
+import { useSDK } from "@tui/context/sdk"
+
+export type DialogSkillProps = {
+  onSelect: (skill: string) => void
+}
+
+export function DialogSkill(props: DialogSkillProps) {
+  const dialog = useDialog()
+  const sdk = useSDK()
+
+  const [skills] = createResource(async () => {
+    const result = await sdk.client.app.skills()
+    return result.data ?? []
+  })
+
+  const options = createMemo<DialogSelectOption<string>[]>(() => {
+    const list = skills() ?? []
+    return list.map((skill) => ({
+      title: skill.name,
+      description: skill.description,
+      value: skill.name,
+      category: "Skills",
+      onSelect: () => {
+        props.onSelect(skill.name)
+        dialog.clear()
+      },
+    }))
+  })
+
+  return <DialogSelect title="Skills" placeholder="Search skills..." options={options()} />
+}

+ 2 - 1
packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx

@@ -345,7 +345,8 @@ export function Autocomplete(props: {
     const results: AutocompleteOption[] = [...command.slashes()]
 
     for (const serverCommand of sync.data.command) {
-      const label = serverCommand.source === "mcp" ? ":mcp" : serverCommand.source === "skill" ? ":skill" : ""
+      if (serverCommand.source === "skill") continue
+      const label = serverCommand.source === "mcp" ? ":mcp" : ""
       results.push({
         display: "/" + serverCommand.name + label,
         description: serverCommand.description,

+ 23 - 0
packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx

@@ -31,6 +31,7 @@ import { DialogAlert } from "../../ui/dialog-alert"
 import { useToast } from "../../ui/toast"
 import { useKV } from "../../context/kv"
 import { useTextareaKeybindings } from "../textarea-keybindings"
+import { DialogSkill } from "../dialog-skill"
 
 export type PromptProps = {
   sessionID?: string
@@ -315,6 +316,28 @@ export function Prompt(props: PromptProps) {
           input.cursorOffset = Bun.stringWidth(content)
         },
       },
+      {
+        title: "Skills",
+        value: "prompt.skills",
+        category: "Prompt",
+        slash: {
+          name: "skills",
+        },
+        onSelect: () => {
+          dialog.replace(() => (
+            <DialogSkill
+              onSelect={(skill) => {
+                input.setText(`/${skill} `)
+                setStore("prompt", {
+                  input: `/${skill} `,
+                  parts: [],
+                })
+                input.gotoBufferEnd()
+              }}
+            />
+          ))
+        },
+      },
     ]
   })