Skip to content

Commit 77706f8

Browse files
authored
Merge branch 'dev' into fix/acp-show-proper-run-command-message
2 parents 46d011f + 2c36cbb commit 77706f8

124 files changed

Lines changed: 1999 additions & 833 deletions

File tree

Some content is hidden

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

.github/actions/setup-git-committer/action.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ runs:
2323
with:
2424
app-id: ${{ inputs.opencode-app-id }}
2525
private-key: ${{ inputs.opencode-app-secret }}
26+
owner: ${{ github.repository_owner }}
2627

2728
- name: Configure git user
2829
run: |

.github/pull_request_template.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
### What does this PR do?
22

3+
Please provide a description of the issue (if there is one), the changes you made to fix it, and why they work. It is expected that you understand why your changes work and if you do not understand why at least say as much so a maintainer knows how much to value the pr.
4+
5+
**If you paste a large clearly AI generated description here your PR may be IGNORED or CLOSED!**
6+
37
### How did you verify your code works?

.github/workflows/generate.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ on:
44
push:
55
branches:
66
- dev
7-
pull_request:
8-
workflow_dispatch:
97

108
jobs:
119
generate:

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ jobs:
103103
target: x86_64-pc-windows-msvc
104104
- host: blacksmith-4vcpu-ubuntu-2404
105105
target: x86_64-unknown-linux-gnu
106-
- host: blacksmith-4vcpu-ubuntu-2404-arm
106+
- host: blacksmith-8vcpu-ubuntu-2404-arm
107107
target: aarch64-unknown-linux-gnu
108108
runs-on: ${{ matrix.settings.host }}
109109
steps:

bun.lock

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

infra/console.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ const ZEN_MODELS = [
133133
new sst.Secret("ZEN_MODELS6"),
134134
new sst.Secret("ZEN_MODELS7"),
135135
new sst.Secret("ZEN_MODELS8"),
136+
new sst.Secret("ZEN_MODELS9"),
137+
new sst.Secret("ZEN_MODELS10"),
136138
]
137139
const STRIPE_SECRET_KEY = new sst.Secret("STRIPE_SECRET_KEY")
138140
const STRIPE_PUBLISHABLE_KEY = new sst.Secret("STRIPE_PUBLISHABLE_KEY")

packages/app/e2e/actions.ts

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import { expect, type Locator, type Page } from "@playwright/test"
2+
import fs from "node:fs/promises"
3+
import os from "node:os"
4+
import path from "node:path"
5+
import { execSync } from "node:child_process"
6+
import { modKey, serverUrl } from "./utils"
7+
8+
export async function defocus(page: Page) {
9+
await page.mouse.click(5, 5)
10+
}
11+
12+
export async function openPalette(page: Page) {
13+
await defocus(page)
14+
await page.keyboard.press(`${modKey}+P`)
15+
16+
const dialog = page.getByRole("dialog")
17+
await expect(dialog).toBeVisible()
18+
await expect(dialog.getByRole("textbox").first()).toBeVisible()
19+
return dialog
20+
}
21+
22+
export async function closeDialog(page: Page, dialog: Locator) {
23+
await page.keyboard.press("Escape")
24+
const closed = await dialog
25+
.waitFor({ state: "detached", timeout: 1500 })
26+
.then(() => true)
27+
.catch(() => false)
28+
29+
if (closed) return
30+
31+
await page.keyboard.press("Escape")
32+
const closedSecond = await dialog
33+
.waitFor({ state: "detached", timeout: 1500 })
34+
.then(() => true)
35+
.catch(() => false)
36+
37+
if (closedSecond) return
38+
39+
await page.locator('[data-component="dialog-overlay"]').click({ position: { x: 5, y: 5 } })
40+
await expect(dialog).toHaveCount(0)
41+
}
42+
43+
export async function isSidebarClosed(page: Page) {
44+
const main = page.locator("main")
45+
const classes = (await main.getAttribute("class")) ?? ""
46+
return classes.includes("xl:border-l")
47+
}
48+
49+
export async function toggleSidebar(page: Page) {
50+
await defocus(page)
51+
await page.keyboard.press(`${modKey}+B`)
52+
}
53+
54+
export async function openSidebar(page: Page) {
55+
if (!(await isSidebarClosed(page))) return
56+
await toggleSidebar(page)
57+
await expect(page.locator("main")).not.toHaveClass(/xl:border-l/)
58+
}
59+
60+
export async function closeSidebar(page: Page) {
61+
if (await isSidebarClosed(page)) return
62+
await toggleSidebar(page)
63+
await expect(page.locator("main")).toHaveClass(/xl:border-l/)
64+
}
65+
66+
export async function openSettings(page: Page) {
67+
await defocus(page)
68+
69+
const dialog = page.getByRole("dialog")
70+
await page.keyboard.press(`${modKey}+Comma`).catch(() => undefined)
71+
72+
const opened = await dialog
73+
.waitFor({ state: "visible", timeout: 3000 })
74+
.then(() => true)
75+
.catch(() => false)
76+
77+
if (opened) return dialog
78+
79+
await page.getByRole("button", { name: "Settings" }).first().click()
80+
await expect(dialog).toBeVisible()
81+
return dialog
82+
}
83+
84+
export async function seedProjects(page: Page, input: { directory: string; extra?: string[] }) {
85+
await page.addInitScript(
86+
(args: { directory: string; serverUrl: string; extra: string[] }) => {
87+
const key = "opencode.global.dat:server"
88+
const raw = localStorage.getItem(key)
89+
const parsed = (() => {
90+
if (!raw) return undefined
91+
try {
92+
return JSON.parse(raw) as unknown
93+
} catch {
94+
return undefined
95+
}
96+
})()
97+
98+
const store = parsed && typeof parsed === "object" ? (parsed as Record<string, unknown>) : {}
99+
const list = Array.isArray(store.list) ? store.list : []
100+
const lastProject = store.lastProject && typeof store.lastProject === "object" ? store.lastProject : {}
101+
const projects = store.projects && typeof store.projects === "object" ? store.projects : {}
102+
const nextProjects = { ...(projects as Record<string, unknown>) }
103+
104+
const add = (origin: string, directory: string) => {
105+
const current = nextProjects[origin]
106+
const items = Array.isArray(current) ? current : []
107+
const existing = items.filter(
108+
(p): p is { worktree: string; expanded?: boolean } =>
109+
!!p &&
110+
typeof p === "object" &&
111+
"worktree" in p &&
112+
typeof (p as { worktree?: unknown }).worktree === "string",
113+
)
114+
115+
if (existing.some((p) => p.worktree === directory)) return
116+
nextProjects[origin] = [{ worktree: directory, expanded: true }, ...existing]
117+
}
118+
119+
const directories = [args.directory, ...args.extra]
120+
for (const directory of directories) {
121+
add("local", directory)
122+
add(args.serverUrl, directory)
123+
}
124+
125+
localStorage.setItem(
126+
key,
127+
JSON.stringify({
128+
list,
129+
projects: nextProjects,
130+
lastProject,
131+
}),
132+
)
133+
},
134+
{ directory: input.directory, serverUrl, extra: input.extra ?? [] },
135+
)
136+
}
137+
138+
export async function createTestProject() {
139+
const root = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-e2e-project-"))
140+
141+
await fs.writeFile(path.join(root, "README.md"), "# e2e\n")
142+
143+
execSync("git init", { cwd: root, stdio: "ignore" })
144+
execSync("git add -A", { cwd: root, stdio: "ignore" })
145+
execSync('git -c user.name="e2e" -c user.email="[email protected]" commit -m "init" --allow-empty', {
146+
cwd: root,
147+
stdio: "ignore",
148+
})
149+
150+
return root
151+
}
152+
153+
export async function cleanupTestProject(directory: string) {
154+
await fs.rm(directory, { recursive: true, force: true }).catch(() => undefined)
155+
}
156+
157+
export function sessionIDFromUrl(url: string) {
158+
const match = /\/session\/([^/?#]+)/.exec(url)
159+
return match?.[1]
160+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { test, expect } from "./fixtures"
2-
import { serverName } from "./utils"
1+
import { test, expect } from "../fixtures"
2+
import { serverName } from "../utils"
33

44
test("home renders and shows core entrypoints", async ({ page }) => {
55
await page.goto("/")
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import { test, expect } from "./fixtures"
2-
import { dirPath, promptSelector } from "./utils"
1+
import { test, expect } from "../fixtures"
2+
import { promptSelector } from "../selectors"
3+
import { dirPath } from "../utils"
34

45
test("project route redirects to /session", async ({ page, directory, slug }) => {
56
await page.goto(dirPath(directory))
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { test, expect } from "../fixtures"
2+
import { openPalette } from "../actions"
3+
4+
test("search palette opens and closes", async ({ page, gotoSession }) => {
5+
await gotoSession()
6+
7+
const dialog = await openPalette(page)
8+
9+
await page.keyboard.press("Escape")
10+
await expect(dialog).toHaveCount(0)
11+
})

0 commit comments

Comments
 (0)