Merge remote-tracking branch 'origin/sqlite2' into sqlite2
This commit is contained in:
@@ -307,7 +307,7 @@ export const AuthLoginCommand = cmd({
|
||||
|
||||
if (prompts.isCancel(provider)) throw new UI.CancelledError()
|
||||
|
||||
const plugin = await Plugin.list().then((x) => x.find((x) => x.auth?.provider === provider))
|
||||
const plugin = await Plugin.list().then((x) => x.findLast((x) => x.auth?.provider === provider))
|
||||
if (plugin && plugin.auth) {
|
||||
const handled = await handlePluginAuth({ auth: plugin.auth }, provider)
|
||||
if (handled) return
|
||||
@@ -323,7 +323,7 @@ export const AuthLoginCommand = cmd({
|
||||
if (prompts.isCancel(provider)) throw new UI.CancelledError()
|
||||
|
||||
// Check if a plugin provides auth for this custom provider
|
||||
const customPlugin = await Plugin.list().then((x) => x.find((x) => x.auth?.provider === provider))
|
||||
const customPlugin = await Plugin.list().then((x) => x.findLast((x) => x.auth?.provider === provider))
|
||||
if (customPlugin && customPlugin.auth) {
|
||||
const handled = await handlePluginAuth({ auth: customPlugin.auth }, provider)
|
||||
if (handled) return
|
||||
|
||||
@@ -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()} />
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
}}
|
||||
/>
|
||||
))
|
||||
},
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ import type { ApplyPatchTool } from "@/tool/apply_patch"
|
||||
import type { WebFetchTool } from "@/tool/webfetch"
|
||||
import type { TaskTool } from "@/tool/task"
|
||||
import type { QuestionTool } from "@/tool/question"
|
||||
import type { SkillTool } from "@/tool/skill"
|
||||
import { useKeyboard, useRenderer, useTerminalDimensions, type JSX } from "@opentui/solid"
|
||||
import { useSDK } from "@tui/context/sdk"
|
||||
import { useCommandDialog } from "@tui/component/dialog-command"
|
||||
@@ -1447,6 +1448,9 @@ function ToolPart(props: { last: boolean; part: ToolPart; message: AssistantMess
|
||||
<Match when={props.part.tool === "question"}>
|
||||
<Question {...toolprops} />
|
||||
</Match>
|
||||
<Match when={props.part.tool === "skill"}>
|
||||
<Skill {...toolprops} />
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<GenericTool {...toolprops} />
|
||||
</Match>
|
||||
@@ -1636,7 +1640,9 @@ function Bash(props: ToolProps<typeof BashTool>) {
|
||||
>
|
||||
<box gap={1}>
|
||||
<text fg={theme.text}>$ {props.input.command}</text>
|
||||
<text fg={theme.text}>{limited()}</text>
|
||||
<Show when={output()}>
|
||||
<text fg={theme.text}>{limited()}</text>
|
||||
</Show>
|
||||
<Show when={overflow()}>
|
||||
<text fg={theme.textMuted}>{expanded() ? "Click to collapse" : "Click to expand"}</text>
|
||||
</Show>
|
||||
@@ -1701,7 +1707,9 @@ function Glob(props: ToolProps<typeof GlobTool>) {
|
||||
return (
|
||||
<InlineTool icon="✱" pending="Finding files..." complete={props.input.pattern} part={props.part}>
|
||||
Glob "{props.input.pattern}" <Show when={props.input.path}>in {normalizePath(props.input.path)} </Show>
|
||||
<Show when={props.metadata.count}>({props.metadata.count} matches)</Show>
|
||||
<Show when={props.metadata.count}>
|
||||
({props.metadata.count} {props.metadata.count === 1 ? "match" : "matches"})
|
||||
</Show>
|
||||
</InlineTool>
|
||||
)
|
||||
}
|
||||
@@ -1737,7 +1745,9 @@ function Grep(props: ToolProps<typeof GrepTool>) {
|
||||
return (
|
||||
<InlineTool icon="✱" pending="Searching content..." complete={props.input.pattern} part={props.part}>
|
||||
Grep "{props.input.pattern}" <Show when={props.input.path}>in {normalizePath(props.input.path)} </Show>
|
||||
<Show when={props.metadata.matches}>({props.metadata.matches} matches)</Show>
|
||||
<Show when={props.metadata.matches}>
|
||||
({props.metadata.matches} {props.metadata.matches === 1 ? "match" : "matches"})
|
||||
</Show>
|
||||
</InlineTool>
|
||||
)
|
||||
}
|
||||
@@ -1795,7 +1805,7 @@ function Task(props: ToolProps<typeof TaskTool>) {
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Match when={props.metadata.summary?.length}>
|
||||
<Match when={props.input.description || props.input.subagent_type}>
|
||||
<BlockTool
|
||||
title={"# " + Locale.titlecase(props.input.subagent_type ?? "unknown") + " Task"}
|
||||
onClick={
|
||||
@@ -1807,7 +1817,7 @@ function Task(props: ToolProps<typeof TaskTool>) {
|
||||
>
|
||||
<box>
|
||||
<text style={{ fg: theme.textMuted }}>
|
||||
{props.input.description} ({props.metadata.summary?.length} toolcalls)
|
||||
{props.input.description} ({props.metadata.summary?.length ?? 0} toolcalls)
|
||||
</text>
|
||||
<Show when={current()}>
|
||||
<text style={{ fg: current()!.state.status === "error" ? theme.error : theme.textMuted }}>
|
||||
@@ -1816,22 +1826,17 @@ function Task(props: ToolProps<typeof TaskTool>) {
|
||||
</text>
|
||||
</Show>
|
||||
</box>
|
||||
<text fg={theme.text}>
|
||||
{keybind.print("session_child_cycle")}
|
||||
<span style={{ fg: theme.textMuted }}> view subagents</span>
|
||||
</text>
|
||||
<Show when={props.metadata.sessionId}>
|
||||
<text fg={theme.text}>
|
||||
{keybind.print("session_child_cycle")}
|
||||
<span style={{ fg: theme.textMuted }}> view subagents</span>
|
||||
</text>
|
||||
</Show>
|
||||
</BlockTool>
|
||||
</Match>
|
||||
<Match when={true}>
|
||||
<InlineTool
|
||||
icon="◉"
|
||||
iconColor={color()}
|
||||
pending="Delegating..."
|
||||
complete={props.input.subagent_type ?? props.input.description}
|
||||
part={props.part}
|
||||
>
|
||||
<span style={{ fg: theme.text }}>{Locale.titlecase(props.input.subagent_type ?? "unknown")}</span> Task "
|
||||
{props.input.description}"
|
||||
<InlineTool icon="#" pending="Delegating..." complete={props.input.subagent_type} part={props.part}>
|
||||
{props.input.subagent_type} Task {props.input.description}
|
||||
</InlineTool>
|
||||
</Match>
|
||||
</Switch>
|
||||
@@ -2036,6 +2041,14 @@ function Question(props: ToolProps<typeof QuestionTool>) {
|
||||
)
|
||||
}
|
||||
|
||||
function Skill(props: ToolProps<typeof SkillTool>) {
|
||||
return (
|
||||
<InlineTool icon="→" pending="Loading skill..." complete={props.input.name} part={props.part}>
|
||||
Skill "{props.input.name}"
|
||||
</InlineTool>
|
||||
)
|
||||
}
|
||||
|
||||
function normalizePath(input?: string) {
|
||||
if (!input) return ""
|
||||
if (path.isAbsolute(input)) {
|
||||
|
||||
@@ -228,7 +228,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
||||
</text>
|
||||
<text fg={theme.textMuted}>esc</text>
|
||||
</box>
|
||||
<box paddingTop={1} paddingBottom={1}>
|
||||
<box paddingTop={1}>
|
||||
<input
|
||||
onInput={(e) => {
|
||||
batch(() => {
|
||||
|
||||
@@ -80,17 +80,17 @@ export function formatPart(part: Part, options: TranscriptOptions): string {
|
||||
}
|
||||
|
||||
if (part.type === "tool") {
|
||||
let result = `\`\`\`\nTool: ${part.tool}\n`
|
||||
let result = `**Tool: ${part.tool}**\n`
|
||||
if (options.toolDetails && part.state.input) {
|
||||
result += `\n**Input:**\n\`\`\`json\n${JSON.stringify(part.state.input, null, 2)}\n\`\`\``
|
||||
result += `\n**Input:**\n\`\`\`json\n${JSON.stringify(part.state.input, null, 2)}\n\`\`\`\n`
|
||||
}
|
||||
if (options.toolDetails && part.state.status === "completed" && part.state.output) {
|
||||
result += `\n**Output:**\n\`\`\`\n${part.state.output}\n\`\`\``
|
||||
result += `\n**Output:**\n\`\`\`\n${part.state.output}\n\`\`\`\n`
|
||||
}
|
||||
if (options.toolDetails && part.state.status === "error" && part.state.error) {
|
||||
result += `\n**Error:**\n\`\`\`\n${part.state.error}\n\`\`\``
|
||||
result += `\n**Error:**\n\`\`\`\n${part.state.error}\n\`\`\`\n`
|
||||
}
|
||||
result += `\n\`\`\`\n\n`
|
||||
result += `\n`
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user