docs(desktop): 更新 AGENTS.md 文档与开发计划以反映最新实现

This commit is contained in:
2026-02-07 18:49:50 +08:00
parent b7a6a793a3
commit 55d45e6a49
2 changed files with 881 additions and 77 deletions

View File

@@ -1,124 +1,130 @@
# AGENTS.md - Desktop App Guidelines
Electrobun desktop shell — loads the server app in a native window.
Thin Electrobun shell hosting the fullstack server app.
## Tech Stack
> **⚠️ This project uses Bun — NOT Node.js / npm. All commands use `bun`. Never use `npm`, `npx`, or `node`.**
- **Type**: Electrobun desktop application
- **Design**: Server-driven desktop (thin native shell hosting web app)
- **Runtime**: Bun (Main process) + CEF (Chromium Embedded Framework)
- **Framework**: Electrobun
- **Build**: Electrobun CLI + Turborepo
## Architecture
- **Type**: Electrobun desktop application
- **Design**: Bun main process + CEF renderer (Chromium Embedded Framework)
- **Dev mode**: Connects to `localhost:3000` (requires server dev running)
- **Prod mode**: Embeds server bundle and starts local HTTP server
- **Config**: `electrobun.config.ts` — app metadata, build entrypoint, platform options
- **Server-driven design**: The desktop app is a "thin" native shell. It does not contain UI or business logic; it merely hosts the `apps/server` TanStack Start application in a native window.
- **Dev mode**: Connects to an external Vite dev server at `localhost:3000`. Requires `apps/server` to be running separately.
- **Prod mode**: Spawns an embedded TanStack Start server (Nitro) as a child process and loads the dynamically assigned local URL.
- **Config**: `electrobun.config.ts` manages app metadata (identifier, name), build entries, and asset bundling.
## Commands
```bash
# Development (from apps/desktop/)
bun dev # Start Electrobun dev mode
# Development
bun dev # Start Electrobun dev mode (requires server dev running)
# Build
bun build # Build canary release (current platform)
bun build:all # Build canary release (all platforms)
bun build:stable # Build stable release (current platform)
bun build:stable:all # Build stable release (all platforms)
bun build # Build stable release (all platforms)
# Code Quality
bun fix # Biome auto-fix (lint + format)
bun fix # Biome auto-fix
bun typecheck # TypeScript check
```
## Directory Structure
```
apps/desktop/
.
├── src/
│ └── bun/
│ └── index.ts # Main process entry (BrowserWindow + server wait)
├── electrobun.config.ts # App name, identifier, version, build config
├── package.json
├── tsconfig.json # Extends @furtherverse/tsconfig/bun.json
└── turbo.json # Build output config
│ └── index.ts # Main process entry (Window management + server lifecycle)
├── electrobun.config.ts # App metadata and build/copy configuration
├── package.json # Scripts and dependencies
├── turbo.json # Build pipeline dependencies (depends on server build)
└── AGENTS.md # Desktop guidelines (this file)
```
## Development Workflow
1. **Start server dev first**: `bun dev` from `apps/server/`
2. **Start Electrobun**: `bun dev` from `apps/desktop/`
3. Desktop app polls `localhost:3000` until server responds, then opens window
1. **Start server**: In `apps/server`, run `bun dev`.
2. **Start desktop**: In `apps/desktop`, run `bun dev`.
3. **Connection**: The desktop app polls `localhost:3000` until responsive, then opens the native window.
## Production Architecture
### Build Pipeline
The desktop build is orchestrated by Turbo. It depends on the server's production build:
- `turbo.json`: `@furtherverse/desktop#build` depends on `@furtherverse/server#build`.
- `electrobun.config.ts`: Copies `../server/.output` to `server-output` folder within the app bundle.
### Server Lifecycle
In production, the main process manages the embedded server:
- **Spawn**: Spawns server from `server-output/server/index.mjs` using `Bun.spawn`.
- **Port Allocation**: Server is started with `PORT=0` and `HOST=127.0.0.1`.
- **Port Detection**: The main process parses the server's `stdout` using a regex to find the dynamically assigned port.
- **Lifecycle**: The server process is tied to the app; it is killed on `SIGTERM`, `SIGINT`, or app exit. If the server process crashes, the app exits with an error.
## Environment Detection
The application determines its environment via the `ELECTROBUN_BUILD_ENV` variable, automatically set by the Electrobun CLI:
```typescript
const isDev = () => {
const env = process.env.ELECTROBUN_BUILD_ENV
return !env || env === 'dev'
}
```
- **dev**: Development mode (connects to external host).
- **canary / stable**: Production mode (starts embedded server).
## Environment Variables
- `ELECTROBUN_BUILD_ENV`: Auto-set by CLI. Determines whether to use local dev server or embedded server.
- `DATABASE_URL`: Required by the server process. Must be passed through from the parent environment to the spawned child process.
## Electrobun Patterns
### Config (`electrobun.config.ts`)
### BrowserWindow Configuration
The main window uses the CEF renderer for consistency across platforms.
```typescript
import type { ElectrobunConfig } from 'electrobun'
export default {
app: {
name: 'MyApp',
identifier: 'com.example.myapp',
version: '0.1.0',
},
build: {
bun: { entrypoint: 'src/bun/index.ts' },
linux: { bundleCEF: true },
},
} satisfies ElectrobunConfig
```
### BrowserWindow
```typescript
import { BrowserWindow } from 'electrobun/bun'
new BrowserWindow({
title: 'My App',
url: 'http://localhost:3000',
frame: { x: 100, y: 100, width: 1200, height: 800 },
title: 'Furtherverse',
url: serverUrl,
frame: {
x: 100,
y: 100,
width: 1200,
height: 800,
},
renderer: 'cef',
})
```
### Server Readiness Check
### Path Aliases
The main process uses `electrobun/bun` for native APIs and `PATHS` for locating bundled assets.
```typescript
// Poll server before opening window — don't block indefinitely
async function waitForServer(url: string, timeoutMs = 30000): Promise<boolean> {
const start = Date.now()
while (Date.now() - start < timeoutMs) {
try {
const response = await fetch(url, { method: 'HEAD' })
if (response.ok) return true
} catch {
await Bun.sleep(100)
}
}
return false
}
```
import { BrowserWindow, PATHS } from 'electrobun/bun'
### Application Events
```typescript
import Electrobun from 'electrobun/bun'
Electrobun.events.on('will-quit', () => {
console.log('App quitting...')
})
// Locate the embedded server bundle
const serverEntryPath = join(PATHS.VIEWS_FOLDER, '..', 'server-output', 'server', 'index.mjs')
```
## Critical Rules
**DO:**
- Run server dev before desktop dev
- Use `catalog:` for dependency versions
- Wait for server readiness before opening BrowserWindow
- Handle server timeout gracefully (exit with helpful error message)
- Use arrow functions for all components and utility functions.
- Ensure `apps/server` is built before building `apps/desktop` (handled by Turbo).
- Parse the server's stdout for the port instead of hardcoding ports in production.
- Handle server process termination to avoid orphan processes.
- Use `catalog:` for all dependency versions in `package.json`.
**DON'T:**
- Use `npm`, `npx`, `node`, `yarn`, `pnpm` — always use `bun` / `bunx`
- Hardcode dependency versions (use catalog)
- Block main thread with synchronous waits
- Use `unwrap()`-style patterns without error handling
- Use `npm`, `npx`, `node`, `yarn`, or `pnpm`. Always use `bun`.
- Hardcode `localhost:3000` for production builds.
- Include UI components or business logic in the desktop app (keep it thin).
- Use `as any` or `@ts-ignore`.