claude-code-workflow 6.3.9 → 6.3.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/.claude/CLAUDE.md +1 -1
  2. package/.claude/agents/issue-plan-agent.md +21 -15
  3. package/.claude/agents/issue-queue-agent.md +114 -87
  4. package/.claude/commands/issue/discover.md +427 -0
  5. package/.claude/commands/issue/execute.md +195 -363
  6. package/.claude/commands/issue/new.md +13 -1
  7. package/.claude/commands/issue/plan.md +55 -32
  8. package/.claude/commands/issue/queue.md +145 -71
  9. package/.claude/commands/workflow/init.md +75 -29
  10. package/.claude/commands/workflow/lite-fix.md +8 -0
  11. package/.claude/commands/workflow/lite-plan.md +8 -0
  12. package/.claude/commands/workflow/review-module-cycle.md +4 -0
  13. package/.claude/commands/workflow/review-session-cycle.md +4 -0
  14. package/.claude/commands/workflow/review.md +4 -4
  15. package/.claude/commands/workflow/session/solidify.md +299 -0
  16. package/.claude/commands/workflow/session/start.md +10 -7
  17. package/.claude/commands/workflow/tools/context-gather.md +17 -10
  18. package/.claude/skills/software-manual/SKILL.md +184 -0
  19. package/.claude/skills/software-manual/phases/01-requirements-discovery.md +162 -0
  20. package/.claude/skills/software-manual/phases/02-project-exploration.md +101 -0
  21. package/.claude/skills/software-manual/phases/02.5-api-extraction.md +161 -0
  22. package/.claude/skills/software-manual/phases/03-parallel-analysis.md +183 -0
  23. package/.claude/skills/software-manual/phases/03.5-consolidation.md +82 -0
  24. package/.claude/skills/software-manual/phases/04-screenshot-capture.md +89 -0
  25. package/.claude/skills/software-manual/phases/05-html-assembly.md +132 -0
  26. package/.claude/skills/software-manual/phases/06-iterative-refinement.md +259 -0
  27. package/.claude/skills/software-manual/scripts/api-extractor.md +245 -0
  28. package/.claude/skills/software-manual/scripts/bundle-libraries.md +85 -0
  29. package/.claude/skills/software-manual/scripts/extract_apis.py +270 -0
  30. package/.claude/skills/software-manual/scripts/screenshot-helper.md +447 -0
  31. package/.claude/skills/software-manual/scripts/swagger-runner.md +419 -0
  32. package/.claude/skills/software-manual/scripts/typedoc-runner.md +357 -0
  33. package/.claude/skills/software-manual/specs/html-template.md +325 -0
  34. package/.claude/skills/software-manual/specs/quality-standards.md +253 -0
  35. package/.claude/skills/software-manual/specs/writing-style.md +298 -0
  36. package/.claude/skills/software-manual/templates/css/wiki-base.css +788 -0
  37. package/.claude/skills/software-manual/templates/css/wiki-dark.css +278 -0
  38. package/.claude/skills/software-manual/templates/tiddlywiki-shell.html +327 -0
  39. package/.claude/workflows/cli-templates/schemas/discovery-finding-schema.json +219 -0
  40. package/.claude/workflows/cli-templates/schemas/discovery-state-schema.json +125 -0
  41. package/.claude/workflows/cli-templates/schemas/issues-jsonl-schema.json +168 -74
  42. package/.claude/workflows/cli-templates/schemas/queue-schema.json +225 -108
  43. package/.claude/workflows/cli-templates/schemas/solution-schema.json +6 -28
  44. package/.claude/workflows/context-tools.md +17 -25
  45. package/.codex/AGENTS.md +10 -5
  46. package/.codex/prompts/issue-execute.md +174 -84
  47. package/.codex/prompts/issue-plan.md +106 -0
  48. package/.codex/prompts/issue-queue.md +225 -0
  49. package/ccw/dist/cli.d.ts.map +1 -1
  50. package/ccw/dist/cli.js +1 -0
  51. package/ccw/dist/cli.js.map +1 -1
  52. package/ccw/dist/commands/issue.d.ts.map +1 -1
  53. package/ccw/dist/commands/issue.js +443 -123
  54. package/ccw/dist/commands/issue.js.map +1 -1
  55. package/ccw/dist/core/dashboard-generator.d.ts.map +1 -1
  56. package/ccw/dist/core/dashboard-generator.js +4 -1
  57. package/ccw/dist/core/dashboard-generator.js.map +1 -1
  58. package/ccw/dist/core/data-aggregator.d.ts +32 -0
  59. package/ccw/dist/core/data-aggregator.d.ts.map +1 -1
  60. package/ccw/dist/core/data-aggregator.js +55 -11
  61. package/ccw/dist/core/data-aggregator.js.map +1 -1
  62. package/ccw/dist/core/routes/discovery-routes.d.ts +37 -0
  63. package/ccw/dist/core/routes/discovery-routes.d.ts.map +1 -0
  64. package/ccw/dist/core/routes/discovery-routes.js +514 -0
  65. package/ccw/dist/core/routes/discovery-routes.js.map +1 -0
  66. package/ccw/dist/core/server.d.ts.map +1 -1
  67. package/ccw/dist/core/server.js +9 -1
  68. package/ccw/dist/core/server.js.map +1 -1
  69. package/ccw/dist/tools/codex-lens.d.ts +12 -1
  70. package/ccw/dist/tools/codex-lens.d.ts.map +1 -1
  71. package/ccw/dist/tools/codex-lens.js +56 -7
  72. package/ccw/dist/tools/codex-lens.js.map +1 -1
  73. package/ccw/src/cli.ts +1 -0
  74. package/ccw/src/commands/issue.ts +498 -158
  75. package/ccw/src/core/dashboard-generator.ts +4 -1
  76. package/ccw/src/core/data-aggregator.ts +94 -11
  77. package/ccw/src/core/routes/discovery-routes.ts +607 -0
  78. package/ccw/src/core/server.ts +9 -1
  79. package/ccw/src/templates/dashboard-css/34-discovery.css +783 -0
  80. package/ccw/src/templates/dashboard-js/components/cli-status.js +1 -78
  81. package/ccw/src/templates/dashboard-js/components/navigation.js +8 -0
  82. package/ccw/src/templates/dashboard-js/i18n.js +140 -4
  83. package/ccw/src/templates/dashboard-js/views/cli-manager.js +0 -18
  84. package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +13 -3
  85. package/ccw/src/templates/dashboard-js/views/issue-discovery.js +730 -0
  86. package/ccw/src/templates/dashboard-js/views/issue-manager.js +57 -26
  87. package/ccw/src/templates/dashboard-js/views/project-overview.js +153 -0
  88. package/ccw/src/templates/dashboard.html +5 -0
  89. package/ccw/src/tools/codex-lens.ts +75 -9
  90. package/package.json +1 -1
  91. package/.claude/workflows/context-tools-ace.md +0 -105
@@ -0,0 +1,270 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ API 文档提取脚本
4
+ 支持 FastAPI、TypeScript、Python 模块
5
+ """
6
+
7
+ import subprocess
8
+ import sys
9
+ import json
10
+ from pathlib import Path
11
+ from typing import Dict, Any, Optional
12
+
13
+ # 项目配置
14
+ PROJECTS = {
15
+ 'backend': {
16
+ 'path': Path('D:/dongdiankaifa9/backend'),
17
+ 'type': 'fastapi',
18
+ 'entry': 'app.main:app',
19
+ 'output': 'api-docs/backend'
20
+ },
21
+ 'frontend': {
22
+ 'path': Path('D:/dongdiankaifa9/frontend'),
23
+ 'type': 'typescript',
24
+ 'entries': ['lib', 'hooks', 'components'],
25
+ 'output': 'api-docs/frontend'
26
+ },
27
+ 'hydro_generator_module': {
28
+ 'path': Path('D:/dongdiankaifa9/hydro_generator_module'),
29
+ 'type': 'python',
30
+ 'output': 'api-docs/hydro_generator'
31
+ },
32
+ 'multiphysics_network': {
33
+ 'path': Path('D:/dongdiankaifa9/multiphysics_network'),
34
+ 'type': 'python',
35
+ 'output': 'api-docs/multiphysics'
36
+ }
37
+ }
38
+
39
+
40
+ def extract_fastapi(name: str, config: Dict[str, Any], output_base: Path) -> bool:
41
+ """提取 FastAPI OpenAPI 文档"""
42
+ path = config['path']
43
+ output_dir = output_base / config['output']
44
+ output_dir.mkdir(parents=True, exist_ok=True)
45
+
46
+ # 添加路径到 sys.path
47
+ if str(path) not in sys.path:
48
+ sys.path.insert(0, str(path))
49
+
50
+ try:
51
+ # 动态导入 app
52
+ from app.main import app
53
+
54
+ # 获取 OpenAPI schema
55
+ openapi_schema = app.openapi()
56
+
57
+ # 保存 JSON
58
+ json_path = output_dir / 'openapi.json'
59
+ with open(json_path, 'w', encoding='utf-8') as f:
60
+ json.dump(openapi_schema, f, indent=2, ensure_ascii=False)
61
+
62
+ # 生成 Markdown 摘要
63
+ md_path = output_dir / 'API_SUMMARY.md'
64
+ generate_api_markdown(openapi_schema, md_path)
65
+
66
+ endpoints = len(openapi_schema.get('paths', {}))
67
+ print(f" ✓ Extracted {endpoints} endpoints → {output_dir}")
68
+ return True
69
+
70
+ except ImportError as e:
71
+ print(f" ✗ Import error: {e}")
72
+ return False
73
+ except Exception as e:
74
+ print(f" ✗ Error: {e}")
75
+ return False
76
+
77
+
78
+ def generate_api_markdown(schema: Dict, output_path: Path):
79
+ """从 OpenAPI schema 生成 Markdown"""
80
+ lines = [
81
+ f"# {schema.get('info', {}).get('title', 'API Reference')}",
82
+ "",
83
+ f"Version: {schema.get('info', {}).get('version', '1.0.0')}",
84
+ "",
85
+ "## Endpoints",
86
+ "",
87
+ "| Method | Path | Summary |",
88
+ "|--------|------|---------|"
89
+ ]
90
+
91
+ for path, methods in schema.get('paths', {}).items():
92
+ for method, details in methods.items():
93
+ if method in ('get', 'post', 'put', 'delete', 'patch'):
94
+ summary = details.get('summary', details.get('operationId', '-'))
95
+ lines.append(f"| `{method.upper()}` | `{path}` | {summary} |")
96
+
97
+ lines.extend([
98
+ "",
99
+ "## Schemas",
100
+ ""
101
+ ])
102
+
103
+ for name, schema_def in schema.get('components', {}).get('schemas', {}).items():
104
+ lines.append(f"### {name}")
105
+ lines.append("")
106
+ if 'properties' in schema_def:
107
+ lines.append("| Property | Type | Required |")
108
+ lines.append("|----------|------|----------|")
109
+ required = schema_def.get('required', [])
110
+ for prop, prop_def in schema_def['properties'].items():
111
+ prop_type = prop_def.get('type', prop_def.get('$ref', 'any'))
112
+ is_required = '✓' if prop in required else ''
113
+ lines.append(f"| `{prop}` | {prop_type} | {is_required} |")
114
+ lines.append("")
115
+
116
+ with open(output_path, 'w', encoding='utf-8') as f:
117
+ f.write('\n'.join(lines))
118
+
119
+
120
+ def extract_typescript(name: str, config: Dict[str, Any], output_base: Path) -> bool:
121
+ """提取 TypeScript 文档 (TypeDoc)"""
122
+ path = config['path']
123
+ output_dir = output_base / config['output']
124
+
125
+ # 检查 TypeDoc 是否已安装
126
+ try:
127
+ result = subprocess.run(
128
+ ['npx', 'typedoc', '--version'],
129
+ cwd=path,
130
+ capture_output=True,
131
+ text=True
132
+ )
133
+ if result.returncode != 0:
134
+ print(f" ⚠ TypeDoc not installed, installing...")
135
+ subprocess.run(
136
+ ['npm', 'install', '--save-dev', 'typedoc', 'typedoc-plugin-markdown'],
137
+ cwd=path,
138
+ check=True
139
+ )
140
+ except FileNotFoundError:
141
+ print(f" ✗ npm/npx not found")
142
+ return False
143
+
144
+ # 运行 TypeDoc
145
+ try:
146
+ entries = config.get('entries', ['lib'])
147
+ cmd = [
148
+ 'npx', 'typedoc',
149
+ '--plugin', 'typedoc-plugin-markdown',
150
+ '--out', str(output_dir),
151
+ '--entryPointStrategy', 'expand',
152
+ '--exclude', '**/node_modules/**',
153
+ '--exclude', '**/*.test.*',
154
+ '--readme', 'none'
155
+ ]
156
+ for entry in entries:
157
+ entry_path = path / entry
158
+ if entry_path.exists():
159
+ cmd.extend(['--entryPoints', str(entry_path)])
160
+
161
+ result = subprocess.run(cmd, cwd=path, capture_output=True, text=True)
162
+
163
+ if result.returncode == 0:
164
+ print(f" ✓ TypeDoc generated → {output_dir}")
165
+ return True
166
+ else:
167
+ print(f" ✗ TypeDoc error: {result.stderr[:200]}")
168
+ return False
169
+
170
+ except Exception as e:
171
+ print(f" ✗ Error: {e}")
172
+ return False
173
+
174
+
175
+ def extract_python_module(name: str, config: Dict[str, Any], output_base: Path) -> bool:
176
+ """提取 Python 模块文档 (pdoc)"""
177
+ path = config['path']
178
+ output_dir = output_base / config['output']
179
+ module_name = path.name
180
+
181
+ # 检查 pdoc
182
+ try:
183
+ subprocess.run(['pdoc', '--version'], capture_output=True, check=True)
184
+ except (FileNotFoundError, subprocess.CalledProcessError):
185
+ print(f" ⚠ pdoc not installed, installing...")
186
+ subprocess.run([sys.executable, '-m', 'pip', 'install', 'pdoc'], check=True)
187
+
188
+ # 运行 pdoc
189
+ try:
190
+ result = subprocess.run(
191
+ [
192
+ 'pdoc', module_name,
193
+ '--output-dir', str(output_dir),
194
+ '--format', 'markdown'
195
+ ],
196
+ cwd=path.parent,
197
+ capture_output=True,
198
+ text=True
199
+ )
200
+
201
+ if result.returncode == 0:
202
+ # 统计生成的文件
203
+ md_files = list(output_dir.glob('**/*.md'))
204
+ print(f" ✓ pdoc generated {len(md_files)} files → {output_dir}")
205
+ return True
206
+ else:
207
+ print(f" ✗ pdoc error: {result.stderr[:200]}")
208
+ return False
209
+
210
+ except Exception as e:
211
+ print(f" ✗ Error: {e}")
212
+ return False
213
+
214
+
215
+ EXTRACTORS = {
216
+ 'fastapi': extract_fastapi,
217
+ 'typescript': extract_typescript,
218
+ 'python': extract_python_module
219
+ }
220
+
221
+
222
+ def main(output_base: Optional[str] = None, projects: Optional[list] = None):
223
+ """主入口"""
224
+ base = Path(output_base) if output_base else Path.cwd()
225
+
226
+ print("=" * 50)
227
+ print("API Documentation Extraction")
228
+ print("=" * 50)
229
+
230
+ results = {}
231
+
232
+ for name, config in PROJECTS.items():
233
+ if projects and name not in projects:
234
+ continue
235
+
236
+ print(f"\n[{name}] ({config['type']})")
237
+
238
+ if not config['path'].exists():
239
+ print(f" ✗ Path not found: {config['path']}")
240
+ results[name] = False
241
+ continue
242
+
243
+ extractor = EXTRACTORS.get(config['type'])
244
+ if extractor:
245
+ results[name] = extractor(name, config, base)
246
+ else:
247
+ print(f" ✗ Unknown type: {config['type']}")
248
+ results[name] = False
249
+
250
+ # 汇总
251
+ print("\n" + "=" * 50)
252
+ print("Summary")
253
+ print("=" * 50)
254
+ success = sum(1 for v in results.values() if v)
255
+ print(f"Success: {success}/{len(results)}")
256
+
257
+ return all(results.values())
258
+
259
+
260
+ if __name__ == '__main__':
261
+ import argparse
262
+
263
+ parser = argparse.ArgumentParser(description='Extract API documentation')
264
+ parser.add_argument('--output', '-o', default='.', help='Output base directory')
265
+ parser.add_argument('--projects', '-p', nargs='+', help='Specific projects to extract')
266
+
267
+ args = parser.parse_args()
268
+
269
+ success = main(args.output, args.projects)
270
+ sys.exit(0 if success else 1)
@@ -0,0 +1,447 @@
1
+ # Screenshot Helper
2
+
3
+ Guide for capturing screenshots using Chrome MCP.
4
+
5
+ ## Overview
6
+
7
+ This script helps capture screenshots of web interfaces for the software manual using Chrome MCP or fallback methods.
8
+
9
+ ## Chrome MCP Prerequisites
10
+
11
+ ### Check MCP Availability
12
+
13
+ ```javascript
14
+ async function checkChromeMCPAvailability() {
15
+ try {
16
+ // Attempt to get Chrome version via MCP
17
+ const version = await mcp__chrome__getVersion();
18
+ return {
19
+ available: true,
20
+ browser: version.browser,
21
+ version: version.version
22
+ };
23
+ } catch (error) {
24
+ return {
25
+ available: false,
26
+ error: error.message
27
+ };
28
+ }
29
+ }
30
+ ```
31
+
32
+ ### MCP Configuration
33
+
34
+ Expected Claude configuration for Chrome MCP:
35
+
36
+ ```json
37
+ {
38
+ "mcpServers": {
39
+ "chrome": {
40
+ "command": "npx",
41
+ "args": ["@anthropic-ai/mcp-chrome"],
42
+ "env": {
43
+ "CHROME_PATH": "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"
44
+ }
45
+ }
46
+ }
47
+ }
48
+ ```
49
+
50
+ ## Screenshot Workflow
51
+
52
+ ### Step 1: Prepare Environment
53
+
54
+ ```javascript
55
+ async function prepareScreenshotEnvironment(workDir, config) {
56
+ const screenshotDir = `${workDir}/screenshots`;
57
+
58
+ // Create directory
59
+ Bash({ command: `mkdir -p "${screenshotDir}"` });
60
+
61
+ // Check Chrome MCP
62
+ const chromeMCP = await checkChromeMCPAvailability();
63
+
64
+ if (!chromeMCP.available) {
65
+ console.log('Chrome MCP not available. Will generate manual guide.');
66
+ return { mode: 'manual' };
67
+ }
68
+
69
+ // Start development server if needed
70
+ if (config.screenshot_config?.dev_command) {
71
+ const server = await startDevServer(config);
72
+ return { mode: 'auto', server, screenshotDir };
73
+ }
74
+
75
+ return { mode: 'auto', screenshotDir };
76
+ }
77
+ ```
78
+
79
+ ### Step 2: Start Development Server
80
+
81
+ ```javascript
82
+ async function startDevServer(config) {
83
+ const devCommand = config.screenshot_config.dev_command;
84
+ const devUrl = config.screenshot_config.dev_url;
85
+
86
+ // Start server in background
87
+ const server = Bash({
88
+ command: devCommand,
89
+ run_in_background: true
90
+ });
91
+
92
+ console.log(`Starting dev server: ${devCommand}`);
93
+
94
+ // Wait for server to be ready
95
+ const ready = await waitForServer(devUrl, 30000);
96
+
97
+ if (!ready) {
98
+ throw new Error(`Server at ${devUrl} did not start in time`);
99
+ }
100
+
101
+ console.log(`Dev server ready at ${devUrl}`);
102
+
103
+ return server;
104
+ }
105
+
106
+ async function waitForServer(url, timeout = 30000) {
107
+ const start = Date.now();
108
+
109
+ while (Date.now() - start < timeout) {
110
+ try {
111
+ const response = await fetch(url, { method: 'HEAD' });
112
+ if (response.ok) return true;
113
+ } catch (e) {
114
+ // Server not ready
115
+ }
116
+ await sleep(1000);
117
+ }
118
+
119
+ return false;
120
+ }
121
+ ```
122
+
123
+ ### Step 3: Capture Screenshots
124
+
125
+ ```javascript
126
+ async function captureScreenshots(screenshots, config, workDir) {
127
+ const results = {
128
+ captured: [],
129
+ failed: []
130
+ };
131
+
132
+ const devUrl = config.screenshot_config.dev_url;
133
+ const screenshotDir = `${workDir}/screenshots`;
134
+
135
+ for (const ss of screenshots) {
136
+ try {
137
+ // Build full URL
138
+ const fullUrl = new URL(ss.url, devUrl).href;
139
+
140
+ console.log(`Capturing: ${ss.id} (${fullUrl})`);
141
+
142
+ // Configure capture options
143
+ const options = {
144
+ url: fullUrl,
145
+ viewport: { width: 1280, height: 800 },
146
+ fullPage: ss.fullPage || false
147
+ };
148
+
149
+ // Wait for specific element if specified
150
+ if (ss.wait_for) {
151
+ options.waitFor = ss.wait_for;
152
+ }
153
+
154
+ // Capture specific element if selector provided
155
+ if (ss.selector) {
156
+ options.selector = ss.selector;
157
+ }
158
+
159
+ // Add delay for animations
160
+ await sleep(500);
161
+
162
+ // Capture via Chrome MCP
163
+ const result = await mcp__chrome__screenshot(options);
164
+
165
+ // Save as PNG
166
+ const filename = `${ss.id}.png`;
167
+ Write(`${screenshotDir}/${filename}`, result.data, { encoding: 'base64' });
168
+
169
+ results.captured.push({
170
+ id: ss.id,
171
+ file: filename,
172
+ url: ss.url,
173
+ description: ss.description,
174
+ size: result.data.length
175
+ });
176
+
177
+ } catch (error) {
178
+ console.error(`Failed to capture ${ss.id}:`, error.message);
179
+ results.failed.push({
180
+ id: ss.id,
181
+ url: ss.url,
182
+ error: error.message
183
+ });
184
+ }
185
+ }
186
+
187
+ return results;
188
+ }
189
+ ```
190
+
191
+ ### Step 4: Generate Manifest
192
+
193
+ ```javascript
194
+ function generateScreenshotManifest(results, workDir) {
195
+ const manifest = {
196
+ generated: new Date().toISOString(),
197
+ total: results.captured.length + results.failed.length,
198
+ captured: results.captured.length,
199
+ failed: results.failed.length,
200
+ screenshots: results.captured,
201
+ failures: results.failed
202
+ };
203
+
204
+ Write(`${workDir}/screenshots/screenshots-manifest.json`,
205
+ JSON.stringify(manifest, null, 2));
206
+
207
+ return manifest;
208
+ }
209
+ ```
210
+
211
+ ### Step 5: Cleanup
212
+
213
+ ```javascript
214
+ async function cleanupScreenshotEnvironment(env) {
215
+ if (env.server) {
216
+ console.log('Stopping dev server...');
217
+ KillShell({ shell_id: env.server.task_id });
218
+ }
219
+ }
220
+ ```
221
+
222
+ ## Main Runner
223
+
224
+ ```javascript
225
+ async function runScreenshotCapture(workDir, screenshots) {
226
+ const config = JSON.parse(Read(`${workDir}/manual-config.json`));
227
+
228
+ // Prepare environment
229
+ const env = await prepareScreenshotEnvironment(workDir, config);
230
+
231
+ if (env.mode === 'manual') {
232
+ // Generate manual capture guide
233
+ generateManualCaptureGuide(screenshots, workDir);
234
+ return { success: false, mode: 'manual' };
235
+ }
236
+
237
+ try {
238
+ // Capture screenshots
239
+ const results = await captureScreenshots(screenshots, config, workDir);
240
+
241
+ // Generate manifest
242
+ const manifest = generateScreenshotManifest(results, workDir);
243
+
244
+ // Generate manual guide for failed captures
245
+ if (results.failed.length > 0) {
246
+ generateManualCaptureGuide(results.failed, workDir);
247
+ }
248
+
249
+ return {
250
+ success: true,
251
+ captured: results.captured.length,
252
+ failed: results.failed.length,
253
+ manifest
254
+ };
255
+
256
+ } finally {
257
+ // Cleanup
258
+ await cleanupScreenshotEnvironment(env);
259
+ }
260
+ }
261
+ ```
262
+
263
+ ## Manual Capture Fallback
264
+
265
+ When Chrome MCP is unavailable:
266
+
267
+ ```javascript
268
+ function generateManualCaptureGuide(screenshots, workDir) {
269
+ const guide = `
270
+ # Manual Screenshot Capture Guide
271
+
272
+ Chrome MCP is not available. Please capture screenshots manually.
273
+
274
+ ## Prerequisites
275
+
276
+ 1. Start your development server
277
+ 2. Open a browser
278
+ 3. Use a screenshot tool (Snipping Tool, Screenshot, etc.)
279
+
280
+ ## Screenshots Required
281
+
282
+ ${screenshots.map((ss, i) => `
283
+ ### ${i + 1}. ${ss.id}
284
+
285
+ - **URL**: ${ss.url}
286
+ - **Description**: ${ss.description}
287
+ - **Save as**: \`screenshots/${ss.id}.png\`
288
+ ${ss.selector ? `- **Capture area**: \`${ss.selector}\` element only` : '- **Type**: Full page or viewport'}
289
+ ${ss.wait_for ? `- **Wait for**: \`${ss.wait_for}\` to be visible` : ''}
290
+
291
+ **Steps:**
292
+ 1. Navigate to ${ss.url}
293
+ ${ss.wait_for ? `2. Wait for ${ss.wait_for} to appear` : ''}
294
+ ${ss.selector ? `2. Capture only the ${ss.selector} area` : '2. Capture the full viewport'}
295
+ 3. Save as \`${ss.id}.png\`
296
+ `).join('\n')}
297
+
298
+ ## After Capturing
299
+
300
+ 1. Place all PNG files in the \`screenshots/\` directory
301
+ 2. Ensure filenames match exactly (case-sensitive)
302
+ 3. Run Phase 5 (HTML Assembly) to continue
303
+
304
+ ## Screenshot Specifications
305
+
306
+ - **Format**: PNG
307
+ - **Width**: 1280px recommended
308
+ - **Quality**: High
309
+ - **Annotations**: None (add in post-processing if needed)
310
+ `;
311
+
312
+ Write(`${workDir}/screenshots/MANUAL_CAPTURE.md`, guide);
313
+ }
314
+ ```
315
+
316
+ ## Advanced Options
317
+
318
+ ### Viewport Sizes
319
+
320
+ ```javascript
321
+ const viewportPresets = {
322
+ desktop: { width: 1280, height: 800 },
323
+ tablet: { width: 768, height: 1024 },
324
+ mobile: { width: 375, height: 667 },
325
+ wide: { width: 1920, height: 1080 }
326
+ };
327
+
328
+ async function captureResponsive(ss, config, workDir) {
329
+ const results = [];
330
+
331
+ for (const [name, viewport] of Object.entries(viewportPresets)) {
332
+ const result = await mcp__chrome__screenshot({
333
+ url: ss.url,
334
+ viewport
335
+ });
336
+
337
+ const filename = `${ss.id}-${name}.png`;
338
+ Write(`${workDir}/screenshots/${filename}`, result.data, { encoding: 'base64' });
339
+
340
+ results.push({ viewport: name, file: filename });
341
+ }
342
+
343
+ return results;
344
+ }
345
+ ```
346
+
347
+ ### Before/After Comparisons
348
+
349
+ ```javascript
350
+ async function captureInteraction(ss, config, workDir) {
351
+ const baseUrl = config.screenshot_config.dev_url;
352
+ const fullUrl = new URL(ss.url, baseUrl).href;
353
+
354
+ // Capture before state
355
+ const before = await mcp__chrome__screenshot({
356
+ url: fullUrl,
357
+ viewport: { width: 1280, height: 800 }
358
+ });
359
+ Write(`${workDir}/screenshots/${ss.id}-before.png`, before.data, { encoding: 'base64' });
360
+
361
+ // Perform interaction (click, type, etc.)
362
+ if (ss.interaction) {
363
+ await mcp__chrome__click({ selector: ss.interaction.click });
364
+ await sleep(500);
365
+ }
366
+
367
+ // Capture after state
368
+ const after = await mcp__chrome__screenshot({
369
+ url: fullUrl,
370
+ viewport: { width: 1280, height: 800 }
371
+ });
372
+ Write(`${workDir}/screenshots/${ss.id}-after.png`, after.data, { encoding: 'base64' });
373
+
374
+ return {
375
+ before: `${ss.id}-before.png`,
376
+ after: `${ss.id}-after.png`
377
+ };
378
+ }
379
+ ```
380
+
381
+ ### Screenshot Annotation
382
+
383
+ ```javascript
384
+ function generateAnnotationGuide(screenshots, workDir) {
385
+ const guide = `
386
+ # Screenshot Annotation Guide
387
+
388
+ For screenshots requiring callouts or highlights:
389
+
390
+ ## Tools
391
+ - macOS: Preview, Skitch
392
+ - Windows: Snipping Tool, ShareX
393
+ - Cross-platform: Greenshot, Lightshot
394
+
395
+ ## Annotation Guidelines
396
+
397
+ 1. **Callouts**: Use numbered circles (1, 2, 3)
398
+ 2. **Highlights**: Use semi-transparent rectangles
399
+ 3. **Arrows**: Point from text to element
400
+ 4. **Text**: Use sans-serif font, 12-14pt
401
+
402
+ ## Color Scheme
403
+
404
+ - Primary: #0d6efd (blue)
405
+ - Secondary: #6c757d (gray)
406
+ - Success: #198754 (green)
407
+ - Warning: #ffc107 (yellow)
408
+ - Danger: #dc3545 (red)
409
+
410
+ ## Screenshots Needing Annotation
411
+
412
+ ${screenshots.filter(s => s.annotate).map(ss => `
413
+ - **${ss.id}**: ${ss.description}
414
+ - Highlight: ${ss.annotate.highlight || 'N/A'}
415
+ - Callouts: ${ss.annotate.callouts?.join(', ') || 'N/A'}
416
+ `).join('\n')}
417
+ `;
418
+
419
+ Write(`${workDir}/screenshots/ANNOTATION_GUIDE.md`, guide);
420
+ }
421
+ ```
422
+
423
+ ## Troubleshooting
424
+
425
+ ### Chrome MCP Not Found
426
+
427
+ 1. Check Claude MCP configuration
428
+ 2. Verify Chrome is installed
429
+ 3. Check CHROME_PATH environment variable
430
+
431
+ ### Screenshots Are Blank
432
+
433
+ 1. Increase wait time before capture
434
+ 2. Check if page requires authentication
435
+ 3. Verify URL is correct
436
+
437
+ ### Elements Not Visible
438
+
439
+ 1. Scroll element into view
440
+ 2. Expand collapsed sections
441
+ 3. Wait for animations to complete
442
+
443
+ ### Server Not Starting
444
+
445
+ 1. Check if port is already in use
446
+ 2. Verify dev command is correct
447
+ 3. Check for startup errors in logs