summaryrefslogtreecommitdiffhomepage
path: root/packages/app/src/pages/session/use-session-commands.tsx
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-03-12 11:32:05 -0500
committerGitHub <[email protected]>2026-03-12 11:32:05 -0500
commitdce7eceb2855bc36a41bc49d9c56d5dcc92a8eb2 (patch)
tree31cd7d7aa33733579134e9a6cf3a61762599d8e0 /packages/app/src/pages/session/use-session-commands.tsx
parent0e077f748352df6d44c811829baff3c26b3436ac (diff)
downloadopencode-dce7eceb2855bc36a41bc49d9c56d5dcc92a8eb2.tar.gz
opencode-dce7eceb2855bc36a41bc49d9c56d5dcc92a8eb2.zip
chore: cleanup (#17197)
Diffstat (limited to 'packages/app/src/pages/session/use-session-commands.tsx')
-rw-r--r--packages/app/src/pages/session/use-session-commands.tsx756
1 files changed, 374 insertions, 382 deletions
diff --git a/packages/app/src/pages/session/use-session-commands.tsx b/packages/app/src/pages/session/use-session-commands.tsx
index 6799504ca..f5a4c0576 100644
--- a/packages/app/src/pages/session/use-session-commands.tsx
+++ b/packages/app/src/pages/session/use-session-commands.tsx
@@ -1,4 +1,3 @@
-import { createMemo } from "solid-js"
import { useNavigate } from "@solidjs/router"
import { useCommand, type CommandOption } from "@/context/command"
import { useDialog } from "@opencode-ai/ui/context/dialog"
@@ -18,6 +17,7 @@ import { DialogSelectMcp } from "@/components/dialog-select-mcp"
import { DialogFork } from "@/components/dialog-fork"
import { showToast } from "@opencode-ai/ui/toast"
import { findLast } from "@opencode-ai/util/array"
+import { createSessionTabs } from "@/pages/session/helpers"
import { extractPromptFromParts } from "@/utils/prompt"
import { UserMessage } from "@opencode-ai/sdk/v2"
import { useSessionLayout } from "@/pages/session/session-layout"
@@ -26,6 +26,7 @@ export type SessionCommandContext = {
navigateMessageByOffset: (offset: number) => void
setActiveMessage: (message: UserMessage | undefined) => void
focusInput: () => void
+ review?: () => boolean
}
const withCategory = (category: string) => {
@@ -50,17 +51,43 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
const navigate = useNavigate()
const { params, tabs, view } = useSessionLayout()
- const info = createMemo(() => (params.id ? sync.session.get(params.id) : undefined))
+ const info = () => {
+ const id = params.id
+ if (!id) return
+ return sync.session.get(id)
+ }
+ const hasReview = () => {
+ const id = params.id
+ if (!id) return false
+ return Math.max(info()?.summary?.files ?? 0, (sync.data.session_diff[id] ?? []).length) > 0
+ }
+ const normalizeTab = (tab: string) => {
+ if (!tab.startsWith("file://")) return tab
+ return file.tab(tab)
+ }
+ const tabState = createSessionTabs({
+ tabs,
+ pathFromTab: file.pathFromTab,
+ normalizeTab,
+ review: actions.review,
+ hasReview,
+ })
+ const activeFileTab = tabState.activeFileTab
+ const closableTab = tabState.closableTab
const idle = { type: "idle" as const }
- const status = createMemo(() => sync.data.session_status[params.id ?? ""] ?? idle)
- const messages = createMemo(() => (params.id ? (sync.data.message[params.id] ?? []) : []))
- const userMessages = createMemo(() => messages().filter((m) => m.role === "user") as UserMessage[])
- const visibleUserMessages = createMemo(() => {
+ const status = () => sync.data.session_status[params.id ?? ""] ?? idle
+ const messages = () => {
+ const id = params.id
+ if (!id) return []
+ return sync.data.message[id] ?? []
+ }
+ const userMessages = () => messages().filter((m) => m.role === "user") as UserMessage[]
+ const visibleUserMessages = () => {
const revert = info()?.revert?.messageID
if (!revert) return userMessages()
return userMessages().filter((m) => m.id < revert)
- })
+ }
const showAllFiles = () => {
if (layout.fileTree.tab() !== "changes") return
@@ -79,9 +106,9 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
}
const canAddSelectionContext = () => {
- const active = tabs().active()
- if (!active) return false
- const path = file.pathFromTab(active)
+ const tab = activeFileTab()
+ if (!tab) return false
+ const path = file.pathFromTab(tab)
if (!path) return false
return file.selectedLines(path) != null
}
@@ -100,404 +127,369 @@ export const useSessionCommands = (actions: SessionCommandContext) => {
const agentCommand = withCategory(language.t("command.category.agent"))
const permissionsCommand = withCategory(language.t("command.category.permissions"))
- const sessionCommands = createMemo(() => [
- sessionCommand({
- id: "session.new",
- title: language.t("command.session.new"),
- keybind: "mod+shift+s",
- slash: "new",
- onSelect: () => navigate(`/${params.dir}/session`),
- }),
- ])
-
- const fileCommands = createMemo(() => [
- fileCommand({
- id: "file.open",
- title: language.t("command.file.open"),
- description: language.t("palette.search.placeholder"),
- keybind: "mod+p",
- slash: "open",
- onSelect: () => dialog.show(() => <DialogSelectFile onOpenFile={showAllFiles} />),
- }),
- fileCommand({
- id: "tab.close",
- title: language.t("command.tab.close"),
- keybind: "mod+w",
- disabled: !tabs().active(),
- onSelect: () => {
- const active = tabs().active()
- if (!active) return
- tabs().close(active)
- },
- }),
- ])
-
- const contextCommands = createMemo(() => [
- contextCommand({
- id: "context.addSelection",
- title: language.t("command.context.addSelection"),
- description: language.t("command.context.addSelection.description"),
- keybind: "mod+shift+l",
- disabled: !canAddSelectionContext(),
- onSelect: () => {
- const active = tabs().active()
- if (!active) return
- const path = file.pathFromTab(active)
- if (!path) return
-
- const range = file.selectedLines(path) as SelectedLineRange | null | undefined
- if (!range) {
- showToast({
- title: language.t("toast.context.noLineSelection.title"),
- description: language.t("toast.context.noLineSelection.description"),
- })
- return
- }
-
- addSelectionToContext(path, selectionFromLines(range))
- },
- }),
- ])
-
- const viewCommands = createMemo(() => [
- viewCommand({
- id: "terminal.toggle",
- title: language.t("command.terminal.toggle"),
- keybind: "ctrl+`",
- slash: "terminal",
- onSelect: () => view().terminal.toggle(),
- }),
- viewCommand({
- id: "review.toggle",
- title: language.t("command.review.toggle"),
- keybind: "mod+shift+r",
- onSelect: () => view().reviewPanel.toggle(),
- }),
- viewCommand({
- id: "fileTree.toggle",
- title: language.t("command.fileTree.toggle"),
- keybind: "mod+\\",
- onSelect: () => layout.fileTree.toggle(),
- }),
- viewCommand({
- id: "input.focus",
- title: language.t("command.input.focus"),
- keybind: "ctrl+l",
- onSelect: () => focusInput(),
- }),
- terminalCommand({
- id: "terminal.new",
- title: language.t("command.terminal.new"),
- description: language.t("command.terminal.new.description"),
- keybind: "ctrl+alt+t",
- onSelect: () => {
- if (terminal.all().length > 0) terminal.new()
- view().terminal.open()
- },
- }),
- ])
-
- const messageCommands = createMemo(() => [
- sessionCommand({
- id: "message.previous",
- title: language.t("command.message.previous"),
- description: language.t("command.message.previous.description"),
- keybind: "mod+arrowup",
- disabled: !params.id,
- onSelect: () => navigateMessageByOffset(-1),
- }),
- sessionCommand({
- id: "message.next",
- title: language.t("command.message.next"),
- description: language.t("command.message.next.description"),
- keybind: "mod+arrowdown",
- disabled: !params.id,
- onSelect: () => navigateMessageByOffset(1),
- }),
- ])
-
- const agentCommands = createMemo(() => [
- modelCommand({
- id: "model.choose",
- title: language.t("command.model.choose"),
- description: language.t("command.model.choose.description"),
- keybind: "mod+'",
- slash: "model",
- onSelect: () => dialog.show(() => <DialogSelectModel />),
- }),
- mcpCommand({
- id: "mcp.toggle",
- title: language.t("command.mcp.toggle"),
- description: language.t("command.mcp.toggle.description"),
- keybind: "mod+;",
- slash: "mcp",
- onSelect: () => dialog.show(() => <DialogSelectMcp />),
- }),
- agentCommand({
- id: "agent.cycle",
- title: language.t("command.agent.cycle"),
- description: language.t("command.agent.cycle.description"),
- keybind: "mod+.",
- slash: "agent",
- onSelect: () => local.agent.move(1),
- }),
- agentCommand({
- id: "agent.cycle.reverse",
- title: language.t("command.agent.cycle.reverse"),
- description: language.t("command.agent.cycle.reverse.description"),
- keybind: "shift+mod+.",
- onSelect: () => local.agent.move(-1),
- }),
- modelCommand({
- id: "model.variant.cycle",
- title: language.t("command.model.variant.cycle"),
- description: language.t("command.model.variant.cycle.description"),
- keybind: "shift+mod+d",
- onSelect: () => {
- local.model.variant.cycle()
- },
- }),
- ])
-
const isAutoAcceptActive = () => {
const sessionID = params.id
if (sessionID) return permission.isAutoAccepting(sessionID, sdk.directory)
return permission.isAutoAcceptingDirectory(sdk.directory)
}
+ command.register("session", () => {
+ const share =
+ sync.data.config.share === "disabled"
+ ? []
+ : [
+ sessionCommand({
+ id: "session.share",
+ title: info()?.share?.url
+ ? language.t("session.share.copy.copyLink")
+ : language.t("command.session.share"),
+ description: info()?.share?.url
+ ? language.t("toast.session.share.success.description")
+ : language.t("command.session.share.description"),
+ slash: "share",
+ disabled: !params.id,
+ onSelect: async () => {
+ if (!params.id) return
- const permissionCommands = createMemo(() => [
- permissionsCommand({
- id: "permissions.autoaccept",
- title: isAutoAcceptActive()
- ? language.t("command.permissions.autoaccept.disable")
- : language.t("command.permissions.autoaccept.enable"),
- keybind: "mod+shift+a",
- disabled: false,
- onSelect: () => {
- const sessionID = params.id
- if (sessionID) {
- permission.toggleAutoAccept(sessionID, sdk.directory)
- } else {
- permission.toggleAutoAcceptDirectory(sdk.directory)
- }
- const active = sessionID
- ? permission.isAutoAccepting(sessionID, sdk.directory)
- : permission.isAutoAcceptingDirectory(sdk.directory)
- showToast({
- title: active
- ? language.t("toast.permissions.autoaccept.on.title")
- : language.t("toast.permissions.autoaccept.off.title"),
- description: active
- ? language.t("toast.permissions.autoaccept.on.description")
- : language.t("toast.permissions.autoaccept.off.description"),
- })
- },
- }),
- ])
+ const write = (value: string) => {
+ const body = typeof document === "undefined" ? undefined : document.body
+ if (body) {
+ const textarea = document.createElement("textarea")
+ textarea.value = value
+ textarea.setAttribute("readonly", "")
+ textarea.style.position = "fixed"
+ textarea.style.opacity = "0"
+ textarea.style.pointerEvents = "none"
+ body.appendChild(textarea)
+ textarea.select()
+ const copied = document.execCommand("copy")
+ body.removeChild(textarea)
+ if (copied) return Promise.resolve(true)
+ }
- const sessionActionCommands = createMemo(() => [
- sessionCommand({
- id: "session.undo",
- title: language.t("command.session.undo"),
- description: language.t("command.session.undo.description"),
- slash: "undo",
- disabled: !params.id || visibleUserMessages().length === 0,
- onSelect: async () => {
- const sessionID = params.id
- if (!sessionID) return
- if (status()?.type !== "idle") {
- await sdk.client.session.abort({ sessionID }).catch(() => {})
- }
- const revert = info()?.revert?.messageID
- const message = findLast(userMessages(), (x) => !revert || x.id < revert)
- if (!message) return
- await sdk.client.session.revert({ sessionID, messageID: message.id })
- const parts = sync.data.part[message.id]
- if (parts) {
- const restored = extractPromptFromParts(parts, { directory: sdk.directory })
- prompt.set(restored)
- }
- const priorMessage = findLast(userMessages(), (x) => x.id < message.id)
- setActiveMessage(priorMessage)
- },
- }),
- sessionCommand({
- id: "session.redo",
- title: language.t("command.session.redo"),
- description: language.t("command.session.redo.description"),
- slash: "redo",
- disabled: !params.id || !info()?.revert?.messageID,
- onSelect: async () => {
- const sessionID = params.id
- if (!sessionID) return
- const revertMessageID = info()?.revert?.messageID
- if (!revertMessageID) return
- const nextMessage = userMessages().find((x) => x.id > revertMessageID)
- if (!nextMessage) {
- await sdk.client.session.unrevert({ sessionID })
- prompt.reset()
- const lastMsg = findLast(userMessages(), (x) => x.id >= revertMessageID)
- setActiveMessage(lastMsg)
- return
- }
- await sdk.client.session.revert({ sessionID, messageID: nextMessage.id })
- const priorMsg = findLast(userMessages(), (x) => x.id < nextMessage.id)
- setActiveMessage(priorMsg)
- },
- }),
- sessionCommand({
- id: "session.compact",
- title: language.t("command.session.compact"),
- description: language.t("command.session.compact.description"),
- slash: "compact",
- disabled: !params.id || visibleUserMessages().length === 0,
- onSelect: async () => {
- const sessionID = params.id
- if (!sessionID) return
- const model = local.model.current()
- if (!model) {
- showToast({
- title: language.t("toast.model.none.title"),
- description: language.t("toast.model.none.description"),
- })
- return
- }
- await sdk.client.session.summarize({
- sessionID,
- modelID: model.id,
- providerID: model.provider.id,
- })
- },
- }),
- sessionCommand({
- id: "session.fork",
- title: language.t("command.session.fork"),
- description: language.t("command.session.fork.description"),
- slash: "fork",
- disabled: !params.id || visibleUserMessages().length === 0,
- onSelect: () => dialog.show(() => <DialogFork />),
- }),
- ])
+ const clipboard = typeof navigator === "undefined" ? undefined : navigator.clipboard
+ if (!clipboard?.writeText) return Promise.resolve(false)
+ return clipboard.writeText(value).then(
+ () => true,
+ () => false,
+ )
+ }
- const shareCommands = createMemo(() => {
- if (sync.data.config.share === "disabled") return []
- return [
- sessionCommand({
- id: "session.share",
- title: info()?.share?.url ? language.t("session.share.copy.copyLink") : language.t("command.session.share"),
- description: info()?.share?.url
- ? language.t("toast.session.share.success.description")
- : language.t("command.session.share.description"),
- slash: "share",
- disabled: !params.id,
- onSelect: async () => {
- if (!params.id) return
+ const copy = async (url: string, existing: boolean) => {
+ const ok = await write(url)
+ if (!ok) {
+ showToast({
+ title: language.t("toast.session.share.copyFailed.title"),
+ variant: "error",
+ })
+ return
+ }
- const write = (value: string) => {
- const body = typeof document === "undefined" ? undefined : document.body
- if (body) {
- const textarea = document.createElement("textarea")
- textarea.value = value
- textarea.setAttribute("readonly", "")
- textarea.style.position = "fixed"
- textarea.style.opacity = "0"
- textarea.style.pointerEvents = "none"
- body.appendChild(textarea)
- textarea.select()
- const copied = document.execCommand("copy")
- body.removeChild(textarea)
- if (copied) return Promise.resolve(true)
- }
+ showToast({
+ title: existing
+ ? language.t("session.share.copy.copied")
+ : language.t("toast.session.share.success.title"),
+ description: language.t("toast.session.share.success.description"),
+ variant: "success",
+ })
+ }
- const clipboard = typeof navigator === "undefined" ? undefined : navigator.clipboard
- if (!clipboard?.writeText) return Promise.resolve(false)
- return clipboard.writeText(value).then(
- () => true,
- () => false,
- )
- }
+ const existing = info()?.share?.url
+ if (existing) {
+ await copy(existing, true)
+ return
+ }
- const copy = async (url: string, existing: boolean) => {
- const ok = await write(url)
- if (!ok) {
- showToast({
- title: language.t("toast.session.share.copyFailed.title"),
- variant: "error",
- })
- return
- }
+ const url = await sdk.client.session
+ .share({ sessionID: params.id })
+ .then((res) => res.data?.share?.url)
+ .catch(() => undefined)
+ if (!url) {
+ showToast({
+ title: language.t("toast.session.share.failed.title"),
+ description: language.t("toast.session.share.failed.description"),
+ variant: "error",
+ })
+ return
+ }
+ await copy(url, false)
+ },
+ }),
+ sessionCommand({
+ id: "session.unshare",
+ title: language.t("command.session.unshare"),
+ description: language.t("command.session.unshare.description"),
+ slash: "unshare",
+ disabled: !params.id || !info()?.share?.url,
+ onSelect: async () => {
+ if (!params.id) return
+ await sdk.client.session
+ .unshare({ sessionID: params.id })
+ .then(() =>
+ showToast({
+ title: language.t("toast.session.unshare.success.title"),
+ description: language.t("toast.session.unshare.success.description"),
+ variant: "success",
+ }),
+ )
+ .catch(() =>
+ showToast({
+ title: language.t("toast.session.unshare.failed.title"),
+ description: language.t("toast.session.unshare.failed.description"),
+ variant: "error",
+ }),
+ )
+ },
+ }),
+ ]
+
+ return [
+ sessionCommand({
+ id: "session.new",
+ title: language.t("command.session.new"),
+ keybind: "mod+shift+s",
+ slash: "new",
+ onSelect: () => navigate(`/${params.dir}/session`),
+ }),
+ fileCommand({
+ id: "file.open",
+ title: language.t("command.file.open"),
+ description: language.t("palette.search.placeholder"),
+ keybind: "mod+p",
+ slash: "open",
+ onSelect: () => dialog.show(() => <DialogSelectFile onOpenFile={showAllFiles} />),
+ }),
+ fileCommand({
+ id: "tab.close",
+ title: language.t("command.tab.close"),
+ keybind: "mod+w",
+ disabled: !closableTab(),
+ onSelect: () => {
+ const tab = closableTab()
+ if (!tab) return
+ tabs().close(tab)
+ },
+ }),
+ contextCommand({
+ id: "context.addSelection",
+ title: language.t("command.context.addSelection"),
+ description: language.t("command.context.addSelection.description"),
+ keybind: "mod+shift+l",
+ disabled: !canAddSelectionContext(),
+ onSelect: () => {
+ const tab = activeFileTab()
+ if (!tab) return
+ const path = file.pathFromTab(tab)
+ if (!path) return
+
+ const range = file.selectedLines(path) as SelectedLineRange | null | undefined
+ if (!range) {
showToast({
- title: existing
- ? language.t("session.share.copy.copied")
- : language.t("toast.session.share.success.title"),
- description: language.t("toast.session.share.success.description"),
- variant: "success",
+ title: language.t("toast.context.noLineSelection.title"),
+ description: language.t("toast.context.noLineSelection.description"),
})
+ return
}
- const existing = info()?.share?.url
- if (existing) {
- await copy(existing, true)
+ addSelectionToContext(path, selectionFromLines(range))
+ },
+ }),
+ viewCommand({
+ id: "terminal.toggle",
+ title: language.t("command.terminal.toggle"),
+ keybind: "ctrl+`",
+ slash: "terminal",
+ onSelect: () => view().terminal.toggle(),
+ }),
+ viewCommand({
+ id: "review.toggle",
+ title: language.t("command.review.toggle"),
+ keybind: "mod+shift+r",
+ onSelect: () => view().reviewPanel.toggle(),
+ }),
+ viewCommand({
+ id: "fileTree.toggle",
+ title: language.t("command.fileTree.toggle"),
+ keybind: "mod+\\",
+ onSelect: () => layout.fileTree.toggle(),
+ }),
+ viewCommand({
+ id: "input.focus",
+ title: language.t("command.input.focus"),
+ keybind: "ctrl+l",
+ onSelect: focusInput,
+ }),
+ terminalCommand({
+ id: "terminal.new",
+ title: language.t("command.terminal.new"),
+ description: language.t("command.terminal.new.description"),
+ keybind: "ctrl+alt+t",
+ onSelect: () => {
+ if (terminal.all().length > 0) terminal.new()
+ view().terminal.open()
+ },
+ }),
+ sessionCommand({
+ id: "message.previous",
+ title: language.t("command.message.previous"),
+ description: language.t("command.message.previous.description"),
+ keybind: "mod+arrowup",
+ disabled: !params.id,
+ onSelect: () => navigateMessageByOffset(-1),
+ }),
+ sessionCommand({
+ id: "message.next",
+ title: language.t("command.message.next"),
+ description: language.t("command.message.next.description"),
+ keybind: "mod+arrowdown",
+ disabled: !params.id,
+ onSelect: () => navigateMessageByOffset(1),
+ }),
+ modelCommand({
+ id: "model.choose",
+ title: language.t("command.model.choose"),
+ description: language.t("command.model.choose.description"),
+ keybind: "mod+'",
+ slash: "model",
+ onSelect: () => dialog.show(() => <DialogSelectModel />),
+ }),
+ mcpCommand({
+ id: "mcp.toggle",
+ title: language.t("command.mcp.toggle"),
+ description: language.t("command.mcp.toggle.description"),
+ keybind: "mod+;",
+ slash: "mcp",
+ onSelect: () => dialog.show(() => <DialogSelectMcp />),
+ }),
+ agentCommand({
+ id: "agent.cycle",
+ title: language.t("command.agent.cycle"),
+ description: language.t("command.agent.cycle.description"),
+ keybind: "mod+.",
+ slash: "agent",
+ onSelect: () => local.agent.move(1),
+ }),
+ agentCommand({
+ id: "agent.cycle.reverse",
+ title: language.t("command.agent.cycle.reverse"),
+ description: language.t("command.agent.cycle.reverse.description"),
+ keybind: "shift+mod+.",
+ onSelect: () => local.agent.move(-1),
+ }),
+ modelCommand({
+ id: "model.variant.cycle",
+ title: language.t("command.model.variant.cycle"),
+ description: language.t("command.model.variant.cycle.description"),
+ keybind: "shift+mod+d",
+ onSelect: () => local.model.variant.cycle(),
+ }),
+ permissionsCommand({
+ id: "permissions.autoaccept",
+ title: isAutoAcceptActive()
+ ? language.t("command.permissions.autoaccept.disable")
+ : language.t("command.permissions.autoaccept.enable"),
+ keybind: "mod+shift+a",
+ disabled: false,
+ onSelect: () => {
+ const sessionID = params.id
+ if (sessionID) permission.toggleAutoAccept(sessionID, sdk.directory)
+ else permission.toggleAutoAcceptDirectory(sdk.directory)
+
+ const active = sessionID
+ ? permission.isAutoAccepting(sessionID, sdk.directory)
+ : permission.isAutoAcceptingDirectory(sdk.directory)
+ showToast({
+ title: active
+ ? language.t("toast.permissions.autoaccept.on.title")
+ : language.t("toast.permissions.autoaccept.off.title"),
+ description: active
+ ? language.t("toast.permissions.autoaccept.on.description")
+ : language.t("toast.permissions.autoaccept.off.description"),
+ })
+ },
+ }),
+ sessionCommand({
+ id: "session.undo",
+ title: language.t("command.session.undo"),
+ description: language.t("command.session.undo.description"),
+ slash: "undo",
+ disabled: !params.id || visibleUserMessages().length === 0,
+ onSelect: async () => {
+ const sessionID = params.id
+ if (!sessionID) return
+ if (status().type !== "idle") {
+ await sdk.client.session.abort({ sessionID }).catch(() => {})
+ }
+ const revert = info()?.revert?.messageID
+ const message = findLast(userMessages(), (x) => !revert || x.id < revert)
+ if (!message) return
+ await sdk.client.session.revert({ sessionID, messageID: message.id })
+ const parts = sync.data.part[message.id]
+ if (parts) {
+ const restored = extractPromptFromParts(parts, { directory: sdk.directory })
+ prompt.set(restored)
+ }
+ const priorMessage = findLast(userMessages(), (x) => x.id < message.id)
+ setActiveMessage(priorMessage)
+ },
+ }),
+ sessionCommand({
+ id: "session.redo",
+ title: language.t("command.session.redo"),
+ description: language.t("command.session.redo.description"),
+ slash: "redo",
+ disabled: !params.id || !info()?.revert?.messageID,
+ onSelect: async () => {
+ const sessionID = params.id
+ if (!sessionID) return
+ const revertMessageID = info()?.revert?.messageID
+ if (!revertMessageID) return
+ const nextMessage = userMessages().find((x) => x.id > revertMessageID)
+ if (!nextMessage) {
+ await sdk.client.session.unrevert({ sessionID })
+ prompt.reset()
+ const lastMsg = findLast(userMessages(), (x) => x.id >= revertMessageID)
+ setActiveMessage(lastMsg)
return
}
-
- const url = await sdk.client.session
- .share({ sessionID: params.id })
- .then((res) => res.data?.share?.url)
- .catch(() => undefined)
- if (!url) {
+ await sdk.client.session.revert({ sessionID, messageID: nextMessage.id })
+ const priorMsg = findLast(userMessages(), (x) => x.id < nextMessage.id)
+ setActiveMessage(priorMsg)
+ },
+ }),
+ sessionCommand({
+ id: "session.compact",
+ title: language.t("command.session.compact"),
+ description: language.t("command.session.compact.description"),
+ slash: "compact",
+ disabled: !params.id || visibleUserMessages().length === 0,
+ onSelect: async () => {
+ const sessionID = params.id
+ if (!sessionID) return
+ const model = local.model.current()
+ if (!model) {
showToast({
- title: language.t("toast.session.share.failed.title"),
- description: language.t("toast.session.share.failed.description"),
- variant: "error",
+ title: language.t("toast.model.none.title"),
+ description: language.t("toast.model.none.description"),
})
return
}
-
- await copy(url, false)
+ await sdk.client.session.summarize({
+ sessionID,
+ modelID: model.id,
+ providerID: model.provider.id,
+ })
},
}),
sessionCommand({
- id: "session.unshare",
- title: language.t("command.session.unshare"),
- description: language.t("command.session.unshare.description"),
- slash: "unshare",
- disabled: !params.id || !info()?.share?.url,
- onSelect: async () => {
- if (!params.id) return
- await sdk.client.session
- .unshare({ sessionID: params.id })
- .then(() =>
- showToast({
- title: language.t("toast.session.unshare.success.title"),
- description: language.t("toast.session.unshare.success.description"),
- variant: "success",
- }),
- )
- .catch(() =>
- showToast({
- title: language.t("toast.session.unshare.failed.title"),
- description: language.t("toast.session.unshare.failed.description"),
- variant: "error",
- }),
- )
- },
+ id: "session.fork",
+ title: language.t("command.session.fork"),
+ description: language.t("command.session.fork.description"),
+ slash: "fork",
+ disabled: !params.id || visibleUserMessages().length === 0,
+ onSelect: () => dialog.show(() => <DialogFork />),
}),
+ ...share,
]
})
-
- command.register("session", () =>
- [
- sessionCommands(),
- fileCommands(),
- contextCommands(),
- viewCommands(),
- messageCommands(),
- agentCommands(),
- permissionCommands(),
- sessionActionCommands(),
- shareCommands(),
- ].flatMap((x) => x),
- )
}