# 开发指南

LibreFang 开发环境设置和贡献指南。

---

## 开发环境

### 前置要求

- **Rust** 1.85+
- **Node.js** 22+（用于 Dashboard 和桌面应用）
- **pnpm** 10+（用于 Dashboard、文档站点和官网）
- **just**（命令运行器，[安装说明](https://github.com/casey/just#installation)）

安装 just：

```bash
# macOS
brew install just

# Windows
winget install Casey.Just        # 或：scoop install just

# Linux (Debian/Ubuntu)
sudo apt install just            # Ubuntu 24.04+，否则用 cargo 安装

# 任何已安装 Rust 的平台
cargo install just
```

### 克隆仓库

```bash
git clone https://github.com/librefang/librefang.git
cd librefang
```

### 使用 just 构建（推荐）

项目使用 [just](https://github.com/casey/just) 作为命令运行器。
运行 `just` 可查看所有可用命令。

```bash
# 构建 + 安装 CLI 和 Dashboard（首次设置推荐）
just install

# 仅构建工作空间库
just build

# 运行所有测试
just test

# 代码检查（clippy 必须零警告）
just lint

# 本地 CI 模拟：构建 + 测试 + clippy + web lint
just ci
```

`just install` 会自动先构建 React Dashboard，再编译 CLI 二进制，
确保 Dashboard 在 `http://127.0.0.1:4545/` 上完整可用。

<Note>
justfile 使用 `[unix]` 和 `[windows]` recipe 属性实现跨平台支持。所有命令在 macOS、Linux 和 Windows 上均可使用。在 Windows 上，`just install` 会自动使用 PowerShell 命令。
</Note>

### 不使用 just 构建

```bash
# 构建整个工作空间（Dashboard 资源已预提交，无需额外步骤）
cargo build --workspace

# 仅构建 CLI
cargo build -p librefang-cli

# 构建桌面应用
cargo build -p librefang-desktop
```

### 首次运行

```bash
# 初始化配置（~/.librefang/config.toml）
librefang init

# 启动守护进程
librefang start

# 打开 Dashboard: http://127.0.0.1:4545/
```

### Dashboard 开发

React Dashboard 构建产物输出到 `crates/librefang-api/static/react/`（已 gitignore）。
CI 会自动构建并上传；本地开发时，需要在编译 Rust 二进制之前手动构建：

```bash
# 重新构建 Dashboard 资源
just dashboard-build

# 或手动构建：
cd crates/librefang-api/dashboard
pnpm install --frozen-lockfile
pnpm run build
cd ../../..
cargo build -p librefang-cli
```

使用热更新进行开发：

```bash
# 方式一：同时启动守护进程 + Dashboard 开发服务器
just dev

# 方式二：手动启动
librefang start                          # 终端 1：后端守护进程
cd crates/librefang-api/dashboard        # 终端 2：Vite 开发服务器
pnpm install && pnpm dev
# 打开 http://localhost:5173/dashboard/  # 自动代理 /api 到 127.0.0.1:4545
```

### 测试

```bash
# 运行所有测试
cargo test --workspace

# 运行特定 crate
cargo test -p librefang-kernel

# 运行文档测试
cargo test --doc
```

### 代码检查

```bash
# 必须零警告
cargo clippy --workspace --all-targets -- -D warnings

# 格式化检查
cargo fmt --all -- --check
```

---

## 项目结构

```
librefang/
├── Cargo.lock
├── Cargo.toml
├── crates/
│   ├── librefang-cli/          # CLI 工具
│   ├── librefang-api/         # REST API 服务器
│   ├── librefang-kernel/      # 核心内核
│   ├── librefang-runtime/     # Agent 运行时
│   ├── librefang-memory/      # 内存子系统
│   ├── librefang-types/       # 共享类型
│   ├── librefang-channels/    # 通道适配器
│   ├── librefang-skills/      # 技能系统
│   ├── librefang-hands/       # Hands 系统
│   ├── librefang-wire/        # P2P 协议
│   ├── librefang-desktop/     # 桌面应用
│   ├── librefang-migrate/     # 迁移工具
│   └── librefang-extensions/   # 扩展
├── xtask/                      # 构建脚本
├── docs/                       # 项目文档
└── scripts/                    # 辅助脚本
```

---

## 添加新通道

### 1. 创建通道模块

```rust
// crates/librefang-channels/src/my_channel.rs

use async_trait::async_trait;
use std::pin::Pin;
use futures::Stream;
use crate::types::{ChannelAdapter, ChannelContent, ChannelMessage, ChannelStatus, ChannelType, ChannelUser};

pub struct MyChannel {
    // 特定通道的字段（如 API 客户端、配置等）
}

#[async_trait]
impl ChannelAdapter for MyChannel {
    fn name(&self) -> &str {
        "my_channel"
    }

    fn channel_type(&self) -> ChannelType {
        ChannelType::Custom("my_channel".to_string())
    }

    async fn start(
        &self,
    ) -> Result<
        Pin<Box<dyn Stream<Item = ChannelMessage> + Send>>,
        Box<dyn std::error::Error + Send + Sync>,
    > {
        // 返回传入消息的流
        todo!()
    }

    async fn send(
        &self,
        _user: &ChannelUser,
        _content: ChannelContent,
    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
        // 向用户发送响应
        Ok(())
    }

    async fn stop(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
        Ok(())
    }
}
```

### 2. 注册通道

通道适配器通过 `librefang-api/src/server.rs` 中的 `BridgeManager` 注册，
调用 `bridge_manager.add_adapter(Arc::new(MyChannel::new(config)))` 即可。
每个适配器都通过 `crates/librefang-channels/Cargo.toml` 中的 Cargo feature flag
（`channel-my-channel`）进行控制。

```rust
// crates/librefang-channels/src/lib.rs — 添加 feature-gated 模块
#[cfg(feature = "channel-my-channel")]
pub mod my_channel;
```

### 3. 添加配置

```rust
// crates/librefang-types/src/config.rs

#[derive(Debug, Clone, Deserialize)]
pub struct MyChannelConfig {
    pub api_key_env: String,
    pub allowed_users: Option<Vec<String>>,
}
```

---

## 添加新技能

### 1. 创建技能结构

```toml
# skills/my-skill/skill.toml
name = "my-skill"
version = "1.0.0"
description = "My custom skill"

[runtime]
type = "python"
entrypoint = "main.py"

[tools]
provided = ["my_tool"]

[requirements]
packages = ["requests"]
```

### 2. 实现代码

```python
# skills/my-skill/main.py

def my_tool(param: str) -> str:
    """My custom tool description"""
    # 实现逻辑
    return f"Result: {param}"

# 注册工具
TOOLS = [my_tool]
```

### 3. 编译技能

```bash
# 技能会自动编译到二进制中
cargo build --workspace
```

---

## 添加新工具

### 1. 定义工具

```rust
// crates/librefang-runtime/src/tools/mod.rs

use crate::tool::{Tool, ToolResult};

pub struct MyTool;

impl Tool for MyTool {
    fn name(&self) -> &str {
        "my_tool"
    }

    fn description(&self) -> &str {
        "My custom tool description"
    }

    async fn execute(&self, params: Value) -> ToolResult {
        // 实现工具逻辑
        Ok(Value::String("result".to_string()))
    }
}
```

### 2. 注册工具

```rust
// crates/librefang-runtime/src/lib.rs

pub fn register_tools(registry: &mut ToolRegistry) {
    registry.register(MyTool::new());
}
```

---

## 添加新 LLM 提供商

### 1. 实现驱动

```rust
// crates/librefang-runtime/src/llm/my_provider.rs

use crate::llm::{LlmDriver, LlmResponse, LlmError};

pub struct MyProvider {
    api_key: String,
    base_url: String,
}

#[async_trait]
impl LlmDriver for MyProvider {
    async fn complete(&self, prompt: &str) -> Result<LlmResponse, LlmError> {
        // 调用 API
        Ok(LlmResponse {
            text: "response".to_string(),
            tokens: 100,
        })
    }
}
```

### 2. 添加到模型目录

```rust
// crates/librefang-types/src/models.rs

pub fn get_provider(name: &str) -> Option<Box<dyn LlmDriver>> {
    match name {
        "my_provider" => Some(Box::new(MyProvider::new())),
        _ => None,
    }
}
```

---

## 代码风格

### Rust 规范

- 使用 `cargo fmt` 格式化
- 使用 `cargo clippy` 检查
- 遵循 Rust 命名约定
- 添加文档注释 (`///`)

### 提交规范

```bash
# 格式: <type>(<scope>): <description>

git commit -m "feat(kernel): add new scheduling algorithm"
git commit -m "fix(channels): resolve Slack rate limit"
git commit -m "docs(api): update endpoint documentation"
git commit -m "test(runtime): add tool execution tests"
```

### 类型

| 类型 | 说明 |
|------|------|
| feat | 新功能 |
| fix | Bug 修复 |
| docs | 文档 |
| style | 格式 |
| refactor | 重构 |
| test | 测试 |
| chore | 维护 |

---

## 测试

### 单元测试

```rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_my_function() {
        assert_eq!(my_function(2), 4);
    }
}
```

### 集成测试

```rust
#[tokio::test]
async fn test_agent_spawn() {
    let kernel = Kernel::new().await;
    let agent = kernel.spawn("test-agent").await;
    assert!(agent.is_running());
}
```

### 基准测试

```rust
#[tokio::bench]
async fn benchmark_llm_call(b: &mut Bencher) {
    b.iter(|| {
        runtime.block_on(llm.complete("test prompt"))
    })
}
```

---

## 调试

### 日志

```rust
use tracing::{info, warn, error};

info!("Starting agent {}", agent_id);
warn!("Rate limit exceeded for channel {}", channel_id);
error!("Failed to connect to provider: {}", error);
```

### 调试模式

```bash
# 启用详细日志
RUST_LOG=debug cargo run

# 只看特定模块
RUST_LOG=librefang_kernel=trace cargo run
```

### Dashboard 调试

Dashboard 是一个 React SPA，通过 `include_dir!` 在编译时嵌入到二进制中。
资源文件通过 `/dashboard/*` 路径提供服务。

**空白页 / 资源 404：**

```bash
# 1. 确认守护进程正在运行且健康
curl -s http://127.0.0.1:4545/api/health

# 2. 验证 HTML 是否正常返回（应返回 <!doctype html>...）
curl -s http://127.0.0.1:4545/ | head -5

# 3. 测试具体资源路径（从 HTML 中的 <script> 标签获取路径）
curl -sI http://127.0.0.1:4545/dashboard/assets/index-DVRukrPy.js
# 200 = 正常, 404 = 资源未嵌入

# 4. 如果资源 404，本地重新构建 dashboard 并重新编译
just dashboard-build
cargo build -p librefang-cli --release
```

**Dashboard 能显示但数据为空：**

```bash
# 直接测试 API 端点
curl -s http://127.0.0.1:4545/api/status | python3 -m json.tool
curl -s http://127.0.0.1:4545/api/agents | python3 -m json.tool

# 检查浏览器控制台是否有 CORS 或认证错误（F12 → Console）
# 默认安装无需认证 — 如果设置了 api_key，需要传入：
curl -s -H "Authorization: Bearer YOUR_KEY" http://127.0.0.1:4545/api/status
```

**Dashboard 开发服务器无法连接 API：**

```bash
# Vite 会将 /api 代理到 http://127.0.0.1:4545 — 确保守护进程正在运行
librefang status
# 如果未运行：
librefang start
```

### 性能分析

```bash
# CPU profiling
cargo flamegraph --bin librefang-cli -- start
```

---

## 发布

### 版本规则

LibreFang 使用 [Calendar Versioning](https://calver.org/) — `YYYY.M.DDHH`。

| 类型 | 格式 | 示例 | 说明 |
|------|------|------|------|
| 稳定版 | `YYYY.M.DDHH` | `2026.3.2314` | 发布日期 + 小时 |
| Beta | `YYYY.M.DDHH-betaN` | `2026.3.2314-beta1` | 测试预发布 |
| RC | `YYYY.M.DDHH-rcN` | `2026.3.2314-rc1` | 发布候选 |
| LTS | `YYYY.M.PATCH-lts` | `2026.3.0-lts` | 长期支持版本 |

### 发布流程

所有发布通过 `cargo xtask release` 完成：

```bash
cargo xtask release
#   1) stable  -> 2026.3.2314
#   2) beta    -> 2026.3.2314-beta1
#   3) rc      -> 2026.3.2314-rc1
#   4) lts     -> 2026.3.0-lts
```

该命令自动完成：
- 从 git 历史生成 CHANGELOG
- 同步版本号到 Cargo.toml、package.json、setup.py
- 构建 React 面板
- 创建 git tag 并推送
- 创建版本 bump 的 PR

使用 `--dry-run` 预览而不做任何修改：
```bash
cargo xtask release --dry-run --version "2026.3.0-lts"
```

### LTS 长期支持版本

LTS 版本只接受安全修复和 bug 修复，不加新功能。

**版本格式：**
```
v2026.3.0-lts     ← 初始 LTS
v2026.3.1-lts     ← 补丁 1（bug 修复）
v2026.3.2-lts     ← 补丁 2（安全修复）
```

**创建 LTS 版本：**
```bash
# 在 main 分支上，选择选项 4
cargo xtask release
```

CI 自动完成：
- 从 tag 创建 `release/2026.3` 分支
- 设置分支保护（需要 PR 审查）
- Docker 镜像打 `:lts` 标签
- GitHub Release 标记为 LTS

**发布 LTS 补丁：**
```bash
# 切换到 LTS 分支
git checkout release/2026.3

# 从 main 挑选修复
git cherry-pick <commit-sha>

# 发布补丁（自动递增补丁号）
cargo xtask release --lts-patch
```

**规则：**
- 只 cherry-pick 修复，不引入新功能
- 每个补丁必须通过 `release/` 分支上的 PR 审查
- LTS 分支维护到下一个 LTS 版本发布为止
- Docker `:lts` 标签始终指向最新的 LTS 版本

---

## 贡献

### 贡献流程

1. Fork 仓库
2. 创建特性分支 (`git checkout -b feature/my-feature`)
3. 提交更改 (`git commit -m "feat: add my feature"`)
4. 推送分支 (`git push origin feature/my-feature`)
5. 创建 Pull Request

### 代码审查

- 确保 `cargo clippy` 无警告
- 确保 `cargo test` 通过
- 添加测试覆盖新代码
- 更新文档

### 行为准则

- 尊重他人
- 欢迎新手
- 专业沟通
- 接受建设性批评
