Skip to content

Commit 705da59

Browse files
Zexiclaude
authored andcommitted
docs: update FORK.md for zexi/dev-clean branch structure
Refresh commit SHAs, consolidate 17 scattered commits into 5 logical sections, and add invariant anomalyco#4 for the 401 redirect-loop fix. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent c370615 commit 705da59

1 file changed

Lines changed: 82 additions & 98 deletions

File tree

FORK.md

Lines changed: 82 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,25 @@ quickly.
88

99
## How to rebase
1010

11-
The workflow `sync-upstream.yml` runs every Friday and rebases `zexi/dev` onto
12-
upstream automatically. After a rebase, verify the [behavioral invariants](#behavioral-invariants) below.
11+
The workflow `sync-upstream.yml` runs every Friday and opens a PR rebasing
12+
`zexi/dev` onto upstream automatically.
1313

14-
Manual rebase if needed:
14+
Manual rebase onto a clean branch:
1515

1616
```sh
1717
git fetch upstream
18-
git rebase --onto upstream/dev $(git merge-base HEAD upstream/dev) zexi/dev
18+
git checkout -b zexi/dev-clean upstream/dev
19+
git merge --squash zexi/dev
20+
# resolve conflicts, then commit in logical groups (see commits below)
1921
```
2022

2123
---
2224

2325
## Fork commits (relative to upstream/dev)
2426

25-
### 1 · Release workflows — `f4bb5ae17`
27+
### 1 · Release workflows — `dfa2df240`
2628

27-
**Files:** `.github/workflows/zexi-electron.yml`, `.github/workflows/sync-upstream.yml`, `packages/desktop/electron-builder.config.ts`, `packages/script/src/index.ts`
29+
**Files:** `.github/workflows/zexi-electron.yml`, `.github/workflows/sync-upstream.yml`
2830

2931
Custom CI that builds and releases signed macOS (arm64 + notarization) and
3032
Windows (x64 + Azure trusted signing) Electron packages on every push to
@@ -33,124 +35,105 @@ pruned to keep the 3 most recent.
3335

3436
The sync workflow disables all upstream workflows except these two.
3537

36-
**Rebase risk:** Low — touches only `.github/` and build config. Conflicts
37-
typically arise if upstream renames `electron-builder.config.ts`.
38+
**Rebase risk:** Low — touches only `.github/`. Conflicts only if upstream
39+
renames its own workflow files.
3840

3941
---
4042

41-
### 2 · Configure desktop local server access — `78b5d1182`
43+
### 2 · Configure desktop local server access and sync opened projects `bd776bfa3`
4244

43-
**Files:** `packages/app/src/components/dialog-select-server.tsx`, `packages/app/src/components/server/server-row.tsx`, `packages/app/src/components/status-popover*.tsx`, `packages/desktop/src/main/{index,ipc,server,sidecar}.ts`, `packages/desktop/src/preload/`, `packages/opencode/src/config/server.ts`, i18n files
45+
**Files:** `packages/app/src/components/dialog-select-server.tsx`, `packages/app/src/components/server/server-row.tsx`, `packages/app/src/components/status-popover*.tsx`, `packages/desktop/src/main/{index,ipc,server,sidecar,constants}.ts`, `packages/desktop/src/preload/`, `packages/opencode/src/config/{server,projects}.ts`, `packages/opencode/src/server/shared/opened-projects{,.sql}.ts`, `packages/opencode/src/server/routes/instance/httpapi/{groups,handlers}/global.ts`, `packages/opencode/migration/20260511170500_opened_projects_db/migration.sql`, `packages/sdk/js/src/v2/gen/`, i18n files
4446

45-
**What it does:** Adds UI for users to configure the local Electron-embedded
46-
server's hostname, port, username, and password from within the app. Previously
47-
these could only be set via environment variables. The config is persisted in
48-
Electron's store under `localServerConfig` (see `constants.ts`).
49-
50-
Key additions:
51-
- IPC channels: `get-local-server-config`, `set-local-server-config`
52-
- `getLocalServerConfig() / setLocalServerConfig()` in `server.ts`
53-
- Server dialog revamp in `dialog-select-server.tsx` — includes a local-server
54-
config panel when running in desktop mode
55-
- Status bar server icon (bottom-left) opens the server selection/config dialog
56-
57-
**Rebase risk:** High — touches many app-layer files. Conflicts are likely if
58-
upstream refactors `status-popover`, `dialog-select-server`, or the desktop
59-
main/preload plumbing.
60-
61-
---
62-
63-
### 3 · Sync opened projects through server events — `7aa32f066`
64-
65-
**Files:** `packages/app/src/context/opened-projects.tsx`, `packages/opencode/src/config/projects.ts`, `packages/opencode/src/server/routes/instance/httpapi/{groups,handlers}/global.ts`, `packages/sdk/js/src/v2/gen/`
47+
**What it does:**
6648

67-
**What it does:** Moves opened-project state from scattered per-component state
68-
into a single `OpenedProjectsContext` (Solid.js). The context subscribes to the
69-
`project.opened.updated` server-sent event so all windows/tabs stay in sync
70-
without polling.
49+
**a) Local server config UI**
50+
Adds UI for users to configure the local Electron-embedded server's hostname,
51+
port, username, and password from within the app. Config is persisted in
52+
Electron's store under `localServerConfig`. Key IPC channels:
53+
`get-local-server-config`, `set-local-server-config`.
7154

72-
Adds server-side API routes under `/global` for listing, opening, closing, and
73-
reordering opened projects. Also extends the JS SDK types accordingly.
55+
**b) Opened projects sync**
56+
Moves opened-project state into a single `OpenedProjectsContext` (Solid.js)
57+
backed by a server-side SQLite table (`OpenedProjectTable`). All windows/tabs
58+
subscribe to the `project.opened.updated` SSE event and stay in sync without
59+
polling. Server-side API routes under `/global` handle list, open, close, and
60+
reorder.
7461

75-
**Rebase risk:** Medium — `handlers/global.ts` and the SDK generated files are
76-
common conflict points if upstream adds routes in the same files.
62+
**Rebase risk:** High — touches many app-layer files. Most likely conflict
63+
points: `status-popover.tsx`, `dialog-select-server.tsx`, `handlers/global.ts`,
64+
and the SDK generated files.
7765

7866
---
7967

80-
### 4 · Keep opened project metadata single-sourced `02416fa48`
68+
### 3 · Embed and serve web UI from sidecar `54660edfa`
8169

82-
**Files:** `packages/opencode/src/server/shared/opened-projects.ts` (new), `packages/opencode/src/server/shared/opened-projects.sql.ts` (new), `packages/desktop/src/main/{server,ipc,constants}.ts`, `packages/app/src/context/{platform,server,opened-projects}.tsx`, `packages/app/src/pages/layout.tsx`
70+
**Files:** `packages/core/src/flag/flag.ts`, `packages/desktop/electron-builder.config.ts`, `packages/desktop/electron.vite.config.ts`, `packages/desktop/scripts/prebuild.ts`, `packages/opencode/src/config/server.ts`, `packages/opencode/src/server/shared/{public-ui,ui}.ts`
8371

84-
**What it does:** Persists opened-project metadata (name, icon, commands,
85-
ordering) in the opencode SQLite database via a dedicated `OpenedProjectTable`,
86-
rather than duplicating it across Electron store and server memory. This was a
87-
follow-up fix after the upstream rebase broke the original implementation.
72+
**What it does:**
73+
Bundles the web SPA into the sidecar binary at build time via a generated
74+
module (`opencode-web-ui.gen.ts`). The sidecar serves it directly, with a
75+
priority chain:
8876

89-
Also stores `localServerConfig` in Electron store (previously it lived only in
90-
memory), fixing the config disappearing on restart.
77+
1. Embedded bundle (`opencode-web-ui.gen.ts`) — production
78+
2. Local directory (`OPENCODE_DEV_UI_DIR`) — dev mode, set automatically in
79+
Electron dev to `packages/app/dist`
80+
3. Proxy to `https://app.opencode.ai` (override with `OPENCODE_DEV_UI_URL`) —
81+
fallback
9182

92-
**Rebase risk:** Medium-High — `opened-projects.ts` is a new file owned by this
93-
fork; conflicts arise only if upstream creates a file at the same path. The
94-
migration SQL file path must stay unique.
83+
Static assets (HTML shell, JS/CSS bundles, icons, favicons) under
84+
`isPublicUIPath()` are served without authentication so a remote browser can
85+
load the UI shell before entering credentials.
9586

96-
---
87+
**Prerequisite for dev:** build `packages/app` first:
88+
```sh
89+
cd packages/app && bun run build
90+
```
9791

98-
### 5 · Allow web UI shell without auth — `b8c154e01`
92+
**Rebase risk:** Medium — `ui.ts` conflicts if upstream restructures
93+
`serveUIEffect`. `flag.ts` conflicts if upstream adds flags at the same
94+
location.
9995

100-
**Files:** `packages/opencode/src/server/shared/public-ui.ts`, `packages/opencode/test/server/httpapi-ui.test.ts`
96+
---
10197

102-
**What it does:** Static assets (HTML shell, JS bundles, CSS, icons, favicons)
103-
are served without requiring authentication, so a remote browser can load the
104-
app UI shell before the user has entered credentials. API routes remain
105-
protected.
98+
### 4 · Serve SPA at any subpath without auth, display auth-required page on 401 — `7bac50fd8`
10699

107-
`isPublicUIPath()` returns `true` for:
108-
- `/`, `/index.html`, `/site.webmanifest`, manifest PNGs
109-
- `/assets/*` (JS/CSS bundles)
110-
- `/favicon*`, `/apple-touch-icon*`, `/social-share.*`
100+
**Files:** `packages/opencode/src/server/routes/instance/httpapi/middleware/authorization.ts`, `packages/opencode/src/server/routes/instance/httpapi/server.ts`, `packages/app/src/pages/error.tsx`, `packages/app/src/pages/session.tsx`, `packages/app/src/i18n/{en,zh,zht}.ts`, `packages/opencode/test/server/httpapi-ui.test.ts`
111101

112-
**Why this matters:** Without this, a remote browser hitting the server gets a
113-
401 on the very first request and cannot load anything — the user has no way to
114-
enter credentials.
102+
**What it does:**
115103

116-
**Rebase risk:** Low — `public-ui.ts` is a small file. Conflict only if upstream
117-
adds its own public-path logic here.
104+
**a) SPA catch-all serves without auth**
105+
The `/*` route loads unconditionally (no credentials check) so the browser can
106+
bootstrap the SPA shell at any subpath. API routes under `/global/*` and
107+
instance routes remain fully protected.
118108

119-
---
109+
**b) Bearer auth scheme**
110+
`WWW-Authenticate` is `Bearer realm="Secure Area"` instead of `Basic`. This
111+
suppresses the browser's native credential popup on 401 while keeping the server
112+
fully functional — it still reads and validates `Authorization: Basic` headers
113+
sent by the desktop app.
120114

121-
### 6 · Serve local web UI in dev mode, suppress auth dialog — `dd426faec`
115+
**c) Auth-required error page**
116+
On 401 the SPA shows a localized "Authentication required" page with a manual
117+
"Go to home" button, breaking the infinite redirect loop that previously occurred
118+
when the app auto-navigated from `/` to the last opened project.
122119

123-
**Files:** `packages/core/src/flag/flag.ts`, `packages/desktop/src/main/server.ts`, `packages/opencode/src/server/routes/instance/httpapi/middleware/authorization.ts`, `packages/opencode/src/server/shared/ui.ts`
120+
**d) /global/health probe**
121+
Allows unauthenticated health probes so the SPA can discover the server before
122+
the user enters credentials. If credentials are supplied but wrong, returns 401.
124123

125-
**What it does:**
124+
**Rebase risk:** Low for `authorization.ts` (small, self-contained). Medium for
125+
`error.tsx` if upstream changes the error page structure.
126126

127-
**a) Bearer auth scheme** (`authorization.ts`)
128-
Changed `WWW-Authenticate` response header from `Basic` to `Bearer`. Chrome and
129-
Firefox show a native credentials popup for `Basic` on every 401, including XHR
130-
responses from the SPA. `Bearer` suppresses this popup while keeping the server
131-
fully functional — it still reads and validates `Authorization: Basic` headers
132-
sent by the desktop app.
127+
---
133128

134-
**b) Local build serving in dev mode** (`flag.ts`, `server.ts`, `ui.ts`)
135-
Added two env flags:
136-
- `OPENCODE_DEV_UI_DIR` — if set, the server serves static files from this
137-
directory (with SPA index.html fallback) instead of proxying to
138-
`https://app.opencode.ai`.
139-
- `OPENCODE_DEV_UI_URL` — overrides the upstream proxy base URL.
129+
### 5 · Cap diff size to prevent SQLite/V8 crash on large files — `c37061538`
140130

141-
In desktop dev mode (`!app.isPackaged`), `preferAppEnv()` automatically sets
142-
`OPENCODE_DEV_UI_DIR` to `packages/app/dist`. This means remote browsers
143-
connecting to the Electron-local server see the locally built UI (with fork
144-
customizations like the server icon) instead of the production CDN version.
131+
**Files:** `packages/opencode/src/tool/apply_patch.ts`, `packages/opencode/src/tool/edit.ts`
145132

146-
**Prerequisite:** `packages/app` must be built before starting Electron in dev
147-
mode:
148-
```sh
149-
cd packages/app && bun run build
150-
```
133+
Truncates patch/diff strings before storing them to prevent SQLite blob limits
134+
and V8 string size limits from crashing the process on very large file edits.
151135

152-
**Rebase risk:** Low for `authorization.ts` (one constant). Medium for `ui.ts`
153-
if upstream restructures `serveUIEffect` or `serveEmbeddedUIEffect`.
136+
**Rebase risk:** Low — isolated tool change.
154137

155138
---
156139

@@ -163,11 +146,12 @@ After every rebase, verify these before merging/releasing:
163146
| 1 | Remote browser opens `http://<host>:4096/` (no credentials) | 200, loads UI shell (no browser auth popup) |
164147
| 2 | Remote browser fetches `/favicon-96x96-v3.png` | 200 (no auth required) |
165148
| 3 | SPA fetches `/global/config` without credentials | 401 with `WWW-Authenticate: Bearer …` (not `Basic`) |
166-
| 4 | Desktop app bottom-left shows server icon with current server URL | Visible, clickable |
167-
| 5 | Clicking server icon opens server config dialog | Dialog appears, shows local-server config panel |
168-
| 6 | Setting local server credentials and restarting → credentials persist | Config survives restart |
169-
| 7 | Opening a project in one browser tab → other tabs update | `project.opened.updated` event triggers sync |
170-
| 8 | Dev mode: remote browser sees fork UI (server icon in bottom left) | Not the upstream `app.opencode.ai` version |
149+
| 4 | Navigate to `http://<host>:4096/<project>/session/<id>` without credentials | Loads SPA shell, shows auth-required page, no infinite redirect |
150+
| 5 | Desktop app bottom-left shows server icon with current server URL | Visible, clickable |
151+
| 6 | Clicking server icon opens server config dialog | Dialog appears, shows local-server config panel in desktop mode |
152+
| 7 | Setting local server credentials and restarting → credentials persist | Config survives restart |
153+
| 8 | Opening a project in one browser tab → other tabs update | `project.opened.updated` event triggers sync |
154+
| 9 | Dev mode: remote browser sees fork UI (server icon in bottom left) | Not the upstream `app.opencode.ai` version |
171155

172156
Quick automated check (run against a live local server on port 4096):
173157

0 commit comments

Comments
 (0)