Skip to content

Commit a718f86

Browse files
authored
Merge branch 'dev' into feat/canceled-prompts-in-history
2 parents f3efdff + 1db292f commit a718f86

46 files changed

Lines changed: 795 additions & 470 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bun.lock

Lines changed: 23 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nix/hashes.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"nodeModules": {
3-
"x86_64-linux": "sha256-4kjoJ06VNvHltPHfzQRBG0bC6R39jao10ffGzrNZ230=",
4-
"aarch64-linux": "sha256-6Uio+S2rcyBWbBEeOZb9N1CCKgkbKi68lOIKi3Ws/pQ=",
5-
"aarch64-darwin": "sha256-8ngN5KVN4vhdsk0QJ11BGgSVBrcaEbwSj23c77HBpgs=",
6-
"x86_64-darwin": "sha256-v/ueYGb9a0Nymzy+mkO4uQr78DAuJnES1qOT0onFgnQ="
3+
"x86_64-linux": "sha256-c99eE1cKAQHvwJosaFo42U9Hk0Rtp/U5oTTlyiz2Zw4=",
4+
"aarch64-linux": "sha256-LbdssPrf8Bijyp4mRo8QaO/swxwUWSo1g0jLPm2rvUA=",
5+
"aarch64-darwin": "sha256-0L9y6Zk4l2vAxsM2bENahhtRZY1C3XhdxLgnnYlhkkY=",
6+
"x86_64-darwin": "sha256-0J5sFG/kHHRDcTpdpdPBMJEOHwCRnAUYmbxEHPPLDvU="
77
}
88
}

packages/app/e2e/terminal/terminal-tabs.spec.ts

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,14 @@ async function store(page: Page, key: string) {
4444
}, key)
4545
}
4646

47-
test("terminal tab buffers persist across tab switches", async ({ page, withProject }) => {
47+
test("inactive terminal tab buffers persist across tab switches", async ({ page, withProject }) => {
4848
await withProject(async ({ directory, gotoSession }) => {
4949
const key = workspacePersistKey(directory, "terminal")
5050
const one = `E2E_TERM_ONE_${Date.now()}`
5151
const two = `E2E_TERM_TWO_${Date.now()}`
5252
const tabs = page.locator('#terminal-panel [data-slot="tabs-trigger"]')
53+
const first = tabs.filter({ hasText: /Terminal 1/ }).first()
54+
const second = tabs.filter({ hasText: /Terminal 2/ }).first()
5355

5456
await gotoSession()
5557
await open(page)
@@ -61,22 +63,39 @@ test("terminal tab buffers persist across tab switches", async ({ page, withProj
6163

6264
await run(page, `echo ${two}`)
6365

64-
await tabs
65-
.filter({ hasText: /Terminal 1/ })
66-
.first()
67-
.click()
66+
await first.click()
67+
await expect(first).toHaveAttribute("aria-selected", "true")
68+
await expect
69+
.poll(
70+
async () => {
71+
const state = await store(page, key)
72+
const first = state?.all.find((item) => item.titleNumber === 1)?.buffer ?? ""
73+
const second = state?.all.find((item) => item.titleNumber === 2)?.buffer ?? ""
74+
return {
75+
first: first.includes(one),
76+
second: second.includes(two),
77+
}
78+
},
79+
{ timeout: 30_000 },
80+
)
81+
.toEqual({ first: false, second: true })
6882

83+
await second.click()
84+
await expect(second).toHaveAttribute("aria-selected", "true")
6985
await expect
7086
.poll(
7187
async () => {
7288
const state = await store(page, key)
7389
const first = state?.all.find((item) => item.titleNumber === 1)?.buffer ?? ""
7490
const second = state?.all.find((item) => item.titleNumber === 2)?.buffer ?? ""
75-
return first.includes(one) && second.includes(two)
91+
return {
92+
first: first.includes(one),
93+
second: second.includes(two),
94+
}
7695
},
7796
{ timeout: 30_000 },
7897
)
79-
.toBe(true)
98+
.toEqual({ first: true, second: false })
8099
})
81100
})
82101

packages/app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@opencode-ai/app",
3-
"version": "1.2.21",
3+
"version": "1.2.22",
44
"description": "",
55
"type": "module",
66
"exports": {

packages/app/src/context/terminal.tsx

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createStore, produce } from "solid-js/store"
22
import { createSimpleContext } from "@opencode-ai/ui/context"
3-
import { batch, createEffect, createMemo, createRoot, onCleanup } from "solid-js"
3+
import { batch, createEffect, createMemo, createRoot, on, onCleanup } from "solid-js"
44
import { useParams } from "@solidjs/router"
55
import { useSDK } from "./sdk"
66
import type { Platform } from "./platform"
@@ -38,6 +38,16 @@ type TerminalCacheEntry = {
3838

3939
const caches = new Set<Map<string, TerminalCacheEntry>>()
4040

41+
const trimTerminal = (pty: LocalPTY) => {
42+
if (!pty.buffer && pty.cursor === undefined && pty.scrollY === undefined) return pty
43+
return {
44+
...pty,
45+
buffer: undefined,
46+
cursor: undefined,
47+
scrollY: undefined,
48+
}
49+
}
50+
4151
export function clearWorkspaceTerminals(dir: string, sessionIDs?: string[], platform?: Platform) {
4252
const key = getWorkspaceTerminalCacheKey(dir)
4353
for (const cache of caches) {
@@ -188,6 +198,18 @@ function createWorkspaceTerminalSession(sdk: ReturnType<typeof useSDK>, dir: str
188198
console.error("Failed to update terminal", error)
189199
})
190200
},
201+
trim(id: string) {
202+
const index = store.all.findIndex((x) => x.id === id)
203+
if (index === -1) return
204+
setStore("all", index, (pty) => trimTerminal(pty))
205+
},
206+
trimAll() {
207+
setStore("all", (all) => {
208+
const next = all.map(trimTerminal)
209+
if (next.every((pty, index) => pty === all[index])) return all
210+
return next
211+
})
212+
},
191213
async clone(id: string) {
192214
const index = store.all.findIndex((x) => x.id === id)
193215
const pty = store.all[index]
@@ -322,12 +344,27 @@ export const { use: useTerminal, provider: TerminalProvider } = createSimpleCont
322344

323345
const workspace = createMemo(() => loadWorkspace(params.dir!, params.id))
324346

347+
createEffect(
348+
on(
349+
() => ({ dir: params.dir, id: params.id }),
350+
(next, prev) => {
351+
if (!prev?.dir) return
352+
if (next.dir === prev.dir && next.id === prev.id) return
353+
if (next.dir === prev.dir && next.id) return
354+
loadWorkspace(prev.dir, prev.id).trimAll()
355+
},
356+
{ defer: true },
357+
),
358+
)
359+
325360
return {
326361
ready: () => workspace().ready(),
327362
all: () => workspace().all(),
328363
active: () => workspace().active(),
329364
new: () => workspace().new(),
330365
update: (pty: Partial<LocalPTY> & { id: string }) => workspace().update(pty),
366+
trim: (id: string) => workspace().trim(id),
367+
trimAll: () => workspace().trimAll(),
331368
clone: (id: string) => workspace().clone(id),
332369
open: (id: string) => workspace().open(id),
333370
close: (id: string) => workspace().close(id),

packages/app/src/pages/layout.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,6 +1891,7 @@ export default function Layout(props: ParentProps) {
18911891

18921892
const SidebarPanel = (panelProps: { project: LocalProject | undefined; mobile?: boolean; merged?: boolean }) => {
18931893
const merged = createMemo(() => panelProps.mobile || (panelProps.merged ?? layout.sidebar.opened()))
1894+
const hover = createMemo(() => !panelProps.mobile && panelProps.merged === false && !layout.sidebar.opened())
18941895
const projectName = createMemo(() => {
18951896
const project = panelProps.project
18961897
if (!project) return ""
@@ -1919,8 +1920,8 @@ export default function Layout(props: ParentProps) {
19191920
"flex flex-col min-h-0 min-w-0 rounded-tl-[12px] px-2": true,
19201921
"border border-b-0 border-border-weak-base": !merged(),
19211922
"border-l border-t border-border-weaker-base": merged(),
1922-
"bg-background-base": merged(),
1923-
"bg-background-stronger": !merged(),
1923+
"bg-background-base": merged() || hover(),
1924+
"bg-background-stronger": !merged() && !hover(),
19241925
"flex-1 min-w-0": panelProps.mobile,
19251926
"max-w-full overflow-hidden": panelProps.mobile,
19261927
}}

packages/app/src/pages/layout/sidebar-project.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ const ProjectTile = (props: {
9191
modal={!props.sidebarHovering()}
9292
onOpenChange={(value) => {
9393
props.setMenu(value)
94+
props.setSuppressHover(value)
9495
if (value) props.setOpen(false)
9596
}}
9697
>
@@ -107,6 +108,12 @@ const ProjectTile = (props: {
107108
!props.selected() && !props.active(),
108109
"bg-surface-base-hover border border-border-weak-base": !props.selected() && props.active(),
109110
}}
111+
onPointerDown={(event) => {
112+
if (!props.overlay()) return
113+
if (event.button !== 2 && !(event.button === 0 && event.ctrlKey)) return
114+
props.setSuppressHover(true)
115+
event.preventDefault()
116+
}}
110117
onMouseEnter={(event: MouseEvent) => {
111118
if (!props.overlay()) return
112119
if (props.suppressHover()) return

0 commit comments

Comments
 (0)