Skip to content

Commit 8055f91

Browse files
author
Andrew Maguire
committed
Merge branch 'dev' of https://github.com/anduimagui/opencode into dev
2 parents 5ef0ad3 + c3ddc85 commit 8055f91

579 files changed

Lines changed: 24333 additions & 11985 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/VOUCHED.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ r44vc0rp
2121
rekram1-node
2222
-spider-yamet clawdbot/llm psychosis, spam pinging the team
2323
thdxr
24+
-OpenCode2026

.github/actions/setup-bun/action.yml

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,6 @@ description: "Setup Bun with caching and install dependencies"
33
runs:
44
using: "composite"
55
steps:
6-
- name: Cache Bun dependencies
7-
uses: actions/cache@v4
8-
with:
9-
path: ~/.bun/install/cache
10-
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }}
11-
restore-keys: |
12-
${{ runner.os }}-bun-
13-
146
- name: Get baseline download URL
157
id: bun-url
168
shell: bash
@@ -31,10 +23,31 @@ runs:
3123
bun-version-file: ${{ !steps.bun-url.outputs.url && 'package.json' || '' }}
3224
bun-download-url: ${{ steps.bun-url.outputs.url }}
3325

26+
- name: Get cache directory
27+
id: cache
28+
shell: bash
29+
run: echo "dir=$(bun pm cache)" >> "$GITHUB_OUTPUT"
30+
31+
- name: Cache Bun dependencies
32+
uses: actions/cache@v4
33+
with:
34+
path: ${{ steps.cache.outputs.dir }}
35+
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
36+
restore-keys: |
37+
${{ runner.os }}-bun-
38+
3439
- name: Install setuptools for distutils compatibility
3540
run: python3 -m pip install setuptools || pip install setuptools || true
3641
shell: bash
3742

3843
- name: Install dependencies
39-
run: bun install
44+
run: |
45+
# Workaround for patched peer variants
46+
# e.g. ./patches/ for standard-openapi
47+
# https://github.com/oven-sh/bun/issues/28147
48+
if [ "$RUNNER_OS" = "Windows" ]; then
49+
bun install --linker hoisted
50+
else
51+
bun install
52+
fi
4053
shell: bash

.github/workflows/publish.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ jobs:
115115
target: x86_64-apple-darwin
116116
- host: macos-latest
117117
target: aarch64-apple-darwin
118+
# github-hosted: blacksmith lacks ARM64 MSVC cross-compilation toolchain
119+
- host: windows-2025
120+
target: aarch64-pc-windows-msvc
118121
- host: blacksmith-4vcpu-windows-2025
119122
target: x86_64-pc-windows-msvc
120123
- host: blacksmith-4vcpu-ubuntu-2404
@@ -149,6 +152,10 @@ jobs:
149152
150153
- uses: ./.github/actions/setup-bun
151154

155+
- uses: actions/setup-node@v4
156+
with:
157+
node-version: "24"
158+
152159
- name: Cache apt packages
153160
if: contains(matrix.settings.host, 'ubuntu')
154161
uses: actions/cache@v4
@@ -254,6 +261,10 @@ jobs:
254261
- host: macos-latest
255262
target: aarch64-apple-darwin
256263
platform_flag: --mac --arm64
264+
# github-hosted: blacksmith lacks ARM64 MSVC cross-compilation toolchain
265+
- host: "windows-2025"
266+
target: aarch64-pc-windows-msvc
267+
platform_flag: --win --arm64
257268
- host: "blacksmith-4vcpu-windows-2025"
258269
target: x86_64-pc-windows-msvc
259270
platform_flag: --win

.github/workflows/test.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ on:
88
workflow_dispatch:
99

1010
concurrency:
11-
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
11+
# Keep every run on dev so cancelled checks do not pollute the default branch
12+
# commit history. PRs and other branches still share a group and cancel stale runs.
13+
group: ${{ case(github.ref == 'refs/heads/dev', format('{0}-{1}', github.workflow, github.run_id), format('{0}-{1}', github.workflow, github.event.pull_request.number || github.ref)) }}
1214
cancel-in-progress: true
1315

1416
permissions:

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ ts-dist
1717
/result
1818
refs
1919
Session.vim
20-
opencode.json
20+
/opencode.json
2121
a.out
2222
target
2323
.scripts

bun.lock

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

infra/console.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@ export const stripeWebhook = new stripe.WebhookEndpoint("StripeWebhookEndpoint",
103103
const zenLiteProduct = new stripe.Product("ZenLite", {
104104
name: "OpenCode Go",
105105
})
106+
const zenLiteCouponFirstMonth50 = new stripe.Coupon("ZenLiteCouponFirstMonth50", {
107+
name: "First month 50% off",
108+
percentOff: 50,
109+
appliesToProducts: [zenLiteProduct.id],
110+
duration: "once",
111+
})
106112
const zenLitePrice = new stripe.Price("ZenLitePrice", {
107113
product: zenLiteProduct.id,
108114
currency: "usd",
@@ -116,6 +122,7 @@ const ZEN_LITE_PRICE = new sst.Linkable("ZEN_LITE_PRICE", {
116122
properties: {
117123
product: zenLiteProduct.id,
118124
price: zenLitePrice.id,
125+
firstMonth50Coupon: zenLiteCouponFirstMonth50.id,
119126
},
120127
})
121128

@@ -194,6 +201,10 @@ const bucketNew = new sst.cloudflare.Bucket("ZenDataNew")
194201
const AWS_SES_ACCESS_KEY_ID = new sst.Secret("AWS_SES_ACCESS_KEY_ID")
195202
const AWS_SES_SECRET_ACCESS_KEY = new sst.Secret("AWS_SES_SECRET_ACCESS_KEY")
196203

204+
const SALESFORCE_CLIENT_ID = new sst.Secret("SALESFORCE_CLIENT_ID")
205+
const SALESFORCE_CLIENT_SECRET = new sst.Secret("SALESFORCE_CLIENT_SECRET")
206+
const SALESFORCE_INSTANCE_URL = new sst.Secret("SALESFORCE_INSTANCE_URL")
207+
197208
const logProcessor = new sst.cloudflare.Worker("LogProcessor", {
198209
handler: "packages/console/function/src/log-processor.ts",
199210
link: [new sst.Secret("HONEYCOMB_API_KEY")],
@@ -212,6 +223,9 @@ new sst.cloudflare.x.SolidStart("Console", {
212223
EMAILOCTOPUS_API_KEY,
213224
AWS_SES_ACCESS_KEY_ID,
214225
AWS_SES_SECRET_ACCESS_KEY,
226+
SALESFORCE_CLIENT_ID,
227+
SALESFORCE_CLIENT_SECRET,
228+
SALESFORCE_INSTANCE_URL,
215229
ZEN_BLACK_PRICE,
216230
ZEN_LITE_PRICE,
217231
new sst.Secret("ZEN_LIMITS"),

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-dhL4YeSi4Lm9yDp919Fx7N2hyLUbZQa2qWoCf/50ce8=",
4-
"aarch64-linux": "sha256-//YxCsrvYlxuvd0MtFFO+pLxjmuemyrvGzSIPxzO+rA=",
5-
"aarch64-darwin": "sha256-c65kSWteQNaBcQUsjbXNqT61vt98JPNYo9yMNvUygCw=",
6-
"x86_64-darwin": "sha256-hlTzEFv3nZHwlDXU65LfMC+NaqYjjyZqagdJ366CNxY="
3+
"x86_64-linux": "sha256-VF3rXpIz9XbTTfM8YB98DJJOs4Sotaq5cSwIBUfbNDA=",
4+
"aarch64-linux": "sha256-cIE10+0xhb5u0TQedaDbEu6e40ypHnSBmh8unnhCDZE=",
5+
"aarch64-darwin": "sha256-d/l7g/4angRw/oxoSGpcYL0i9pNphgRChJwhva5Kypo=",
6+
"x86_64-darwin": "sha256-WQyuUKMfHpO1rpWsjhCXuG99iX2jEdSe3AVltxvt+1Y="
77
}
88
}

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"dev": "bun run --cwd packages/opencode --conditions=browser src/index.ts",
1010
"dev:desktop": "bun --cwd packages/desktop tauri dev",
1111
"dev:web": "bun --cwd packages/app dev",
12+
"dev:console": "ulimit -n 10240 2>/dev/null; bun run --cwd packages/console/app dev",
1213
"dev:storybook": "bun --cwd packages/storybook storybook",
1314
"typecheck": "bun turbo typecheck",
1415
"prepare": "husky",
@@ -44,7 +45,7 @@
4445
"dompurify": "3.3.1",
4546
"drizzle-kit": "1.0.0-beta.16-ea816b6",
4647
"drizzle-orm": "1.0.0-beta.16-ea816b6",
47-
"effect": "4.0.0-beta.29",
48+
"effect": "4.0.0-beta.31",
4849
"ai": "5.0.124",
4950
"hono": "4.10.7",
5051
"hono-openapi": "1.1.2",

packages/app/e2e/AGENTS.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ test("test description", async ({ page, sdk, gotoSession }) => {
7070
- `openSettings(page)` - Open settings dialog
7171
- `closeDialog(page, dialog)` - Close any dialog
7272
- `openSidebar(page)` / `closeSidebar(page)` - Toggle sidebar
73+
- `waitTerminalReady(page, { term? })` - Wait for a mounted terminal to connect and finish rendering output
74+
- `runTerminal(page, { cmd, token, term?, timeout? })` - Type into the terminal via the browser and wait for rendered output
7375
- `withSession(sdk, title, callback)` - Create temp session
7476
- `withProject(...)` - Create temp project/workspace
7577
- `sessionIDFromUrl(url)` - Read session ID from URL
@@ -167,6 +169,42 @@ await page.keyboard.press(`${modKey}+B`) // Toggle sidebar
167169
await page.keyboard.press(`${modKey}+Comma`) // Open settings
168170
```
169171

172+
### Terminal Tests
173+
174+
- In terminal tests, type through the browser. Do not write to the PTY through the SDK.
175+
- Use `waitTerminalReady(page, { term? })` and `runTerminal(page, { cmd, token, term?, timeout? })` from `actions.ts`.
176+
- These helpers use the fixture-enabled test-only terminal driver and wait for output after the terminal writer settles.
177+
- After opening the terminal, use `waitTerminalFocusIdle(...)` before the next keyboard action when prompt focus or keyboard routing matters.
178+
- This avoids racing terminal mount, focus handoff, and prompt readiness when the next step types or sends shortcuts.
179+
- Avoid `waitForTimeout` and custom DOM or `data-*` readiness checks.
180+
181+
### Wait on state
182+
183+
- Never use wall-clock waits like `page.waitForTimeout(...)` to make a test pass
184+
- Avoid race-prone flows that assume work is finished after an action
185+
- Wait or poll on observable state with `expect(...)`, `expect.poll(...)`, or existing helpers
186+
- Prefer locator assertions like `toBeVisible()`, `toHaveCount(0)`, and `toHaveAttribute(...)` for normal UI state, and reserve `expect.poll(...)` for probe, mock, or backend state
187+
- Prefer semantic app state over transient DOM visibility when behavior depends on active selection, focus ownership, or async retry loops
188+
- Do not treat a visible element as proof that the app will route the next action to it
189+
- When fixing a flake, validate with `--repeat-each` and multiple workers when practical
190+
191+
### Add hooks
192+
193+
- If required state is not observable from the UI, add a small test-only driver or probe in app code instead of sleeps or fragile DOM checks
194+
- Keep these hooks minimal and purpose-built, following the style of `packages/app/src/testing/terminal.ts`
195+
- Test-only hooks must be inert unless explicitly enabled; do not add normal-runtime listeners, reactive subscriptions, or per-update allocations for e2e ceremony
196+
- When mocking routes or APIs, expose explicit mock state and wait on that before asserting post-action UI
197+
- Add minimal test-only probes for semantic state like the active list item or selected command when DOM intermediates are unstable
198+
- Prefer probing committed app state over asserting on transient highlight, visibility, or animation states
199+
200+
### Prefer helpers
201+
202+
- Prefer fluent helpers and drivers when they make intent obvious and reduce locator-heavy noise
203+
- Use direct locators when the interaction is simple and a helper would not add clarity
204+
- Prefer helpers that both perform an action and verify the app consumed it
205+
- Avoid composing helpers redundantly when one already includes the other or already waits for the resulting state
206+
- If a helper already covers the required wait or verification, use it directly instead of layering extra clicks, keypresses, or assertions
207+
170208
## Writing New Tests
171209

172210
1. Choose appropriate folder or create new one

0 commit comments

Comments
 (0)