本文件面向 AI Agent 与开发者,记录工具设计、架构选型、决议项与开发约定。 项目渊源:原始上游为 3 个分离的 xxx2api 仓库 → workbuddy-wild v0.1.x(wails GUI 包装器)→ v0.2.x(增加 traework 集成)→ v2.0.x(大改版弃用 wails,改用系统托盘 daemon + Web UI,增加 qoder 渠道)。 当前
master分支为 v2.0.x 版本;v0.2.x 已迁移至legacy-wails分支。
Wild-Work 是 WorkBuddy/TraeWork/Qoder 三渠道账号聚合工具,演进历程:
- 上游 API 仓库:3 个独立仓库 (
wild-work-buddy-api,wild-work-traework-api,wild-work-qoder-api) → 提供各渠道基础 API 封装 - v0.1.x (workbuddy-wild):Wails GUI 包装器,仅支持 WorkBuddy 单渠道
- v0.2.x:增加 TraeWork 集成,仍用 Wails
- v2.0.x (当前 master):大改版弃用 Wails,改用系统托盘 daemon + 浏览器 Web UI;新增 Qoder 渠道
⚠️ v0.2.x 代码已迁移至legacy-wails分支,不再维护。
去掉 wails/WebView2,改为 系统托盘 daemon + 系统浏览器 Web UI 的多平台(Win/mac)多渠道账号聚合工具。
| # | 决议 | 说明 |
|---|---|---|
| R1 | 托盘菜单固定,不做动态内容、不做定时/事件刷新 | 用户在自己客户端操作无法捕捉,动态展示无意义 |
| R2 | 托盘菜单精简为:打开主界面 / 查看日志 / 退出 | |
| R3 | 托盘固定菜单项:打开主界面 / 查看日志 / 退出 | 双击托盘 = 打开主界面;不再弹"已启动"提示框 |
| R4 | 不设管理 API 鉴权 | 单机个人工具;监听 0.0.0.0 的风险由用户承担,UI/文档给一句风险提示 |
| R5 | Web UI 用纯静态 HTML/CSS/JS(无前端编译链) | go:embed 打进单文件;实用 + 大众审美即可 |
| R6 | 托盘库:保留 energye/systray(已跨平台 Win/mac/Linux) | 各菜单项使用不同颜色纯 Go 生成图标,无需外部图标文件 |
| R7 | 移除 wails / WebView2 全部依赖 | 省内存与运行时;平台能力封装进 internal/platform(build tag 拆分) |
| R8 | daemon 单进程:一个 http.Server 同时服务 OpenAI 端点 + 管理 API + 静态 UI |
沿用 server 现有 ServeMux 扩展 |
| R9 | 核心业务(pool/scheduler/upstream/traework/server/login/config/auth/provider)整体复用,格式零迁移 | config.json / auths/ / data/state.json 兼容旧版;旧 state.json 自动迁移到 state-workbuddy.json |
| R10 | 新增渠道扩展方式:实现 provider.Upstream 接口 + auth 加载器 + 注册 Runtime |
模型前缀 channel/<model> 路由;已实现 WorkBuddy + TraeWork + Qoder 三渠道 |
| R11 | Windows 产物在 WSL 交叉编译(GOOS=windows CGO_ENABLED=0,已验证可行);macOS 产物走 GitHub Actions macos-latest(cgo 必需) |
WSL 无法编 darwin cgo;CI 增加 darwin job |
| R12 | 无桌面 Linux 使用 --no-tray 参数 |
无参启动在无 DBus 环境托盘 panic 直接 exit 并提示;--no-tray 跳过托盘打印信息阻塞等待 Ctrl+C |
| 主题 | 选型 | 理由 |
|---|---|---|
| GUI 壳 | 无(删除 wails) | WebView2 内存开销大 + Windows 绑定;托盘 + 浏览器足够 |
| 托盘 | energye/systray v1.0.3(现有) | 已跨平台;菜单固定方案规避其不可删菜单项限制 |
| 管理后端 | 现有 http.Server 扩展 /api/* | 单端口、复用鉴权中间件(无鉴权)、零新服务 |
| Web UI | 纯静态 embed + fetch | 无 Node 构建链,单 exe 双击即用 |
| 登录 | 复用 internal/login + login_trae | 纯 HTTP + 本地回调端口,跨平台 |
| 平台能力 | internal/platform + build tag(windows/darwin/other) | 浏览器无痕/开机自启/消息框/日志/工作区,接口同名 |
| 构建 | WSL 交叉编译 win;CI macos-latest 编 darwin | 见 R11 |
wild-work
──────────
打开主界面 → 系统浏览器打开 http://<listen>/
查看日志 → 系统默认编辑器打开 data/app.log
──────────
退出 → 退出 daemon(确认框)
- 单击/双击/右击:右击弹菜单;单击与双击 = 打开主界面
- 各菜单项使用不同颜色纯 Go 生成图标(蓝色=打开、灰色=日志、红色=退出)
- 刷新积分功能已移至 Web UI 面板操作
| 页面/区块 | 内容 |
|---|---|
| 顶部栏 | 品牌名/版本号、API 地址(点击弹窗配置)、API-Key(点击弹窗修改)、帮助/关于 |
| 账号管理 | 双列卡片网格,账号名/UID/积分/签到状态,图标按钮操作(签到/刷新/停用/删除) |
| 自动签到 | 签到时间(HH:MM 多组)+ 开机自启开关(左右布局) |
| 渠道费率 | 三渠道模型定价表(按渠道分组,合并单元格),刷新按钮 |
管理 API(REST,均挂 /api/*):
GET /api/state # 全量状态(账号/积分/签到/配置)
POST /api/login/start # {channel} → {auth_url}
POST /api/login/cancel
POST /api/account/checkin # {uid}
POST /api/account/checkin_all
POST /api/account/refresh # {uid}
POST /api/account/refresh_all
POST /api/account/remove # {uid}
POST /api/account/disable # {uid,disabled} 停用/启用
POST /api/account/resource_detail # {uid} → 积分明细
POST /api/config/checkin_times # {times:["09:00","21:30"]}
POST /api/config/listen # {host,port}
POST /api/config/api_key # {key}
POST /api/config/autostart # {on:bool}
GET /api/fees # 渠道费率(本地缓存 + 按需刷新)
POST /api/fees/refresh # 异步刷新费率
GET /api/logs # 最近 300 行日志
POST /api/quit # 退出程序
- 新建
internal/<channel>/包,实现provider.Upstream接口 internal/auth增加对应Load<Channel>Dir()(文件名前缀<channel>-*.json)- 装配处注册
server.Runtime{Kind, Pool, Upstream, StaticModels}+app.Runtime{..., Scheduler} - 前端渠道选择器加一项;
internal/login_<channel>实现登录编排(如需)
provider.Kind 即模型名前缀;server 按
channel/<model>前缀路由,无需改接口。 Qoder 渠道无签到活动:DailyCheckin返回错误,调度器只做 token keepalive。QClaw 渠道(
internal/qclaw,2026-09-23):对接 QClaw 桌面端(OpenClaw 内核)的本地 AuthGateway——桌面端在127.0.0.1:19000起 OpenAI 兼容 LLM 代理(/proxy/llm/chat/completions、/proxy/llm/models),鉴权由网关自注入,无需 API Key。多账号形态:QClaw 无 Linux 版、云端有请求签名(HMAC 绑设备,逆向不可行),采用多开 macOS 实例——scripts/qclaw-multi.sh start <名> <序号>启动隔离实例(HOME + user-data-dir 双隔离),网关端口自动递增(19000/19001/19002…,实测三实例并存),每实例登录一个账号,auths/qclaw-<名>.json的 apiHost 指向对应端口,scripts/qclaw-tunnel.sh 19000 19001 …多端口反向隧道到服务器。两个硬约束(逆向 0.2.37 实测):
- messages 必须含 system 消息,缺失整单
invalid request(PrepareBody兜底补入);- 网关拉黑 Go 默认 UA(
Go-http-client/*→invalid request),必须显式设 UA。auth 文件
auths/qclaw-*.json(扁平形):apiHost指定网关地址(默认http://127.0.0.1:19000/proxy/llm)+ uid/nickname;accessToken 占位、expiresAt 自动远期化。通道依赖桌面端进程在线;远程部署时用 SSH 隧道(ssh -R 19000:127.0.0.1:19000 <server>)并把 apiHost 指向隧道地址。模型:qclaw/modelroute(Auto 路由,支持视觉)与qclaw/pool-*系列。
PrepareBody三改写勿动:强制stream=true、tool_choice归一化、developer→system- 日志/面板/消息框零 token:不得输出 access/refresh token(调试用假 token)
- auth 文件嵌套格式
{auth:{...},account:{...}},internal/auth.Parse与 login.SaveAuth 必须一致 config.listen兼容新对象格式 + 旧字符串格式":7863"data/state-*.json只增不减字段,向后兼容;旧 state.json 自动迁移- 托盘回调必须 goroutine 化
config.example.json与config.Default()同步- 上游 HTTP ≥400 错误处理:mask_upstream 开(默认)时对外发中性 OpenAI 错误(原文写 app.log 保排障);关掩码时直接透传原始响应。内容审核拦截文案始终为网关自己的防火墙文案
- 定价缓存持久化到
data/pricing-cache.json,启动加载,超 1h 自动刷新 - 无桌面 Linux 必须
--no-tray,不带参数 panic 直接 exit 提示 - 粘性路由(会话级):
pickWithStickyForModel按【渠道+会话指纹】(upstream.ConversationFingerprint,与缓存键会话源同优先级)粘住账号,直至该会话连续成功 50 次或账号故障(冷却/禁用/6004)。只有账号侧错误清粘性(6004/欠费/会话死/5xx/传输失败/卡流);11140/11133 等请求内容错误不清——账号健康,续用同号保缓存。会话级化的原因:prompt_cache_key 含 uid,换号=换键=上游前缀缓存全冷;渠道全局粘性时 48h 换号 639 次、698 个零缓存大请求中 647 个由换号导致(2026-09-29 实测)。粘性表 4096 条上限 + 2h 空闲淘汰。不使用 credits 阈值(pool 中余额是 stale 数据)。 - 存储双模式:
storage.mode= file(默认,jsonl 追加零依赖)/ postgres(请求日志+防火墙事件落 PG,jsonl 停写不改不删)。PG 模式:内存环两种模式都保留;面板/api/request_logs/page响应形状不变但 total 为真实总数,新增可选过滤参数(model/uid/status_class/since/until,file 模式忽略);请求体存档永远走文件(body_file 是文件名,不入库);历史用cmd/reqlog-import一次性导入,meta 表防重跑;切回 file 即恢复 jsonl 追加(回滚安全)
| 能力 | Windows | macOS | Linux |
|---|---|---|---|
| 打开浏览器 | rundll32 url.dll | open <url> |
xdg-open |
| 系统消息框 | MessageBoxW | osascript display dialog | stderr |
| 开机自启 | 注册表 Run | LaunchAgent plist | 未实现 |
| 打开日志文件 | notepad | open -a TextEdit | xdg-open |
| 确认框 | MessageBoxW YESNO | osascript buttons | 默认否 |
| 无头模式 | --no-tray | --no-tray | --no-tray(推荐) |
# Windows(WSL 交叉编译)
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-H windowsgui" -o dist/wild-work.exe ./cmd/wild-work
# macOS(需 macOS 真机或 CI,cgo 必需)
GOOS=darwin GOARCH=arm64 go build -o dist/wild-work-darwin ./cmd/wild-work
# Linux 无头
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o dist/wild-work-linux ./cmd/wild-work- README.md — 用户文档
- DEVELOPMENT.md — 开发者文档(面向 AI Agent)
- HANDOFF.md — 交接文档(历史记录)