diff --git a/.github/actions/setup-bun/action.yml b/.github/actions/setup-bun/action.yml
index 3f06da519..f53f20fcd 100644
--- a/.github/actions/setup-bun/action.yml
+++ b/.github/actions/setup-bun/action.yml
@@ -3,14 +3,6 @@ description: "Setup Bun with caching and install dependencies"
runs:
using: "composite"
steps:
- - name: Cache Bun dependencies
- uses: actions/cache@v4
- with:
- path: ~/.bun/install/cache
- key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }}
- restore-keys: |
- ${{ runner.os }}-bun-
-
- name: Get baseline download URL
id: bun-url
shell: bash
@@ -31,6 +23,19 @@ runs:
bun-version-file: ${{ !steps.bun-url.outputs.url && 'package.json' || '' }}
bun-download-url: ${{ steps.bun-url.outputs.url }}
+ - name: Get cache directory
+ id: cache
+ shell: bash
+ run: echo "dir=$(bun pm cache)" >> "$GITHUB_OUTPUT"
+
+ - name: Cache Bun dependencies
+ uses: actions/cache@v4
+ with:
+ path: ${{ steps.cache.outputs.dir }}
+ key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-bun-
+
- name: Install setuptools for distutils compatibility
run: python3 -m pip install setuptools || pip install setuptools || true
shell: bash
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 079e6d6f0..b425b32a5 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -115,6 +115,9 @@ jobs:
target: x86_64-apple-darwin
- host: macos-latest
target: aarch64-apple-darwin
+ # github-hosted: blacksmith lacks ARM64 MSVC cross-compilation toolchain
+ - host: windows-2025
+ target: aarch64-pc-windows-msvc
- host: blacksmith-4vcpu-windows-2025
target: x86_64-pc-windows-msvc
- host: blacksmith-4vcpu-ubuntu-2404
@@ -258,6 +261,10 @@ jobs:
- host: macos-latest
target: aarch64-apple-darwin
platform_flag: --mac --arm64
+ # github-hosted: blacksmith lacks ARM64 MSVC cross-compilation toolchain
+ - host: "windows-2025"
+ target: aarch64-pc-windows-msvc
+ platform_flag: --win --arm64
- host: "blacksmith-4vcpu-windows-2025"
target: x86_64-pc-windows-msvc
platform_flag: --win
diff --git a/bun.lock b/bun.lock
index 1721ba330..5e66e3e16 100644
--- a/bun.lock
+++ b/bun.lock
@@ -392,6 +392,7 @@
"@parcel/watcher-linux-arm64-musl": "2.5.1",
"@parcel/watcher-linux-x64-glibc": "2.5.1",
"@parcel/watcher-linux-x64-musl": "2.5.1",
+ "@parcel/watcher-win32-arm64": "2.5.1",
"@parcel/watcher-win32-x64": "2.5.1",
"@standard-schema/spec": "1.0.0",
"@tsconfig/bun": "catalog:",
diff --git a/infra/console.ts b/infra/console.ts
index 128e06986..c7889c587 100644
--- a/infra/console.ts
+++ b/infra/console.ts
@@ -103,6 +103,12 @@ export const stripeWebhook = new stripe.WebhookEndpoint("StripeWebhookEndpoint",
const zenLiteProduct = new stripe.Product("ZenLite", {
name: "OpenCode Go",
})
+const zenLiteCouponFirstMonth50 = new stripe.Coupon("ZenLiteCouponFirstMonth50", {
+ name: "First month 50% off",
+ percentOff: 50,
+ appliesToProducts: [zenLiteProduct.id],
+ duration: "once",
+})
const zenLitePrice = new stripe.Price("ZenLitePrice", {
product: zenLiteProduct.id,
currency: "usd",
@@ -116,6 +122,7 @@ const ZEN_LITE_PRICE = new sst.Linkable("ZEN_LITE_PRICE", {
properties: {
product: zenLiteProduct.id,
price: zenLitePrice.id,
+ firstMonth50Coupon: zenLiteCouponFirstMonth50.id,
},
})
diff --git a/packages/app/e2e/prompt/prompt-slash-terminal.spec.ts b/packages/app/e2e/prompt/prompt-slash-terminal.spec.ts
index bf9f96b47..fa884b752 100644
--- a/packages/app/e2e/prompt/prompt-slash-terminal.spec.ts
+++ b/packages/app/e2e/prompt/prompt-slash-terminal.spec.ts
@@ -6,16 +6,29 @@ test("/terminal toggles the terminal panel", async ({ page, gotoSession }) => {
const prompt = page.locator(promptSelector)
const terminal = page.locator(terminalSelector)
+ const slash = page.locator('[data-slash-id="terminal.toggle"]').first()
await expect(terminal).not.toBeVisible()
await prompt.fill("/terminal")
- await expect(page.locator('[data-slash-id="terminal.toggle"]').first()).toBeVisible()
+ await expect(slash).toBeVisible()
await page.keyboard.press("Enter")
await expect(terminal).toBeVisible()
- await prompt.fill("/terminal")
- await expect(page.locator('[data-slash-id="terminal.toggle"]').first()).toBeVisible()
+ // Terminal panel retries focus (immediate, RAF, 120ms, 240ms) after opening,
+ // which can steal focus from the prompt and prevent fill() from triggering
+ // the slash popover. Re-attempt click+fill until all retries are exhausted
+ // and the popover appears.
+ await expect
+ .poll(
+ async () => {
+ await prompt.click().catch(() => false)
+ await prompt.fill("/terminal").catch(() => false)
+ return slash.isVisible().catch(() => false)
+ },
+ { timeout: 10_000 },
+ )
+ .toBe(true)
await page.keyboard.press("Enter")
await expect(terminal).not.toBeVisible()
})
diff --git a/packages/console/app/src/component/header.tsx b/packages/console/app/src/component/header.tsx
index 24d5a897c..1e129d590 100644
--- a/packages/console/app/src/component/header.tsx
+++ b/packages/console/app/src/component/header.tsx
@@ -161,16 +161,12 @@ export function Header(props: { zen?: boolean; go?: boolean; hideGetStarted?: bo
{i18n.t("nav.docs")}
-
-
- {i18n.t("nav.zen")}
-
-
-
-
- {i18n.t("nav.go")}
-
-
+
+ {i18n.t("nav.zen")}
+
+
+ {i18n.t("nav.go")}
+
{i18n.t("nav.enterprise")}
diff --git a/packages/console/app/src/component/icon.tsx b/packages/console/app/src/component/icon.tsx
index 1225aeb10..e39da4a0e 100644
--- a/packages/console/app/src/component/icon.tsx
+++ b/packages/console/app/src/component/icon.tsx
@@ -1,69 +1,25 @@
import { JSX } from "solid-js"
-export function IconLogo(props: JSX.SvgSVGAttributes) {
+export function IconZen(props: JSX.SvgSVGAttributes) {
return (
-