Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
0174261
feat(sandbox): 实现多实例沙箱管理 (Phase 5)
May 17, 2026
df7f339
docs(release): 添加 release/README.md,从 .gitignore 放出
May 17, 2026
008a8b2
fix(ci): 修复 CI clippy dead_code 警告和 Rust 版本不兼容
May 17, 2026
1674cde
test: 补充单元测试覆盖率
May 17, 2026
7df683f
test: 补充 keycodes/report/player 覆盖率
May 17, 2026
de9a57a
test: 补充 server/keycodes/player/sandbox 覆盖率至 80.6%
May 17, 2026
e1e0a3c
fix(ci): 修复 tarpaulin 覆盖率报告生成失败问题
May 17, 2026
6b80156
fix(ci): 通过环境变量检测屏幕录制权限,控制截图测试执行
May 17, 2026
7759d2d
fix(test): 截图测试断言接受 200/404/500 三种状态码
May 17, 2026
29d4dea
fix(ci): 给 UI 测试加屏幕录制权限检测保护
May 17, 2026
4bd45be
fix(ci): 替换 tarpaulin 为 cargo-llvm-cov 解决 macOS 覆盖率生成失败
May 17, 2026
0baeba8
fix(ci): 创建 coverage 目录后再运行 llvm-cov
May 17, 2026
57daa20
feat(automation): implement post_to_pid for targeted CGEvent delivery
May 17, 2026
cb273ce
fix(automation): 修复 AXUIElement 崩溃和 Tauri rpath 问题
May 17, 2026
4dd3759
fix(release): Phase 8 release test bug fixes
May 17, 2026
0d58409
fix(ui): prettier formatting for frontend files
May 17, 2026
1049c64
fix(macos): add entitlements and usage descriptions to fix TCC permis…
May 17, 2026
6c54416
fix(ci): add frontend test coverage gate with vitest
May 17, 2026
e70f45d
fix(security): fix glob CVE and migrate to @xterm/xterm
May 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 66 additions & 13 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ concurrency:
env:
NODE_VERSION: '22'
PNPM_VERSION: '9'
RUST_VERSION: '1.88'
RUST_VERSION: '1.91'

jobs:
# ==================== Rust 格式化检查 ====================
Expand Down Expand Up @@ -113,18 +113,15 @@ jobs:
- name: 运行 cargo test
run: cargo test -p sandbox-core

- name: 安装 cargo-tarpaulin
continue-on-error: true
- name: 安装 cargo-llvm-cov
run: |
if ! command -v cargo-tarpaulin &> /dev/null; then
cargo install cargo-tarpaulin --locked
fi
rustup component add llvm-tools-preview
cargo install cargo-llvm-cov --locked

- name: 运行测试覆盖率
if: success()
continue-on-error: true
run: |
cargo tarpaulin -p sandbox-core -p sandbox-cli --out Xml --out Html --output-dir coverage --skip-clean
mkdir -p coverage
cargo llvm-cov -p sandbox-core --cobertura --output-path coverage/cobertura.xml

- name: 生成覆盖率摘要
if: always()
Expand Down Expand Up @@ -157,6 +154,9 @@ jobs:
echo "> 详细报告见 Rust 覆盖率 artifact" >> "$SUMMARY_FILE"
else
echo "> ⚠️ 未生成覆盖率报告" >> "$SUMMARY_FILE"
echo "❌ 覆盖率生成失败:cobertura.xml 未生成" >> "$SUMMARY_FILE"
echo "::error::覆盖率报告生成失败,检查 llvm-cov 输出的测试失败信息"
exit 1
fi
echo "" >> "$SUMMARY_FILE"
cat "$SUMMARY_FILE" >> "$GITHUB_STEP_SUMMARY"
Expand Down Expand Up @@ -325,9 +325,63 @@ jobs:
working-directory: sandbox-web
run: pnpm install --frozen-lockfile

- name: 运行单元测试
- name: 运行单元测试 + 覆盖率
working-directory: sandbox-web
run: pnpm test:unit
run: pnpm vitest run --coverage

- name: 生成覆盖率摘要
if: always()
run: |
SUMMARY_FILE="frontend-coverage-summary.md"
echo "## 前端测试覆盖率" > "$SUMMARY_FILE"
echo "" >> "$SUMMARY_FILE"
COV_JSON="sandbox-web/coverage/coverage-summary.json"
if [ -f "$COV_JSON" ]; then
python3 -c "
import json
with open('$COV_JSON') as f:
data = json.load(f)
total = data.get('total', {})
lines_pct = total.get('lines', {}).get('pct', 0)
branches_pct = total.get('branches', {}).get('pct', 0)
functions_pct = total.get('functions', {}).get('pct', 0)
statements_pct = total.get('statements', {}).get('pct', 0)
print(f'| 指标 | 覆盖率 |')
print(f'|------|--------|')
print(f'| 语句 | {statements_pct:.1f}% |')
print(f'| 分支 | {branches_pct:.1f}% |')
print(f'| 函数 | {functions_pct:.1f}% |')
print(f'| 行 | {lines_pct:.1f}% |')
print()
print('| 文件 | 行覆盖率 |')
print('|------|----------|')
for fpath, metrics in sorted(data.items()):
if fpath == 'total':
continue
fname = fpath.replace('src/', '')
f_lines = metrics.get('lines', {}).get('pct', 0)
bar_len = int(f_lines / 5)
bar = '█' * bar_len + '░' * (20 - bar_len)
print(f'| {fname} | {bar} {f_lines:.1f}% |')
" >> "$SUMMARY_FILE"
echo "" >> "$SUMMARY_FILE"
echo "> 详细报告见前端覆盖率 artifact" >> "$SUMMARY_FILE"
else
echo "> ⚠️ 未生成前端覆盖率报告" >> "$SUMMARY_FILE"
echo "❌ 前端覆盖率生成失败:coverage-summary.json 未生成" >> "$SUMMARY_FILE"
echo "::error::前端覆盖率报告生成失败,检查 vitest --coverage 输出"
exit 1
fi
echo "" >> "$SUMMARY_FILE"
cat "$SUMMARY_FILE" >> "$GITHUB_STEP_SUMMARY"

- name: 上传覆盖率摘要
uses: actions/upload-artifact@v4
if: always()
with:
name: frontend-coverage-summary
path: frontend-coverage-summary.md
retention-days: 1

# ==================== 安全检查 ====================
security:
Expand Down Expand Up @@ -367,7 +421,7 @@ jobs:
working-directory: sandbox-web
run: |
if [ -f pnpm-lock.yaml ]; then
pnpm audit --audit-level=high || echo "::warning::前端依赖存在高危漏洞"
pnpm audit --audit-level=high || { echo "::error::前端依赖存在高危漏洞,请升级到已修复版本"; exit 1; }
else
echo "::notice::未找到 pnpm-lock.yaml,跳过前端依赖审计"
fi
Expand Down Expand Up @@ -429,7 +483,6 @@ jobs:
with:
name: frontend-coverage-summary
path: coverage-artifacts
continue-on-error: true

- name: 检查门禁结果
run: |
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ target/
# Build output
dist/
out/
release/
release/*
!release/README.md

# Rust
**/*.rs.bk
Expand Down
32 changes: 16 additions & 16 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,24 +127,24 @@ system-test-sandbox/
```bash
# 多实例管理
sandbox-cli start --cli "claude" # 启动沙箱,运行 Claude Code,返回 sandbox-id
sandbox-cli start --cli "echo" --args "hello" # 带参数启动 CLI
sandbox-cli start --cli "echo" -- "hello" # 带参数启动 CLI
sandbox-cli start --app "/path/to/App.app" # 启动沙箱,运行 macOS 应用
sandbox-cli list # 列出所有活跃沙箱及其状态
sandbox-cli close <sandbox-id> # 关闭指定沙箱
sandbox-cli inspect <sandbox-id> # 查看沙箱详情

# 沙箱作用域操作 (通过 --id 或 <id> 指定目标沙箱)
sandbox-cli screenshot <id> # 截取沙箱截图
sandbox-cli screenshot <id> -o result.png # 截图并指定输出路径
sandbox-cli click <id> 100 200 # 在沙箱内模拟点击
sandbox-cli type <id> "hello world" # 在沙箱内模拟输入
sandbox-cli key <id> Return --modifiers cmd # 在沙箱内模拟按键
# 沙箱作用域操作 (通过 --id 指定目标沙箱)
sandbox-cli screenshot --id <id> # 截取沙箱截图
sandbox-cli screenshot --id <id> -o result.png # 截图并指定输出路径
sandbox-cli click --id <id> 100 200 # 在沙箱内模拟点击
sandbox-cli type --id <id> "hello world" # 在沙箱内模拟输入
sandbox-cli key --id <id> Return --modifiers cmd # 在沙箱内模拟按键

# 进程管理 (沙箱内)
sandbox-cli windows <id> # 列出沙箱内窗口
sandbox-cli processes <id> # 列出沙箱内进程
sandbox-cli spawn-cli <id> "npm" --args "test" # 在沙箱内启动新的 CLI
sandbox-cli kill <id> <pid> # 终止沙箱内进程
sandbox-cli windows --id <id> # 列出沙箱内窗口
sandbox-cli processes --id <id> # 列出沙箱内进程
sandbox-cli spawn-cli --id <id> "npm" -- "test" # 在沙箱内启动新的 CLI
sandbox-cli kill --id <id> <pid> # 终止沙箱内进程

# 独立模式 (无多实例,向后兼容)
sandbox-cli serve --port 5801 # 启动独立 HTTP + MCP 服务器
Expand Down Expand Up @@ -298,7 +298,7 @@ fix(server): 修复 HTTP API 端口冲突
### 7.1 任务执行流程

```
[1]创建任务记录(待执行) → [2]创建特性分支 → [3]编写设计文档
[1]创建任务记录(待执行) → [2]创建特性分支 → [3]编写设计文档(写到docs/design)
→ [4]编写测试(RED) → [5]编码实现(GREEN) → [6]重构优化(REFACTOR)
→ [7]本地检查(fmt+clippy+check+typecheck) → [8]验证测试覆盖率
→ [9]更新任务状态(已完成,必须在push前) → [10]git commit → [11]git push
Expand All @@ -325,10 +325,10 @@ sandbox-cli list
# → def456 "cc-switch" APP Running 15802 2026-05-16 10:31

# 4. 操作指定沙箱
sandbox-cli screenshot abc123 -o sandbox.png # 截图
sandbox-cli click abc123 100 200 # 点击
sandbox-cli type abc123 "帮我写一个函数" # 输入文本
sandbox-cli key abc123 Return # 按键
sandbox-cli screenshot --id abc123 -o sandbox.png # 截图
sandbox-cli click --id abc123 100 200 # 点击
sandbox-cli type --id abc123 "帮我写一个函数" # 输入文本
sandbox-cli key --id abc123 Return # 按键

# 5. 关闭沙箱
sandbox-cli close abc123
Expand Down
Loading
Loading