mirror of
https://github.com/anomalyco/opencode.git
synced 2026-05-22 19:55:11 +00:00
fix(tui): keep compact slash editable
This commit is contained in:
parent
fbce48f597
commit
25f92bba8d
3 changed files with 21 additions and 90 deletions
|
|
@ -18,7 +18,6 @@ const optimistic: Array<{
|
|||
const optimisticSeeded: boolean[] = []
|
||||
const storedSessions: Record<string, Array<{ id: string; title?: string }>> = {}
|
||||
const promoted: Array<{ directory: string; sessionID: string }> = []
|
||||
const sentSummaries: Array<{ sessionID: string; instructions?: string }> = []
|
||||
const sentShell: string[] = []
|
||||
const syncedDirectories: string[] = []
|
||||
|
||||
|
|
@ -26,7 +25,7 @@ let params: { id?: string } = {}
|
|||
let selected = "/repo/worktree-a"
|
||||
let variant: string | undefined
|
||||
|
||||
let promptValue: Prompt = [{ type: "text", content: "ls", start: 0, end: 2 }]
|
||||
const promptValue: Prompt = [{ type: "text", content: "ls", start: 0, end: 2 }]
|
||||
|
||||
const clientFor = (directory: string) => {
|
||||
createdClients.push(directory)
|
||||
|
|
@ -48,10 +47,6 @@ const clientFor = (directory: string) => {
|
|||
prompt: async () => ({ data: undefined }),
|
||||
promptAsync: async () => ({ data: undefined }),
|
||||
command: async () => ({ data: undefined }),
|
||||
summarize: async (input: { sessionID: string; instructions?: string }) => {
|
||||
sentSummaries.push({ sessionID: input.sessionID, instructions: input.instructions })
|
||||
return { data: undefined }
|
||||
},
|
||||
abort: async () => ({ data: undefined }),
|
||||
},
|
||||
worktree: {
|
||||
|
|
@ -213,8 +208,6 @@ beforeEach(() => {
|
|||
optimistic.length = 0
|
||||
optimisticSeeded.length = 0
|
||||
promoted.length = 0
|
||||
promptValue = [{ type: "text", content: "ls", start: 0, end: 2 }]
|
||||
sentSummaries.length = 0
|
||||
params = {}
|
||||
sentShell.length = 0
|
||||
syncedDirectories.length = 0
|
||||
|
|
@ -350,30 +343,4 @@ describe("prompt submit worktree selection", () => {
|
|||
expect(optimisticSeeded).toEqual([true])
|
||||
})
|
||||
|
||||
test("submits typed compact slash arguments as summarize instructions", async () => {
|
||||
params = { id: "session-1" }
|
||||
promptValue = [{ type: "text", content: "/compact keep unresolved TODOs", start: 0, end: 30 }]
|
||||
|
||||
const submit = createPromptSubmit({
|
||||
info: () => ({ id: "session-1" }),
|
||||
imageAttachments: () => [],
|
||||
commentCount: () => 0,
|
||||
autoAccept: () => false,
|
||||
mode: () => "normal",
|
||||
working: () => false,
|
||||
editor: () => undefined,
|
||||
queueScroll: () => undefined,
|
||||
promptLength: (value) => value.reduce((sum, part) => sum + ("content" in part ? part.content.length : 0), 0),
|
||||
addToHistory: () => undefined,
|
||||
resetHistoryNavigation: () => undefined,
|
||||
setMode: () => undefined,
|
||||
setPopover: () => undefined,
|
||||
onSubmit: () => undefined,
|
||||
})
|
||||
|
||||
await submit.handleSubmit({ preventDefault: () => undefined } as unknown as Event)
|
||||
|
||||
expect(sentSummaries).toEqual([{ sessionID: "session-1", instructions: "keep unresolved TODOs" }])
|
||||
expect(optimistic).toHaveLength(0)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -50,21 +50,6 @@ const draftText = (prompt: Prompt) => prompt.map((part) => ("content" in part ?
|
|||
|
||||
const draftImages = (prompt: Prompt) => prompt.filter((part): part is ImageAttachmentPart => part.type === "image")
|
||||
|
||||
const slashCommand = (text: string) => {
|
||||
if (!text.startsWith("/")) return undefined
|
||||
return text.split("\n")[0].split(" ")[0].slice(1)
|
||||
}
|
||||
|
||||
const slashArguments = (text: string) => {
|
||||
const firstLineEnd = text.indexOf("\n")
|
||||
const firstLine = firstLineEnd === -1 ? text : text.slice(0, firstLineEnd)
|
||||
const [, ...firstLineArgs] = firstLine.split(" ")
|
||||
const restOfInput = firstLineEnd === -1 ? "" : text.slice(firstLineEnd + 1)
|
||||
return firstLineArgs.join(" ") + (restOfInput ? "\n" + restOfInput : "")
|
||||
}
|
||||
|
||||
const isCompactSlash = (command: string | undefined) => command === "compact" || command === "summarize"
|
||||
|
||||
export async function sendFollowupDraft(input: FollowupSendInput) {
|
||||
const text = draftText(input.draft.prompt)
|
||||
const images = draftImages(input.draft.prompt)
|
||||
|
|
@ -86,27 +71,8 @@ export async function sendFollowupDraft(input: FollowupSendInput) {
|
|||
return true
|
||||
}
|
||||
|
||||
const cmd = slashCommand(text)
|
||||
if (isCompactSlash(cmd)) {
|
||||
setBusy()
|
||||
try {
|
||||
if (!(await wait())) {
|
||||
setIdle()
|
||||
return false
|
||||
}
|
||||
|
||||
const instructions = slashArguments(text).trim()
|
||||
const payload = instructions
|
||||
? { sessionID: input.draft.sessionID, ...input.draft.model, instructions }
|
||||
: { sessionID: input.draft.sessionID, ...input.draft.model }
|
||||
await input.client.session.summarize(payload)
|
||||
return true
|
||||
} catch (err) {
|
||||
setIdle()
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
const [head, ...tail] = text.split(" ")
|
||||
const cmd = head?.startsWith("/") ? head.slice(1) : undefined
|
||||
if (cmd && input.sync.data.command.find((item) => item.name === cmd)) {
|
||||
setBusy()
|
||||
try {
|
||||
|
|
@ -118,7 +84,7 @@ export async function sendFollowupDraft(input: FollowupSendInput) {
|
|||
await input.client.session.command({
|
||||
sessionID: input.draft.sessionID,
|
||||
command: cmd,
|
||||
arguments: slashArguments(text),
|
||||
arguments: tail.join(" "),
|
||||
agent: input.draft.agent,
|
||||
model: `${input.draft.model.providerID}/${input.draft.model.modelID}`,
|
||||
variant: input.draft.variant,
|
||||
|
|
@ -487,7 +453,8 @@ export function createPromptSubmit(input: PromptSubmitInput) {
|
|||
}
|
||||
|
||||
if (text.startsWith("/")) {
|
||||
const commandName = slashCommand(text) ?? ""
|
||||
const [cmdName, ...args] = text.split(" ")
|
||||
const commandName = cmdName.slice(1)
|
||||
const customCommand = sync.data.command.find((c) => c.name === commandName)
|
||||
if (customCommand) {
|
||||
clearInput()
|
||||
|
|
@ -495,7 +462,7 @@ export function createPromptSubmit(input: PromptSubmitInput) {
|
|||
.command({
|
||||
sessionID: session.id,
|
||||
command: commandName,
|
||||
arguments: slashArguments(text),
|
||||
arguments: args.join(" "),
|
||||
agent,
|
||||
model: `${model.providerID}/${model.modelID}`,
|
||||
variant,
|
||||
|
|
@ -513,22 +480,6 @@ export function createPromptSubmit(input: PromptSubmitInput) {
|
|||
description: formatServerError(err, language.t, language.t("common.requestFailed")),
|
||||
})
|
||||
restoreInput()
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (isCompactSlash(commandName)) {
|
||||
clearInput()
|
||||
const instructions = slashArguments(text).trim()
|
||||
const payload = instructions
|
||||
? { sessionID: session.id, ...model, instructions }
|
||||
: { sessionID: session.id, ...model }
|
||||
client.session.summarize(payload).catch((err) => {
|
||||
showToast({
|
||||
title: language.t("prompt.toast.promptSendFailed.title"),
|
||||
description: errorMessage(err),
|
||||
})
|
||||
restoreInput()
|
||||
})
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -544,7 +544,20 @@ export function Autocomplete(props: {
|
|||
)
|
||||
|
||||
const commands = createMemo((): AutocompleteOption[] => {
|
||||
const results: AutocompleteOption[] = [...slashes()]
|
||||
const results: AutocompleteOption[] = slashes().map((command) => {
|
||||
const name = command.display.trim().slice(1)
|
||||
if (name !== "compact") return command
|
||||
return {
|
||||
...command,
|
||||
onSelect: () => {
|
||||
const newText = `/${name} `
|
||||
const cursor = props.input().logicalCursor
|
||||
props.input().deleteRange(0, 0, cursor.row, cursor.col)
|
||||
props.input().insertText(newText)
|
||||
props.input().cursorOffset = Bun.stringWidth(newText)
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
for (const serverCommand of sync.data.command) {
|
||||
if (serverCommand.source === "skill") continue
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue