12 KiB

name, version, description, metadata
name version description metadata
uncaged-dev 1.0.0 Uncaged 项目的完整开发 skill。涵盖:项目架构、开发流程、build/deploy、 测试验证、调试排查。装这一个 skill 就获得所有 Uncaged 开发能力。
requiredTools
secret
gh

Uncaged Dev

Uncaged 项目开发的一站式 skill。

项目概览

Uncaged — Sigil-native AI Agent 平台,运行在 Cloudflare Workers 上。

uncaged/
├── packages/
│   ├── core/          # 共享核心:LLM、Memory、Sigil、Tool Registry
│   ├── worker/        # CF Worker(后端 API + routing)
│   ├── web/           # React 19 + Tailwind v4 前端(SPA)
│   └── runner/        # Runner 客户端(连设备到 Agent)
├── tests/e2e/         # 场景化测试用例
├── scripts/           # 部署脚本
└── .github/workflows/ # CI/CD

仓库: oc-xiaoju/uncaged 线上: https://uncaged.shazhou.work CI/CD: push main → GitHub Actions 自动部署

开发流程

原则:Issue 驱动,协调者不写代码,Cursor Agent 干活。

需求/Bug → 开 Issue → 创建分支 → Cursor Agent 编码 → 
验证(build + diff)→ Commit(closes #N)→ 合并 main → 自动部署

1. 开 Issue

gh issue create --repo oc-xiaoju/uncaged \
  --title "fix/feat: 简短描述" \
  --body "## Problem\n...\n## Plan\n...\n## Acceptance\n..."

2. 创建分支

cd <uncaged-repo>
git checkout main && git pull
git checkout -b fix/descriptive-name   # 或 feat/

3. 用 Cursor Agent 编码

CURSOR_API_KEY="$(secret get CURSOR_API_KEY)" \
  bash ~/.openclaw/workspace/skills/cursor-agent-cn/scripts/run.sh \
  <uncaged-repo> "<任务描述>" auto ask    # 先 review
# 确认后
  ... auto write                          # 再 apply

中国区必须用 auto model。两步走:先 ask review,再 write apply。

4. 验证

# Build(三步)
cd packages/core && rm -rf dist && npx tsc
cd ../web && npm run build
cd ../worker && npx tsc --noEmit

# Diff 检查
git diff --stat

5. 提交 + 合并

git add -A
git commit -m "fix: description (closes #N)"
git checkout main && git merge <branch> --no-ff
git push origin main    # 触发 CI/CD 自动部署

Build & Deploy

线上(自动)

Push main → GitHub Actions → build core → build web → wrangler deploy

开发环境(手动)

每人一个独立 Worker,互不影响:

bash scripts/deploy-dev.sh xingyue    # → uncaged-xingyue.shazhou.work
bash scripts/deploy-dev.sh xiaoju     # → uncaged-xiaoju.shazhou.work
bash scripts/deploy-dev.sh xiaomooo   # → uncaged-xiaomooo.shazhou.work
bash scripts/deploy-dev.sh aobing     # → uncaged-aobing.shazhou.work

脚本自动:build core → build web → wrangler deploy --env

手动部署线上(紧急)

cd packages/core && rm -rf dist && npx tsc
cd ../web && npm run build
cd ../worker
CLOUDFLARE_API_TOKEN="$(secret get CLOUDFLARE_API_TOKEN)" \
CLOUDFLARE_ACCOUNT_ID="$(secret get CLOUDFLARE_ACCOUNT_ID)" \
  npx wrangler deploy

常见 Build 问题

问题 原因 解决
core dist 为空 tsconfig 缺 noEmitOnError: false 检查 packages/core/tsconfig.json
wrangler can't resolve @uncaged/core/* core 没 build cd packages/core && npx tsc
POST 请求返回 SPA HTML wrangler.toml 缺 run_worker_first = true 检查 [assets] 配置
路由 404 normalizeApiPath strip 了 /api/v1/ 路由匹配用 strip 后路径

测试

测试分层

层级 工具 位置 用途
Unit Test Vitest packages/*/src/*.test.ts 纯逻辑,mock 外部依赖,秒级
UI 组件测试 Vitest + @testing-library/react packages/web/src/**/*.test.tsx React 组件交互,mock fetch
E2E API curl 脚本 tests/e2e/scripts/run-tests.sh 真实 HTTP 请求打线上 API
E2E UI Playwright tests/e2e/ui/*.spec.ts 浏览器自动化,端到端流程

跑测试的顺序: UT → UI 组件 → build → E2E(先快后慢,先本地后线上)

Unit Test

# 跑全部 UT
cd packages/core && npx vitest run
cd packages/worker && npx vitest run
cd packages/web && npx vitest run    # UI 组件测试也在这

# 跑单个文件
npx vitest run src/agent-loop.test.ts

# Watch 模式(开发时)
npx vitest --watch

写 UT 的规范:

  • 文件放在被测源码旁边:foo.tsfoo.test.ts
  • Mock 外部依赖(KV、D1、fetch),参考 core/src/__mocks__/cf-bindings.ts
  • 测试文件不要 import 真实 Cloudflare bindings
  • describe 按功能分组,test 名字说清楚测的是什么行为
  • 验收:npx vitest run 全绿 + 无 type error

现有 UT 覆盖(13 文件 134 tests):

  • agent-loop — loop 流程、tool call、maxRounds、nudge、streaming
  • pipeline — model 选择、context 压缩、orphan tool 清理
  • baton — 创建、状态流转、子 baton 事件
  • tool-registry — 注册、查询、user-invocable 过滤
  • chat-store + chat-store-kv — 消息存储/读取
  • identity / soul / codegen / embedding / chat-key / short-id / slug-resolver

UI 组件测试

cd packages/web && npx vitest run

写 UI 组件测试的规范:

  • @testing-library/react + jsdom 环境
  • 文件放在组件旁边:chat-input.tsxchat-input.test.tsx
  • Mock fetch / authedFetch,不打真实 API
  • 优先测用户交互(输入、点击、键盘事件)和渲染结果
  • 使用 data-testid(#71 已添加)定位元素
  • 不测样式/CSS,测行为和 DOM 结构

Playwright UI 测试(9 个用例,28 秒)

cd <uncaged-repo>
npx playwright test                    # 跑全部
npx playwright test -g "tool search"   # 跑单个
npx playwright test --reporter=html    # 生成 HTML 报告

覆盖:token 登录、聊天发消息、工具搜索浮层、ESC 关闭、主题切换、JS 错误检测、手机端布局。

首次使用需安装浏览器: npx playwright install chromium

指定目标环境: UNCAGED_URL=https://uncaged-xingyue.shazhou.work npx playwright test

指定 token: TOKEN_NAME=UNCAGED_AGENT_TOKEN_XIAOJU npx playwright test

API 回归(12 个用例,curl 脚本)

bash tests/e2e/scripts/run-tests.sh UNCAGED_AGENT_TOKEN_XINGYUE

场景验证(给 subagent 用)

场景文件在 tests/e2e/scenes/

场景 文件
认证 scenes/auth.md
聊天 scenes/chat.md
流式 scenes/streaming.md
Tool Gateway scenes/tool-gateway.md
工具搜索 scenes/tool-search.md
异常处理 scenes/error-handling.md

派 subagent 验证:

读 <uncaged-repo>/tests/e2e/scenes/tool-gateway.md,按描述验证。
失败了收集 logs 开 bug issue。

Token 登录(测试用)

TOKEN=$(secret get UNCAGED_AGENT_TOKEN_XINGYUE)
curl -s -X POST "https://uncaged.shazhou.work/auth/token" \
  -H "Content-Type: application/json" \
  -d "{\"token\": \"$TOKEN\"}" \
  -c /tmp/uncaged-cookies.txt

uncaged-cli 工具

安装:

npm install -g @uncaged/cli    # 官方版本
# 或
npm install -g uncaged-cli     # 备用版本

基本用法:

# 初始化配置
uncaged init

# 登录(自动检测 JWT token 或生成 Admin token)
uncaged login

# 环境状态检查
uncaged status

# 数据库查询
uncaged db users --limit 10
uncaged db messages --user scott --channel web --limit 20
uncaged db agents --format table
uncaged db context-boundaries --user scott --channel telegram

# API 调试
uncaged api chat "hello world"
uncaged api history --user scott --channel web --limit 10
uncaged api debug overview
uncaged api debug stats
uncaged api debug capabilities

# 测试用户管理(Admin 权限)
uncaged admin create-user test-user-123
uncaged admin delete-user test-user-123 --cascade
uncaged admin create-token test-user-123

# Sigil 操作
uncaged sigil list
uncaged sigil inspect <capability-name>

# 配置管理
uncaged config show
uncaged config set endpoint https://uncaged-dev.shazhou.work
uncaged config set auth.method admin

多环境切换:

# 开发环境
uncaged config set endpoint https://uncaged-xingyue.shazhou.work
uncaged config set auth.method jwt
uncaged config set auth.token "$(secret get UNCAGED_AGENT_TOKEN_XINGYUE)"

# 生产环境  
uncaged config set endpoint https://uncaged.shazhou.work
uncaged config set auth.method admin
uncaged config set auth.admin_token "$(secret get UNCAGED_ADMIN_TOKEN)"

# 查看当前配置
uncaged status

Channel 概念:

  • web — 网页聊天
  • telegram — Telegram 消息
  • api — 直接 API 调用

所有 dbapi 命令都支持 --channel 过滤。

调试

Worker 日志

CF_TOKEN=$(secret get CLOUDFLARE_API_TOKEN)
CF_ACCOUNT=$(secret get CLOUDFLARE_ACCOUNT_ID)
cd <uncaged-repo>/packages/worker
CLOUDFLARE_API_TOKEN="$CF_TOKEN" CLOUDFLARE_ACCOUNT_ID="$CF_ACCOUNT" \
  npx wrangler tail --format pretty

D1 查询

CLOUDFLARE_API_TOKEN="$CF_TOKEN" CLOUDFLARE_ACCOUNT_ID="$CF_ACCOUNT" \
  npx wrangler d1 execute uncaged-memory --remote --json \
  --command "SELECT * FROM users LIMIT 10;"

前端状态

# Session
curl -s https://uncaged.shazhou.work/auth/session -b /tmp/uncaged-cookies.txt | python3 -m json.tool
# History
curl -s https://uncaged.shazhou.work/scott/doudou/api/history -b /tmp/uncaged-cookies.txt | python3 -c "
import sys,json; [print(f'  [{m[\"role\"]}] {str(m.get(\"content\",\"\"))[:80]}') for m in json.load(sys.stdin)['history'][-5:]]"

架构速查

API

端点 方法 说明
/auth/token POST Token 登录
/auth/session GET Session 检查
/:o/:a/api/v1/chat POST 发消息
/:o/:a/api/v1/chat/stream POST SSE 流式
/:o/:a/api/v1/history GET 聊天历史
/:o/:a/api/v1/clear POST 清空历史
/:o/:a/api/v1/tools/builtin GET Builtin 工具列表
/:o/:a/api/v1/tools/:slug/invoke POST 直接调用工具

关键文件

文件 作用
core/src/llm/tool-registry.ts SSOT — 所有 builtin tool 定义
core/src/llm/agent-loop.ts LLM agent loop + tool execution
worker/src/index.ts 主路由 + Worker entry
worker/src/services/capability-service.ts Tool Gateway 执行层
web/src/hooks/use-chat.ts 前端聊天状态
web/src/components/chat/chat-input.tsx 输入框 + 工具搜索
web/src/components/chat/message-bubble.tsx 消息气泡渲染
worker/wrangler.toml CF 配置(bindings + routes + envs)

路由注意事项

  • 所有前端 API 调用统一使用 /api/v1/ 前缀(#73 已清理)
  • normalizeApiPath 只 strip /api/v1/ 前缀(不再处理 /api/
  • 新路由要用 strip 后的路径匹配(如 /tools/:slug/invoke 不是 /api/v1/tools/...
  • [assets] run_worker_first = true 确保 POST 请求到 Worker
  • 没有 webEnabledhasBearerchannels/web.ts(#73 已删除)

Tool Registry(SSOT)

添加新 builtin tool 只需改 core/src/llm/tool-registry.tsTOOL_REGISTRY 数组,LLM / Gateway / 前端自动同步。

Secrets

secret get CLOUDFLARE_API_TOKEN       # CF 部署
secret get CLOUDFLARE_ACCOUNT_ID      # CF 账户
secret get CURSOR_API_KEY             # Cursor Agent
secret get UNCAGED_AGENT_TOKEN_XINGYUE # 测试登录 token