首页
/ OpenHuman 日常开发实战:从 dev-agent 看 React 组件、Tauri 命令与插件接入规范

OpenHuman 日常开发实战:从 dev-agent 看 React 组件、Tauri 命令与插件接入规范

2026-09-05 20:31:56作者:郦嵘贵Just

OpenHuman 仓库在 .claude/agents/dev-agent.md 中定义了一个面向日常开发的子 Agent(dev-agent),它把"创建 React 组件、编写 Tauri 命令、添加插件、配置开发环境"这四类高频任务固化成了可复制的模板与命令。读懂这份文档,再对照仓库中 app/src-tauri/src/lib.rs 的真实命令实现与 app/src/utils/tauriCommands/core.ts 的前端调用约定,你就能完整掌握在这个 Tauri + React + Rust 代码库里新增功能的标准路径:声明命令、注册 handler、前端 invoke、跑测试与 lint。

dev-agent 是什么:一份固化的开发 SOP

dev-agent 是 Claude Code 的 subagent 定义文件,采用 YAML frontmatter + Markdown 正文的结构:

---
name: dev-agent
description: Assists with day-to-day development tasks, code generation, and feature implementation
model: model-sonnet
color: teal
---

frontmatter 中的 name 用于在 .claude/agents/ 目录下标识该 Agent,description 描述其职责边界,model 指定使用的模型。它的定位是"日常开发任务、代码生成、功能实现",核心能力被明确限定为四项:

  • 生成 React 组件(Generate React components)
  • 创建 Tauri 命令(Create Tauri commands)
  • 安装配置插件(Set up plugins)
  • 配置开发环境(Configure development environment)

从源码结构看,这个目录还并列存放了 test-agentpr-reviewermobile-agent 等按职责拆分的子 Agent,dev-agent 是其中专注"写功能"的一个。以下各节按文档的四大能力展开,并用仓库真实代码印证每一步。

创建新的 React 组件

文档给出的模板

dev-agent 文档中"Create New Component"一节给出两步操作:

# Create component file
touch src/components/MyComponent.tsx

然后套入如下函数式组件模板:

import { FC } from 'react';

import './MyComponent.css';

interface MyComponentProps {
  title: string;
}

export const MyComponent: FC<MyComponentProps> = ({ title }) => {
  return (
    <div className="my-component">
      <h2>{title}</h2>
    </div>
  );
};

模板体现了文档"Code Style / TypeScript"一节的四条规范:函数式组件 + hooks、所有 props 和 state 必须有类型(interface MyComponentProps)、通过 invoke 调用 Tauri 命令、错误处理用 try/catch。

在本仓库中的落点

需要注意仓库目录布局:前端代码位于 app/ 工作区下,因此文档中的相对路径在本仓库对应 app/src/components/(该目录下有数百个 .tsx 组件)。命令实际在 app/ 目录执行时写作:

touch app/src/components/MyComponent.tsx

组件创建完成后,验证手段在 app/package.json 中已经就绪:pnpm lint(ESLint)、pnpm compiletsc --noEmit 类型检查)、pnpm test(Vitest)。仓库还配有 knip 做未使用代码检测,新增组件若未被引用会被这类工具捕获。

创建 Tauri 命令:声明、注册、调用三步走

这是 dev-agent 文档中技术含量最高的部分,对应仓库中"前端 ⇄ Rust 内核"通信的核心机制。文档给出的三步流程如下。

第一步:在 lib.rs 中声明命令

文档要求在 src-tauri/src/lib.rs 中添加:

#[tauri::command]
fn my_command(arg: String) -> Result<String, String> {
    Ok(format!("Received: {}", arg))
}

在真实仓库中,该文件是 app/src-tauri/src/lib.rs(约 3700 行,是整个桌面 shell 的命令层)。一个真实的同步 + 异步混合命令例子是 core_rpc_url

/// Tauri command: where the renderer should send core JSON-RPC.
#[tauri::command]
async fn core_rpc_url(
    desktop: tauri::State<'_, core_process::CoreProcessHandle>,
) -> Result<String, String> {
    Ok(active_rpc_endpoint(desktop.inner()).await.0)
}

(见 app/src-tauri/src/lib.rs#L113-L124

对照文档"Code Style / Rust"一节的四条规则,这段真实代码恰好全部命中:

  • 命令用 #[tauri::command] 宏标注;
  • 可失败操作返回 Result<T, E>
  • 共享状态通过 State<CoreProcessHandle> 注入(Tauri 的依赖注入点,由 builder 在启动时 manage);
  • 涉及 I/O 的命令(这里要查询 active gateway)声明为 async

第二步:在 builder 中注册 handler

文档要求把命令加入 builder:

.invoke_handler(tauri::generate_handler![my_command])

app/src-tauri/src/lib.rs#L3369 可以看到真实的注册点,tauri::generate_handler![...] 宏内是一个显式清单:

.invoke_handler(tauri::generate_handler![
    core_rpc_url,
    core_rpc_token,
    core_rpc_endpoint,
    // ...
    check_core_update,
    apply_core_update,
    check_app_update,
    apply_app_update,
    restart_core_process,
    recover_port_conflict,
    force_quit_port_owner,
    start_core_process,
    // ...
])

值得注意的工程细节:清单里部分命令带条件编译,例如 gateway 相关命令写作 #[cfg(feature = "gateways")] gateway::commands::gateway_list。注释解释了设计意图——feature 关闭时命令"absent, not stubbed"(干脆不注册,而不是注册一个运行时才报错的桩函数),让前端可以做特性探测。新增命令时若依赖某个 cargo feature,应照此模式处理。

第三步:前端 invoke

文档给出的前端调用:

import { invoke } from '@tauri-apps/api/core';

const result = await invoke<string>('my_command', { arg: 'test' });

仓库中前端对 invoke 做了集中封装,位于 app/src/utils/tauriCommands/core.tsrestartCoreProcess 展示了比文档模板更完整的防御式写法:

export async function restartCoreProcess(): Promise<void> {
  if (!isTauri()) {
    console.debug('[core] restartCoreProcess: skipped — not running in Tauri');
    return;
  }
  console.debug('[core] restartCoreProcess: invoking restart_core_process');
  await invoke<void>('restart_core_process');
  clearCoreRpcTokenCache();
  console.debug('[core] restartCoreProcess: done');
}

两个约定超出文档模板但属于本仓库的硬性实践:

  1. isTauri() 前置守卫——同一套 React 代码也运行在纯 Web 模式(pnpm dev 的 vite 开发模式)下,此时 @tauri-apps/apiinvoke 不可用,所有命令封装都要在入口处判断并优雅降级;
  2. 类型参数显式化——invoke<void> / invoke<string> 的泛型保证返回值在编译期就是前端预期的类型。

命令名与 Rust 函数名一一对应(restart_core_process),参数名同样保持 snake_case 与 Rust 侧签名一致,这是 invoke 序列化匹配的前提。

插件安装与开发服务器

插件

文档给出的插件安装命令:

# Add plugin via CLI
npm run tauri add <plugin-name>

# Common plugins:
npm run tauri add fs
npm run tauri add dialog
npm run tauri add http
npm run tauri add notification
npm run tauri add store

在本仓库中,app/package.json 已定义 "tauri": "tauri" 脚本,且依赖锁定在 pnpm 工作区(packageManager 字段与 gitbooks/developing/getting-set-up.md 要求 pnpm@10.10.0),因此实际执行时建议写作:

pnpm tauri add fs

仓库当前已在依赖中使用了多个官方插件,如 @tauri-apps/plugin-opener@tauri-apps/plugin-os@tauri-apps/plugin-deep-link@tauri-apps/plugin-barcode-scanner(见 app/package.json 的 dependencies 段),可作为"常用插件"清单的实证参考。

开发服务器

文档列出的三条命令:

# Start with hot reload
npm run tauri dev

# Frontend only
npm run dev

# Check for issues
npm run tauri info

对照 app/package.json 的实际 scripts,本仓库的对应关系是:

文档命令 仓库实际脚本 说明
npm run dev pnpm dev 纯前端 Vite 开发服务器,适合快速迭代 UI
npm run tauri dev pnpm dev:app 完整桌面端热重载开发(内部调用 scripts/run-dev-macos.sh 等平台脚本)
npm run tauri info pnpm tauri info 打印工具链诊断信息

开发环境的前置条件(以 gitbooks/developing/getting-set-up.mdrust-toolchain.toml 为准):

  • Node.js 24+(app/package.jsonengines 字段要求 >=24.0.0
  • pnpm 10.10.0
  • Rust 1.93.0(经 rustup 安装,含 rustfmtclippy
  • CMake(原生 Rust 依赖需要)
  • app/src-tauri/vendor/ 下的 git submodule(vendored CEF 版 Tauri CLI)

首次克隆后按该指南初始化:

git submodule update --init --recursive
pnpm install

代码风格规范:TypeScript 与 Rust 双侧约定

文档"Code Style"一节是两侧语言的硬性约定汇总,可作为 Code Review 的检查清单。

TypeScript 侧

  • 函数式组件 + hooks,不写类组件;
  • 所有 props 和 state 必须有类型;
  • 调用 Tauri 命令统一走 invoke(在仓库实践中即走 app/src/utils/tauriCommands/ 下的封装函数,而非散落各组件的直接 invoke);
  • 错误处理用 try/catch。

Rust 侧

  • 命令一律用 #[tauri::command] 标注;
  • 可失败操作返回 Result<T, E>,禁止在命令体内 unwrap 导致进程级 panic;
  • 共享状态用 State<> 注入;
  • 做 I/O 的命令保持 async。

仓库为这些风格配备了可执行的守门脚本(见 app/package.json):pnpm lint(ESLint 9)、pnpm rust:clippycargo clippy -- -D warnings,警告即失败)、pnpm rust:format:checkcargo fmt --check)、pnpm format:check(prettier 校验)。新增代码提交前跑一遍 pnpm format:check && pnpm lint 是低成本的一致性保障。

测试:前后端双栈验证

文档"Testing"一节给出两条命令:

# Frontend tests
npm test

# Rust tests
cd src-tauri && cargo test

在本仓库中对应(注意 shell 工程位于 app/ 下):

cd app
pnpm test                                  # vitest run --config test/vitest.config.ts
cd src-tauri && cargo test                 # Rust 侧单元测试

仓库实际测试面比文档更宽:

  • 前端单测/组件测试:pnpm testpnpm test:coverage(v8 覆盖率),测试入口配置在 app/test/vitest.config.ts
  • 桌面 shell 的 Rust 测试除 cargo test 外,还有 pnpm test:rust(即 scripts/test-rust-with-mock.sh,带 mock 服务);
  • 端到端:pnpm test:e2e(Playwright,含 web 与 mega-flow 两条线);
  • 一键全量:pnpm test:all = 前端覆盖率 + Rust 测试 + E2E。

以 dev-agent 的产出物视角,最小验证回路是:改前端组件 → pnpm test;新增/修改 Tauri 命令 → cd src-tauri && cargo test + 前端侧对应 tauriCommands 单测(如 app/src/utils/tauriCommands/core.test.ts)。

小结:一张日常开发命令速查表

场景 命令(在 app/ 目录) 依据
纯前端开发 pnpm dev app/package.json
桌面端热重载开发 pnpm dev:app 同上
安装 Tauri 插件 pnpm tauri add <name> dev-agent 文档
类型检查 pnpm compile app/package.json
前端测试 pnpm test 同上
Rust 测试 cd src-tauri && cargo test dev-agent 文档
Rust 静态检查 pnpm rust:clippy app/package.json
全量测试 pnpm test:all 同上

dev-agent 文档的价值在于把"组件模板 → 命令三步走 → 插件 → 环境 → 测试"压缩成一条可执行 SOP;而仓库中的真实代码(app/src-tauri/src/lib.rs 的命令声明与 L3369generate_handler! 注册表、app/src/utils/tauriCommands/core.tsisTauri 守卫与类型化 invoke)则补齐了模板之外的工程细节:条件编译注册、跨 Web/Tauri 双模式的降级、以及可执行的 lint/test 守门。按此路径开发,新增功能的每一步都有对应源码与测试可验证。

登录后查看全文
热门项目推荐
相关项目推荐