docs: 更新 AGENTS.md 文档结构和内容
- 新增根目录 AGENTS.md 作为 monorepo 总览 - 移动 desktop AGENTS.md 从 src-tauri/ 到 apps/desktop/ - 修正 server AGENTS.md 目录结构 (src/server/api/ 而非 src/orpc/) - 明确 desktop 为纯 Tauri 壳子,无前端代码,通过 sidecar 加载 server
This commit is contained in:
171
apps/desktop/AGENTS.md
Normal file
171
apps/desktop/AGENTS.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# AGENTS.md - Desktop App Guidelines
|
||||
|
||||
Tauri v2 desktop shell - a lightweight wrapper that loads the server app via sidecar.
|
||||
|
||||
## Architecture
|
||||
|
||||
- **Type**: Tauri v2 desktop application (shell only)
|
||||
- **Design**: Tauri provides native desktop APIs; all web logic handled by sidecar
|
||||
- **Sidecar**: The compiled server binary runs as a child process
|
||||
- **Dev mode**: Connects to `localhost:3000` (requires server dev running)
|
||||
- **Prod mode**: Automatically starts sidecar binary
|
||||
|
||||
**This app has NO frontend src** - it loads the server app entirely.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
# Development (from apps/desktop/)
|
||||
bun dev # Copy sidecar + start Tauri dev
|
||||
|
||||
# Build
|
||||
bun build # Copy sidecar + build Tauri installer
|
||||
|
||||
# Rust Commands (from src-tauri/)
|
||||
cargo check # Compile check
|
||||
cargo clippy # Linter
|
||||
cargo fmt # Formatter
|
||||
cargo test # Run tests
|
||||
cargo test test_name -- --nocapture # Single test with output
|
||||
```
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
apps/desktop/
|
||||
├── src-tauri/ # Rust Tauri code
|
||||
│ ├── src/
|
||||
│ │ ├── main.rs # Entry point (calls lib::run)
|
||||
│ │ ├── lib.rs # Core app logic (plugins, commands, state)
|
||||
│ │ ├── commands/
|
||||
│ │ │ └── mod.rs # Native desktop commands
|
||||
│ │ └── sidecar.rs # Sidecar process management
|
||||
│ ├── binaries/ # Sidecar binaries (copied from server build)
|
||||
│ ├── capabilities/ # Tauri v2 permission config
|
||||
│ ├── icons/ # App icons
|
||||
│ ├── Cargo.toml # Rust dependencies
|
||||
│ └── tauri.conf.json # Tauri configuration
|
||||
├── copy.ts # Script to copy server binary to binaries/
|
||||
├── package.json
|
||||
└── tsconfig.json
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
1. **Start server dev first**: `cd ../server && bun dev`
|
||||
2. **Start Tauri**: `bun dev` (from apps/desktop/)
|
||||
3. Tauri connects to localhost:3000 with HMR support
|
||||
|
||||
## Rust Code Style
|
||||
|
||||
### Formatting
|
||||
- **Indent**: 4 spaces
|
||||
- **Line width**: 100 chars
|
||||
- Run `cargo fmt` before commit
|
||||
|
||||
### Naming
|
||||
| Type | Convention | Example |
|
||||
|------|------------|---------|
|
||||
| Functions/variables | snake_case | `find_available_port` |
|
||||
| Types/structs/enums | PascalCase | `SidecarProcess` |
|
||||
| Constants | SCREAMING_SNAKE | `DEFAULT_PORT` |
|
||||
|
||||
### Imports
|
||||
```rust
|
||||
// Order: std → external crates → internal modules (separated by blank lines)
|
||||
use std::sync::Mutex;
|
||||
|
||||
use tauri::Manager;
|
||||
use tauri_plugin_shell::ShellExt;
|
||||
|
||||
use crate::sidecar::SidecarProcess;
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
```rust
|
||||
// Use expect() with Chinese error messages
|
||||
let sidecar = app_handle
|
||||
.shell()
|
||||
.sidecar("server")
|
||||
.expect("无法找到 server sidecar");
|
||||
|
||||
// Log with emoji for clear feedback
|
||||
println!("✓ Sidecar 启动成功!");
|
||||
eprintln!("✗ Sidecar 启动失败");
|
||||
```
|
||||
|
||||
### Async Code
|
||||
```rust
|
||||
// Use Tauri's async runtime for spawning
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let port = find_available_port(3000).await;
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
## Tauri Patterns
|
||||
|
||||
### Command Definition
|
||||
```rust
|
||||
#[tauri::command]
|
||||
fn greet(name: &str) -> String {
|
||||
format!("Hello, {}!", name)
|
||||
}
|
||||
|
||||
// Register in Builder
|
||||
.invoke_handler(tauri::generate_handler![commands::greet])
|
||||
```
|
||||
|
||||
### State Management
|
||||
```rust
|
||||
struct SidecarProcess(Mutex<Option<CommandChild>>);
|
||||
|
||||
// Register state
|
||||
app.manage(SidecarProcess(Mutex::new(None)));
|
||||
|
||||
// Access state
|
||||
if let Some(state) = app_handle.try_state::<SidecarProcess>() {
|
||||
*state.0.lock().unwrap() = Some(child);
|
||||
}
|
||||
```
|
||||
|
||||
### Sidecar Lifecycle
|
||||
```rust
|
||||
// Start sidecar with environment
|
||||
let sidecar = app_handle
|
||||
.shell()
|
||||
.sidecar("server")
|
||||
.expect("无法找到 server sidecar")
|
||||
.env("PORT", port.to_string());
|
||||
|
||||
// Cleanup on exit
|
||||
match event {
|
||||
tauri::RunEvent::ExitRequested { .. } | tauri::RunEvent::Exit => {
|
||||
if let Some(child) = process.take() {
|
||||
let _ = child.kill();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
```
|
||||
|
||||
## Critical Rules
|
||||
|
||||
**DO:**
|
||||
- Run `cargo fmt` and `cargo clippy` before commit
|
||||
- Use `expect("中文消息")` instead of `unwrap()`
|
||||
- Always cleanup sidecar on app exit
|
||||
- Declare sidecar in `tauri.conf.json` → `bundle.externalBin`
|
||||
|
||||
**DON'T:**
|
||||
- Edit `gen/schemas/` (auto-generated)
|
||||
- Use `unwrap()` in production code without context
|
||||
- Block the async runtime (use `spawn_blocking`)
|
||||
|
||||
## Pre-commit Checklist
|
||||
|
||||
- [ ] `cargo fmt` - formatting
|
||||
- [ ] `cargo clippy` - linting
|
||||
- [ ] `cargo check` - compiles
|
||||
- [ ] `cargo test` - tests pass
|
||||
- [ ] Tauri app starts and exits cleanly
|
||||
Reference in New Issue
Block a user