summaryrefslogtreecommitdiffhomepage
path: root/packages/desktop/src/context/session.tsx
diff options
context:
space:
mode:
authorAdam <[email protected]>2025-12-04 15:37:29 -0600
committerGitHub <[email protected]>2025-12-04 15:37:29 -0600
commitd763c11a6d5bc57869f11c87f5a293f61e427e0a (patch)
tree88fd0024e1c8a2fe5cee803ccf110a3cac6768d4 /packages/desktop/src/context/session.tsx
parentb1202ac6db1cbead1e8f205913524f1c47322970 (diff)
downloadopencode-d763c11a6d5bc57869f11c87f5a293f61e427e0a.tar.gz
opencode-d763c11a6d5bc57869f11c87f5a293f61e427e0a.zip
feat(desktop): terminal pane (#5081)
Co-authored-by: Github Action <[email protected]> Co-authored-by: Dax Raad <[email protected]>
Diffstat (limited to 'packages/desktop/src/context/session.tsx')
-rw-r--r--packages/desktop/src/context/session.tsx100
1 files changed, 88 insertions, 12 deletions
diff --git a/packages/desktop/src/context/session.tsx b/packages/desktop/src/context/session.tsx
index 72098a939..4e9fe71f8 100644
--- a/packages/desktop/src/context/session.tsx
+++ b/packages/desktop/src/context/session.tsx
@@ -8,14 +8,25 @@ import { pipe, sumBy } from "remeda"
import { AssistantMessage, UserMessage } from "@opencode-ai/sdk"
import { useParams } from "@solidjs/router"
import { base64Encode } from "@/utils"
+import { useSDK } from "./sdk"
+
+export type LocalPTY = {
+ id: string
+ title: string
+ rows?: number
+ cols?: number
+ buffer?: string
+ scrollY?: number
+}
export const { use: useSession, provider: SessionProvider } = createSimpleContext({
name: "Session",
init: () => {
+ const sdk = useSDK()
const params = useParams()
const sync = useSync()
const name = createMemo(
- () => `___${base64Encode(sync.data.project.worktree)}/session${params.id ? "/" + params.id : ""}`,
+ () => `______${base64Encode(sync.data.project.worktree)}/session${params.id ? "/" + params.id : ""}`,
)
const [store, setStore] = makePersisted(
@@ -23,16 +34,21 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
messageId?: string
tabs: {
active?: string
- opened: string[]
+ all: string[]
}
prompt: Prompt
cursor?: number
+ terminals: {
+ active?: string
+ all: LocalPTY[]
+ }
}>({
tabs: {
- opened: [],
+ all: [],
},
prompt: clonePrompt(DEFAULT_PROMPT),
cursor: undefined,
+ terminals: { all: [] },
}),
{
name: name(),
@@ -138,7 +154,7 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
setStore("tabs", "active", tab)
},
setOpenedTabs(tabs: string[]) {
- setStore("tabs", "opened", tabs)
+ setStore("tabs", "all", tabs)
},
async openTab(tab: string) {
if (tab === "chat") {
@@ -146,8 +162,8 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
return
}
if (tab !== "review") {
- if (!store.tabs.opened.includes(tab)) {
- setStore("tabs", "opened", [...store.tabs.opened, tab])
+ if (!store.tabs.all.includes(tab)) {
+ setStore("tabs", "all", [...store.tabs.all, tab])
}
}
setStore("tabs", "active", tab)
@@ -156,28 +172,88 @@ export const { use: useSession, provider: SessionProvider } = createSimpleContex
batch(() => {
setStore(
"tabs",
- "opened",
- store.tabs.opened.filter((x) => x !== tab),
+ "all",
+ store.tabs.all.filter((x) => x !== tab),
)
if (store.tabs.active === tab) {
- const index = store.tabs.opened.findIndex((f) => f === tab)
- const previous = store.tabs.opened[Math.max(0, index - 1)]
+ const index = store.tabs.all.findIndex((f) => f === tab)
+ const previous = store.tabs.all[Math.max(0, index - 1)]
setStore("tabs", "active", previous)
}
})
},
moveTab(tab: string, to: number) {
- const index = store.tabs.opened.findIndex((f) => f === tab)
+ const index = store.tabs.all.findIndex((f) => f === tab)
if (index === -1) return
setStore(
"tabs",
- "opened",
+ "all",
produce((opened) => {
opened.splice(to, 0, opened.splice(index, 1)[0])
}),
)
},
},
+ terminal: {
+ all: createMemo(() => Object.values(store.terminals.all)),
+ active: createMemo(() => store.terminals.active),
+ new() {
+ sdk.client.pty.create({ body: { title: `Terminal ${store.terminals.all.length + 1}` } }).then((pty) => {
+ const id = pty.data?.id
+ if (!id) return
+ batch(() => {
+ setStore("terminals", "all", [
+ ...store.terminals.all,
+ {
+ id,
+ title: pty.data?.title ?? "Terminal",
+ // rows: pty.data?.rows ?? 24,
+ // cols: pty.data?.cols ?? 80,
+ // buffer: "",
+ // scrollY: 0,
+ },
+ ])
+ setStore("terminals", "active", id)
+ })
+ })
+ },
+ update(pty: Partial<LocalPTY> & { id: string }) {
+ setStore("terminals", "all", (x) => x.map((x) => (x.id === pty.id ? { ...x, ...pty } : x)))
+ sdk.client.pty.update({
+ path: { id: pty.id },
+ body: { title: pty.title, size: pty.cols && pty.rows ? { rows: pty.rows, cols: pty.cols } : undefined },
+ })
+ },
+ open(id: string) {
+ setStore("terminals", "active", id)
+ },
+ async close(id: string) {
+ batch(() => {
+ setStore(
+ "terminals",
+ "all",
+ store.terminals.all.filter((x) => x.id !== id),
+ )
+ if (store.terminals.active === id) {
+ const index = store.terminals.all.findIndex((f) => f.id === id)
+ const previous = store.tabs.all[Math.max(0, index - 1)]
+ setStore("terminals", "active", previous)
+ }
+ })
+ await sdk.client.pty.remove({ path: { id } })
+ },
+ move(id: string, to: number) {
+ const index = store.terminals.all.findIndex((f) => f.id === id)
+ if (index === -1) return
+ setStore(
+ "terminals",
+ "all",
+ produce((all) => {
+ all.splice(to, 0, all.splice(index, 1)[0])
+ }),
+ )
+ },
+ },
}
},
})