ClawCraft
OpenClaw 的 RTS(即时战略)风格图形配置管理界面,通过城堡/领主/探险者/建筑等隐喻可视化 Agent 生态系统。
概述
ClawCraft 是一个基于 PixiJS 2D Canvas 的 OpenClaw 图形管理界面,采用 RTS 游戏风格将 Agent、Gateway、Channel、Model 等概念映射为城堡建筑系统。用户可以通过拖拽建筑、点击面板来管理 OpenClaw 的配置。项目由 craftbot 开发维护。
技术栈
- 前端:React 18 + TypeScript + PixiJS + Zustand + Tailwind CSS + Vite
- 后端:OpenClaw Gateway 插件(Node.js/TypeScript)
- 认证:Logto OAuth(@logto/react)
- 部署:Caddy + SCP + pm2
项目规模
- 前端 67 文件 / ~16,800 行
- 后端插件 ~2,675 行
- 总计 ~19,500+ 行
- 54 个配置域 100% 覆盖
- 版本:v0.9.5-dev
核心架构
数据对接
前端通过 3 个通道对接后端(Gateway 插件):
| 通道 | 端点 | 用途 |
|---|---|---|
| SSE 长连接 | /clawcraft/events | 实时推送状态变更 |
| 全量快照 | /clawcraft/state | 连接后拉取完整状态 |
| 配置读取 | /clawcraft/config | 管理面板读取配置(密钥脱敏) |
数据流程
- 页面加载 →
useSSE('/clawcraft/events')建立 SSE 连接 - SSE 收到
connected事件 →fetch('/clawcraft/state')拉全量快照写入 Zustand store - 后续 SSE 推送
state-update增量 delta →applyDelta()局部更新 - 面板操作 → 各自 fetch
/clawcraft/config或/clawcraft/action
插件注册
ClawCraft 作为 OpenClaw 插件运行,注册了 11 个 HTTP 路由和 9 个 hooks。插件位于 ~/.openclaw/extensions/clawcraft/(非 workspace/plugins/)。
RTS 隐喻体系
| 概念 | RTS 隐喻 | 说明 |
|---|---|---|
| Gateway | 城堡/主城 | 核心入口,显示领主数/探险者数/频道数 |
| Agent | 领主 | 每个 Agent 对应一个建筑 |
| Channel | 频道建筑 | Mattermost/WhatsApp 等 |
| Model Provider | 模型熔炉 | 显示提供商和模型列表 |
| Binding | 绑定 | Agent 与 Channel 的关联 |
| Session | 探险者 | 活跃会话 |
交互系统
- 建筑拖拽:PixiJS Canvas 内拖拽调整布局,pointerup 时保存位置
- 面板系统:15 个 lazy-loaded 面板(Gateway/Channel/Model/Agent/Activity/Chat 等)
- 对话功能:可直接与 Agent 聊天,支持多轮对话、Session 切换、消息持久化
- 事件日志:实时显示系统事件,默认折叠
- 音效系统:
soundManager提供 hover/select/event/error/complete 音效 - 城墙工具:围墙绘制/清除功能
- 快捷栏:底部功能快捷入口
代码质量审查结果
审查后的质量评分:81/100
已修复问题(21+7 项):
| 类别 | 修复内容 |
|---|---|
| XSS | dangerouslySetInnerHTML → react-markdown |
| ARIA | 16 处 aria/role 属性 |
| 移动端 | min-width:1280px → sm:hidden 全屏提示 |
| 性能 | authFetch token 缓存 55s TTL |
| 代码结构 | WorldCanvas 拆分 (1912→1153+775) |
| Markdown | react-markdown 替换手写 regex |
| 安全 | focus trap + StrictMode 条件化 |
| 样式 | ErrorBoundary + Skeleton 统一 + StyledSelect + theme.ts |
正面发现
- RTS 隐喻一致性优秀,贯穿始终
- PixiJS Canvas 性能优秀(ticker 内用 getState(),不触发 React re-render)
- 代码分割好(15 个 lazy-loaded 面板,manualChunks)
- Zustand store 设计合理(89 处精确 selector)
重大 Bug 历史
SSE 无限重连死循环(2026-03-20)
症状:页面加载或拖拽建筑时界面卡死,SSE 连接疯狂创建(250+ 个)
根因链:
authFetch调用 LogtogetAccessToken()- Logto 内部
proxy()每次调用setIsLoading(true/false)修改 React Context - Context 变化触发整个组件树 re-render
- ProtectedRoute 在 isLoading 时 unmount App → 所有 Effect cleanup
- App remount → 新 SSE 连接 → 又调 getAccessToken → 死循环
修复:SSE 和 fetchSnapshot 移除 getAccessToken 调用;useSSE effect 依赖改为 [];module-level 防重入锁。
对话消息消失(2026-03-17)
根因:loadChatHistory 在流式响应过程中被触发,用空数组覆盖已有消息。
修复:5 处代码修改,包括 loadChatHistory 防重入、空结果不覆盖、session key 匹配修正。
部署环境
生产环境
| 组件 | 位置 |
|---|---|
| 服务器 | owl (4.193.115.141:18822, user restry) |
| 前端 | ~/clawcraft/frontend/ → Caddy 静态文件 |
| 插件 | ~/.openclaw/extensions/clawcraft/ |
| Gateway | systemd service,端口 18789 |
| Caddy | craft.clawlines.net → 静态文件 + API 反代 |
| HTTPS | Let’s Encrypt 自动管理 |
开发环境
| 组件 | 位置 |
|---|---|
| 架构 | clawedbot Caddy → owl:18852 全量反代 |
| 域名 | craft.dev.dora.restry.cn |
| 前端源码 | poc/frontend/src/ |
| 插件源码 | poc/plugin/ |
| pm2 | dev-craft (:3010 静态 dist) |
| vite dev | :4010(按需启动) |
停用域名
clawcraft.octopus-ops.net— 已停用(2026-03-18)
安全注意事项
🔴 开发环境安全债务:
- Gateway auth 设为
none(仅 loopback 绑定) - 插件
CLAWCRAFT_AUTH_SKIP=true跳过 Logto 认证 - 功能开发完成后需恢复:Logto JWT + Gateway auth 统一方案
时间线
- 2026-03-11~15: 概念到全覆盖(5 天),54 配置域 100%
- 2026-03-17: 8 轮 UX 迭代 + 核心 Bug 修复
- 2026-03-18: 测试服迁移至 owl + Monorepo 重构 + 部署
- 2026-03-19: Logto JWT 认证集成
- 2026-03-20: SSE 死循环修复 + 25 项审查优化
- 2026-03-24: 项目稳定,v0.9.5-dev
相关主题
- craftbot — 项目开发 Agent
- openclaw-config — OpenClaw 平台配置
- caddy-reverse-proxy — Caddy 反向代理
- model-provider-config — 模型配置(39 个 Azure 模型)
- multi-agent-architecture — 多 Agent 架构
- clawline-plugin — 关联项目