feat: Add imitate-auto-v3 workflow for high-speed multi-page UI replication

- Introduced a new workflow named `imitate-auto-v3` that allows for batch screenshot capture and optional token refinement.
- Implemented a comprehensive 5-phase execution protocol to handle initialization, screenshot capture, style extraction, token processing, and UI generation.
- Added support for multiple target URLs through a `--url-map` parameter, enhancing flexibility in design replication.
- Included optional parameters for session management and token refinement, allowing users to customize their workflow experience.
- Enhanced error handling and reporting throughout the workflow to ensure clarity and ease of debugging.
- Deprecated the previous `imitate-auto.md` workflow in favor of this more robust version.
This commit is contained in:
catlog22
2025-10-11 11:42:33 +08:00
parent f07e77e9fa
commit 2fcd44e856
7 changed files with 2500 additions and 6 deletions

View File

@@ -0,0 +1,533 @@
---
name: capture
description: Batch screenshot capture for UI design workflows using MCP or local fallback
usage: /workflow:ui-design:capture --url-map "<map>" [--base-path <path>] [--session <id>]
examples:
- /workflow:ui-design:capture --url-map "home:https://linear.app, pricing:https://linear.app/pricing"
- /workflow:ui-design:capture --session WFS-auth --url-map "dashboard:https://app.com/dash"
- /workflow:ui-design:capture --base-path ".workflow/.design/run-20250110" --url-map "hero:https://example.com#hero"
allowed-tools: TodoWrite(*), Read(*), Write(*), Bash(*), Glob(*), mcp__browser__screenshot(*)
---
# Batch Screenshot Capture Command
## Overview
独立的批量截图命令支持MCP优先策略和多级降级机制。可被其他工作流复用。
## Core Philosophy
- **MCP优先**优先使用mcp__browser__screenshot如果可用
- **智能降级**MCP失败 → Playwright → Chrome → 手动上传
- **批量处理**一次处理多个URL并行截图
- **结构化输出**按target_name组织截图文件
- **错误容忍**:部分失败不阻塞整体流程
## Execution Protocol
### Phase 0: 初始化和路径解析
```bash
# 确定base path
IF --base-path:
base_path = {provided_base_path}
ELSE IF --session:
# 查找session最新design run
session_design_dirs = Glob(".workflow/WFS-{session}/design-*")
IF session_design_dirs:
base_path = most_recent(session_design_dirs)
ELSE:
# 创建新的design run
run_id = "run-$(date +%Y%m%d-%H%M%S)"
base_path = ".workflow/WFS-{session}/design-{run_id}"
ELSE:
# Standalone模式
run_id = "run-$(date +%Y%m%d-%H%M%S)"
base_path = ".workflow/.design/{run_id}"
# 创建截图目录
screenshot_dir = "{base_path}/screenshots"
Bash(mkdir -p "{screenshot_dir}")
REPORT: "📸 Batch Screenshot Capture"
REPORT: " Output: {screenshot_dir}/"
# 解析url-map
url_map_string = {--url-map} # "home:https://a.com, pricing:https://a.com/pricing"
# 解析逻辑
url_entries = []
FOR pair IN split(url_map_string, ","):
pair = pair.strip()
IF ":" NOT IN pair:
ERROR: "Invalid url-map format: '{pair}'"
ERROR: "Expected format: 'target:url'"
ERROR: "Example: 'home:https://example.com, pricing:https://example.com/pricing'"
EXIT 1
target, url = pair.split(":", 1)
target = target.strip().lower().replace(" ", "-")
url = url.strip()
# 验证target名称
IF NOT regex_match(target, r"^[a-z0-9][a-z0-9_-]*$"):
ERROR: "Invalid target name: '{target}'"
ERROR: "Target names must start with alphanumeric and contain only [a-z0-9_-]"
EXIT 1
# 验证URL格式
IF NOT (url.startswith("http://") OR url.startswith("https://")):
WARN: "URL '{url}' does not start with http:// or https://"
WARN: "Prepending https:// automatically"
url = f"https://{url}"
url_entries.append({"target": target, "url": url})
VALIDATE: len(url_entries) > 0, "url-map must contain at least one target:url pair"
total_targets = len(url_entries)
REPORT: " Targets: {total_targets}"
FOR entry IN url_entries:
REPORT: " • {entry.target}: {entry.url}"
TodoWrite({todos: [
{content: "Initialize and parse url-map", status: "completed", activeForm: "Initializing"},
{content: "MCP batch screenshot capture", status: "pending", activeForm: "Capturing via MCP"},
{content: "Local tool fallback (if needed)", status: "pending", activeForm: "Local fallback"},
{content: "Verify and summarize results", status: "pending", activeForm: "Verifying"}
]})
```
### Phase 1: MCP批量截图优先策略
```bash
REPORT: "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
REPORT: "🚀 Phase 1: MCP Batch Screenshot"
REPORT: "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# 检测MCP工具可用性
mcp_available = check_tool_availability("mcp__browser__screenshot")
success_captures = []
failed_captures = []
IF mcp_available:
REPORT: "✓ MCP browser screenshot tool detected"
# 构建MCP调用参数
urls = [entry.url for entry in url_entries]
file_prefixes = [entry.target for entry in url_entries]
TRY:
# MCP批量截图调用
REPORT: " Calling MCP for {len(urls)} URLs..."
result = mcp__browser__screenshot({
urls: urls,
output_dir: screenshot_dir,
file_prefix: file_prefixes,
full_page: true,
viewport: "1920,1080",
timeout: 30000
})
# 处理MCP返回结果
success_count = len(result.success)
failed_count = len(result.failed)
REPORT: " MCP capture complete: {success_count} succeeded, {failed_count} failed"
FOR item IN result.success:
success_captures.append(item.target)
REPORT: " ✓ {item.target}.png"
FOR item IN result.failed:
failed_captures.append({"target": item.target, "url": item.url, "error": item.error})
REPORT: " ✗ {item.target}: {item.error}"
# 如果有部分失败标记需要fallback
IF failed_count > 0:
failed_targets = [item.target for item in result.failed]
REPORT: " → {failed_count} failed, proceeding to local fallback..."
TodoWrite(mark_completed: "MCP batch screenshot capture", mark_in_progress: "Local tool fallback")
GOTO Phase 2 (fallback_targets = failed_targets)
ELSE:
REPORT: "✅ All screenshots captured via MCP"
TodoWrite(mark_completed: "MCP batch screenshot capture", mark_completed: "Local tool fallback", mark_in_progress: "Verify results")
GOTO Phase 3 (verification)
CATCH error:
REPORT: "⚠️ MCP call failed: {error}"
REPORT: " Falling back to local tools for all targets"
failed_targets = [entry.target for entry in url_entries]
TodoWrite(mark_completed: "MCP batch screenshot capture", mark_in_progress: "Local tool fallback")
GOTO Phase 2 (fallback_targets = failed_targets)
ELSE:
REPORT: " MCP browser screenshot tool not available"
REPORT: " Using local tool fallback strategy"
failed_targets = [entry.target for entry in url_entries]
TodoWrite(mark_completed: "MCP batch screenshot capture", mark_in_progress: "Local tool fallback")
GOTO Phase 2 (fallback_targets = failed_targets)
```
### Phase 2: Local工具降级Playwright → Chrome
```bash
REPORT: "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
REPORT: "🔧 Phase 2: Local Tool Fallback"
REPORT: "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# 仅处理Phase 1失败的targets
targets_to_capture = [entry for entry in url_entries if entry.target IN fallback_targets]
REPORT: "Processing {len(targets_to_capture)} target(s) with local tools..."
# 检测本地工具(检查可执行文件,不触发安装)
playwright_path = Bash(which playwright 2>/dev/null || echo "")
chrome_path = Bash(which google-chrome 2>/dev/null || which chrome 2>/dev/null || which chromium 2>/dev/null || echo "")
playwright_available = playwright_path != ""
chrome_available = chrome_path != ""
REPORT: " Tool availability:"
REPORT: " Playwright: {playwright_available ? '✓ Available' : '✗ Not found'}"
REPORT: " Chrome: {chrome_available ? '✓ Available' : '✗ Not found'}"
local_success = []
local_failed = []
FOR entry IN targets_to_capture:
target = entry.target
url = entry.url
output_file = "{screenshot_dir}/{target}.png"
captured = false
method_used = null
# 尝试Playwright
IF playwright_available AND NOT captured:
TRY:
REPORT: " Trying Playwright for '{target}'..."
Bash({playwright_path} screenshot "{url}" "{output_file}" --full-page --timeout 30000)
IF exists(output_file) AND file_size(output_file) > 1000: # >1KB验证有效
captured = true
method_used = "Playwright"
local_success.append(target)
success_captures.append(target)
REPORT: " ✓ {target}.png (Playwright, {file_size(output_file)/1024:.1f} KB)"
CATCH error:
REPORT: " ⚠️ Playwright failed: {error}"
# 尝试Chrome
IF chrome_available AND NOT captured:
TRY:
REPORT: " Trying Chrome for '{target}'..."
Bash({chrome_path} --headless --disable-gpu --screenshot="{output_file}" --window-size=1920,1080 "{url}")
IF exists(output_file) AND file_size(output_file) > 1000:
captured = true
method_used = "Chrome"
local_success.append(target)
success_captures.append(target)
REPORT: " ✓ {target}.png (Chrome, {file_size(output_file)/1024:.1f} KB)"
CATCH error:
REPORT: " ⚠️ Chrome failed: {error}"
# 标记彻底失败
IF NOT captured:
local_failed.append(entry)
failed_captures.append({"target": target, "url": url, "error": "All local tools failed"})
REPORT: " ✗ {target}: All tools failed"
REPORT: ""
REPORT: "Local fallback summary:"
REPORT: " Succeeded: {len(local_success)}/{len(targets_to_capture)}"
REPORT: " Failed: {len(local_failed)}/{len(targets_to_capture)}"
# 如果仍有失败,进入手动模式
IF len(local_failed) > 0:
TodoWrite(mark_completed: "Local tool fallback", mark_in_progress: "Manual upload mode")
GOTO Phase 2.5 (manual_upload)
ELSE:
TodoWrite(mark_completed: "Local tool fallback", mark_in_progress: "Verify results")
GOTO Phase 3 (verification)
```
### Phase 2.5: 手动上传降级
```bash
REPORT: "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
REPORT: "⚠️ Phase 2.5: Manual Screenshot Required"
REPORT: "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
REPORT: "Failed to auto-capture {len(local_failed)} target(s):"
REPORT: ""
FOR entry IN local_failed:
REPORT: " {entry.target}:"
REPORT: " URL: {entry.url}"
REPORT: " Save to: {screenshot_dir}/{entry.target}.png"
REPORT: ""
REPORT: "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
REPORT: "📋 Manual Steps:"
REPORT: " 1. Visit each URL above in your browser"
REPORT: " 2. Take full-page screenshot (Browser DevTools or extensions)"
REPORT: " 3. Save screenshot to specified path"
REPORT: " 4. Return here and choose an option"
REPORT: ""
REPORT: "Options:"
REPORT: " • Type 'ready' : I've uploaded screenshot(s), continue workflow"
REPORT: " • Type 'skip' : Skip failed screenshots, continue with available"
REPORT: " • Type 'abort' : Cancel entire capture workflow"
REPORT: "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
user_response = WAIT_FOR_USER_INPUT()
MATCH user_response.lower():
"ready" | "done" | "ok" | "continue":
# 验证手动上传的文件
manual_uploaded = []
REPORT: "🔍 Checking for manual screenshots..."
FOR entry IN local_failed:
expected_path = f"{screenshot_dir}/{entry.target}.png"
IF exists(expected_path) AND file_size(expected_path) > 1000:
manual_uploaded.append(entry.target)
success_captures.append(entry.target)
REPORT: " ✓ {entry.target}.png (manual, {file_size(expected_path)/1024:.1f} KB)"
ELSE:
REPORT: " ✗ {entry.target}.png not found or invalid"
IF len(manual_uploaded) > 0:
REPORT: "✅ Detected {len(manual_uploaded)} manual screenshot(s)"
# 移除已上传的targets from failed list
failed_captures = [f for f in failed_captures if f.target NOT IN manual_uploaded]
ELSE:
REPORT: "⚠️ No valid manual screenshots detected"
REPORT: " Proceeding with available screenshots only"
TodoWrite(mark_completed: "Manual upload mode", mark_in_progress: "Verify results")
GOTO Phase 3
"skip" | "s":
REPORT: "⏭️ Skipping {len(local_failed)} failed screenshot(s)"
REPORT: " Proceeding with {len(success_captures)} available screenshot(s)"
TodoWrite(mark_completed: "Manual upload mode", mark_in_progress: "Verify results")
GOTO Phase 3
"abort" | "cancel" | "exit":
ERROR: "Workflow aborted by user"
TodoWrite(mark_failed: "Manual upload mode")
EXIT 1
_:
REPORT: "⚠️ Invalid input '{user_response}', interpreting as 'skip'"
REPORT: " Proceeding with available screenshots"
TodoWrite(mark_completed: "Manual upload mode", mark_in_progress: "Verify results")
GOTO Phase 3
```
### Phase 3: 验证和总结
```bash
REPORT: "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
REPORT: "✅ Phase 3: Verification & Summary"
REPORT: "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# 扫描实际截图文件
captured_files = Glob("{screenshot_dir}/*.{png,jpg,jpeg,webp}")
captured_targets_actual = [extract_basename_without_ext(f) for f in captured_files]
# 与请求对比
total_requested = len(url_entries)
total_captured = len(captured_targets_actual)
missing_targets = [entry.target for entry in url_entries if entry.target NOT IN captured_targets_actual]
REPORT: "📊 Capture Summary:"
REPORT: " Total requested: {total_requested}"
REPORT: " Successfully captured: {total_captured}"
REPORT: " Success rate: {(total_captured / total_requested * 100):.1f}%"
IF missing_targets:
REPORT: ""
REPORT: "⚠️ Missing screenshots ({len(missing_targets)}):"
FOR target IN missing_targets:
REPORT: " • {target}"
ELSE:
REPORT: ""
REPORT: "✅ All requested screenshots captured!"
# 生成capture元数据
metadata = {
"timestamp": current_timestamp(),
"total_requested": total_requested,
"total_captured": total_captured,
"success_rate": round(total_captured / total_requested * 100, 2),
"screenshots": []
}
FOR entry IN url_entries:
target = entry.target
url = entry.url
is_captured = target IN captured_targets_actual
screenshot_info = {
"target": target,
"url": url,
"captured": is_captured
}
IF is_captured:
file_path = f"{screenshot_dir}/{target}.png"
screenshot_info["path"] = file_path
screenshot_info["size_kb"] = round(file_size(file_path) / 1024, 2)
# 查找捕获方法
IF target IN [s.target for s in result.success if mcp_available]:
screenshot_info["method"] = "MCP"
ELSE IF target IN local_success:
screenshot_info["method"] = "Local (Playwright/Chrome)"
ELSE:
screenshot_info["method"] = "Manual"
ELSE:
screenshot_info["path"] = null
screenshot_info["error"] = next((f.error for f in failed_captures if f.target == target), "Unknown error")
metadata.screenshots.append(screenshot_info)
# 写入元数据文件
metadata_path = "{screenshot_dir}/capture-metadata.json"
Write(metadata_path, JSON.stringify(metadata, null, 2))
REPORT: ""
REPORT: "📁 Output:"
REPORT: " Directory: {screenshot_dir}/"
REPORT: " Metadata: capture-metadata.json"
TodoWrite(mark_completed: "Verify and summarize results")
```
### Phase 4: 完成
```javascript
TodoWrite({todos: [
{content: "Initialize and parse url-map", status: "completed", activeForm: "Initializing"},
{content: "MCP batch screenshot capture", status: "completed", activeForm: "MCP capture"},
{content: "Local tool fallback (if needed)", status: "completed", activeForm: "Local fallback"},
{content: "Verify and summarize results", status: "completed", activeForm: "Verifying"}
]});
```
**Completion Message**:
```
✅ Batch Screenshot Capture Complete!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📊 Capture Summary
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Requested: {total_requested} screenshots
Captured: {total_captured} screenshots
Success Rate: {success_rate}%
Capture Methods:
{IF mcp_available AND mcp_success_count > 0:
• MCP: {mcp_success_count} screenshot(s)
}
{IF local_success_count > 0:
• Local tools: {local_success_count} screenshot(s)
}
{IF manual_count > 0:
• Manual upload: {manual_count} screenshot(s)
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📂 Output Structure
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
{screenshot_dir}/
├── {target1}.png ({size1} KB)
├── {target2}.png ({size2} KB)
{FOR each captured screenshot}
└── capture-metadata.json
{IF missing_targets:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠️ Missing Screenshots ({len(missing_targets)})
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
{FOR target IN missing_targets:
• {target} - {get_error_for_target(target)}
}
💡 Tip: Re-run capture command for failed targets:
/workflow:ui-design:capture --base-path "{base_path}" --url-map "{build_failed_url_map()}"
}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🚀 Next Steps
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Extract design style from captured screenshots:
/workflow:ui-design:extract --base-path "{base_path}" --images "{screenshot_dir}/*.png" --mode imitate --variants 1
2. Or continue with full imitate workflow:
(capture is automatically called by /workflow:ui-design:imitate-auto-v3)
```
## MCP API设计假设实现
```typescript
// 假设的MCP工具签名
mcp__browser__screenshot({
urls: string[], // 要截图的URL列表
output_dir: string, // 输出目录
file_prefix: string[], // 文件名前缀列表对应urls
full_page?: boolean, // 全页截图默认true
viewport?: string, // 视口大小(默认"1920,1080"
timeout?: number // 每个URL的超时默认30000ms
}): {
success: Array<{
target: string, // file_prefix对应的target名称
url: string, // 成功截图的URL
path: string // 生成的截图文件路径
}>,
failed: Array<{
target: string, // file_prefix对应的target名称
url: string, // 失败的URL
error: string // 错误信息
}>
}
```
**注意事项**
- 如果`mcp__browser__screenshot`工具不存在,命令会自动降级到本地工具
- MCP工具应该支持并行截图以提高性能
- 返回结果应该区分成功和失败,允许部分失败
## Error Handling
- **无效url-map格式**:清晰的错误信息+格式示例
- **MCP不可用**静默降级到本地工具Playwright/Chrome
- **所有自动工具失败**:进入交互式手动上传模式
- **部分失败**:记录成功项,继续流程(非阻塞),提供重试建议
## Key Features
1. **MCP优先策略** - 使用托管工具提高可靠性和一致性
2. **多级降级机制** - MCP → Playwright → Chrome → 手动上传
3. **批量并行处理** - 一次处理多个URLMCP支持并行
4. **错误容忍设计** - 部分失败不阻塞整体流程
5. **高度可复用** - 可被imitate-auto-v3、explore-auto等工作流调用
6. **结构化输出** - capture-metadata.json记录完整捕获信息
7. **交互式降级** - 手动模式提供清晰的用户指导
8. **智能路径管理** - 支持session集成和standalone模式
## Integration Points
- **Input**: `--url-map` (target:url pairs) + `--base-path` or `--session`
- **Output**: `{base_path}/screenshots/*.png` + `capture-metadata.json`
- **Callers**: `/workflow:ui-design:imitate-auto-v3`, potentially `/workflow:ui-design:explore-auto-v2`
- **Next Command**: `/workflow:ui-design:extract --images "{screenshot_dir}/*.png"`