real-prototypes-skill 0.1.0

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 (60) hide show
  1. package/.claude/skills/agent-browser-skill/SKILL.md +252 -0
  2. package/.claude/skills/real-prototypes-skill/.gitignore +188 -0
  3. package/.claude/skills/real-prototypes-skill/ACCESSIBILITY.md +668 -0
  4. package/.claude/skills/real-prototypes-skill/INSTALL.md +259 -0
  5. package/.claude/skills/real-prototypes-skill/LICENSE +21 -0
  6. package/.claude/skills/real-prototypes-skill/PUBLISH.md +310 -0
  7. package/.claude/skills/real-prototypes-skill/QUICKSTART.md +240 -0
  8. package/.claude/skills/real-prototypes-skill/README.md +442 -0
  9. package/.claude/skills/real-prototypes-skill/SKILL.md +375 -0
  10. package/.claude/skills/real-prototypes-skill/capture/capture-engine.js +1153 -0
  11. package/.claude/skills/real-prototypes-skill/capture/config.schema.json +170 -0
  12. package/.claude/skills/real-prototypes-skill/cli.js +596 -0
  13. package/.claude/skills/real-prototypes-skill/docs/TROUBLESHOOTING.md +278 -0
  14. package/.claude/skills/real-prototypes-skill/docs/schemas/capture-config.md +167 -0
  15. package/.claude/skills/real-prototypes-skill/docs/schemas/design-tokens.md +183 -0
  16. package/.claude/skills/real-prototypes-skill/docs/schemas/manifest.md +169 -0
  17. package/.claude/skills/real-prototypes-skill/examples/CLAUDE.md.example +73 -0
  18. package/.claude/skills/real-prototypes-skill/examples/amazon-chatbot/CLAUDE.md +136 -0
  19. package/.claude/skills/real-prototypes-skill/examples/amazon-chatbot/FEATURES.md +222 -0
  20. package/.claude/skills/real-prototypes-skill/examples/amazon-chatbot/README.md +82 -0
  21. package/.claude/skills/real-prototypes-skill/examples/amazon-chatbot/references/design-tokens.json +87 -0
  22. package/.claude/skills/real-prototypes-skill/examples/amazon-chatbot/references/screenshots/homepage-viewport.png +0 -0
  23. package/.claude/skills/real-prototypes-skill/examples/amazon-chatbot/references/screenshots/prototype-chatbot-final.png +0 -0
  24. package/.claude/skills/real-prototypes-skill/examples/amazon-chatbot/references/screenshots/prototype-fullpage-v2.png +0 -0
  25. package/.claude/skills/real-prototypes-skill/references/accessibility-fixes.md +298 -0
  26. package/.claude/skills/real-prototypes-skill/references/accessibility-report.json +253 -0
  27. package/.claude/skills/real-prototypes-skill/scripts/CAPTURE-ENHANCEMENTS.md +344 -0
  28. package/.claude/skills/real-prototypes-skill/scripts/IMPLEMENTATION-SUMMARY.md +517 -0
  29. package/.claude/skills/real-prototypes-skill/scripts/QUICK-START.md +229 -0
  30. package/.claude/skills/real-prototypes-skill/scripts/QUICKSTART-layout-analysis.md +148 -0
  31. package/.claude/skills/real-prototypes-skill/scripts/README-analyze-layout.md +407 -0
  32. package/.claude/skills/real-prototypes-skill/scripts/analyze-layout.js +880 -0
  33. package/.claude/skills/real-prototypes-skill/scripts/capture-platform.js +203 -0
  34. package/.claude/skills/real-prototypes-skill/scripts/comprehensive-capture.js +597 -0
  35. package/.claude/skills/real-prototypes-skill/scripts/create-manifest.js +338 -0
  36. package/.claude/skills/real-prototypes-skill/scripts/enterprise-pipeline.js +428 -0
  37. package/.claude/skills/real-prototypes-skill/scripts/extract-tokens.js +468 -0
  38. package/.claude/skills/real-prototypes-skill/scripts/full-site-capture.js +738 -0
  39. package/.claude/skills/real-prototypes-skill/scripts/generate-tailwind-config.js +296 -0
  40. package/.claude/skills/real-prototypes-skill/scripts/integrate-accessibility.sh +161 -0
  41. package/.claude/skills/real-prototypes-skill/scripts/manifest-schema.json +302 -0
  42. package/.claude/skills/real-prototypes-skill/scripts/setup-prototype.sh +167 -0
  43. package/.claude/skills/real-prototypes-skill/scripts/test-analyze-layout.js +338 -0
  44. package/.claude/skills/real-prototypes-skill/scripts/test-validation.js +307 -0
  45. package/.claude/skills/real-prototypes-skill/scripts/validate-accessibility.js +598 -0
  46. package/.claude/skills/real-prototypes-skill/scripts/validate-manifest.js +499 -0
  47. package/.claude/skills/real-prototypes-skill/scripts/validate-output.js +361 -0
  48. package/.claude/skills/real-prototypes-skill/scripts/validate-prerequisites.js +319 -0
  49. package/.claude/skills/real-prototypes-skill/scripts/verify-layout-analysis.sh +77 -0
  50. package/.claude/skills/real-prototypes-skill/templates/dashboard-widget.tsx.template +91 -0
  51. package/.claude/skills/real-prototypes-skill/templates/data-table.tsx.template +193 -0
  52. package/.claude/skills/real-prototypes-skill/templates/form-section.tsx.template +250 -0
  53. package/.claude/skills/real-prototypes-skill/templates/modal-dialog.tsx.template +239 -0
  54. package/.claude/skills/real-prototypes-skill/templates/nav-item.tsx.template +265 -0
  55. package/.claude/skills/real-prototypes-skill/validation/validation-engine.js +559 -0
  56. package/.env.example +74 -0
  57. package/LICENSE +21 -0
  58. package/README.md +444 -0
  59. package/bin/cli.js +319 -0
  60. package/package.json +59 -0
@@ -0,0 +1,738 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Full Site Capture Script - Enhanced with Robust Error Handling
5
+ *
6
+ * Automatically discovers and captures all pages of a platform with:
7
+ * - Wait for networkidle0 (all network requests complete)
8
+ * - Pre-screenshot validation (status codes, page load, element checks)
9
+ * - Retry logic with exponential backoff
10
+ * - Comprehensive error logging
11
+ * - Success validation (file sizes, dimensions)
12
+ *
13
+ * Usage:
14
+ * node full-site-capture.js [claude-md-path] [output-dir]
15
+ *
16
+ * What it does:
17
+ * 1. Reads credentials from CLAUDE.md
18
+ * 2. Logs into the platform
19
+ * 3. Crawls to discover all internal pages
20
+ * 4. Captures screenshot + HTML for each page (with validation)
21
+ * 5. Extracts design tokens
22
+ * 6. Generates manifest.json
23
+ * 7. Creates error log for any failures
24
+ *
25
+ * Output: Generates agent-browser commands for the full capture workflow
26
+ */
27
+
28
+ const fs = require('fs');
29
+ const path = require('path');
30
+
31
+ // Default configuration
32
+ const DEFAULT_CONFIG = {
33
+ maxPages: 50,
34
+ viewportWidth: 1920,
35
+ viewportHeight: 1080,
36
+ waitAfterLoad: 5000, // Increased default to 5s
37
+ maxWaitTimeout: 10000, // Maximum wait timeout
38
+ captureMode: 'full',
39
+ maxRetries: 3, // For 404 errors
40
+ timeoutRetries: 2, // For timeout errors
41
+ retryDelayBase: 1000, // Base delay for exponential backoff (1s)
42
+ minScreenshotSize: 102400, // 100KB minimum
43
+ minHtmlSize: 10240, // 10KB minimum
44
+ minPageHeight: 500 // Minimum page height in pixels
45
+ };
46
+
47
+ /**
48
+ * Parse CLAUDE.md for configuration
49
+ */
50
+ function parseClaudeMd(filePath) {
51
+ if (!fs.existsSync(filePath)) {
52
+ console.error(`Error: CLAUDE.md not found at ${filePath}`);
53
+ process.exit(1);
54
+ }
55
+
56
+ const content = fs.readFileSync(filePath, 'utf-8');
57
+ const config = { ...DEFAULT_CONFIG };
58
+
59
+ // Extract configuration values
60
+ const patterns = {
61
+ PLATFORM_URL: /PLATFORM_URL=(.+)/,
62
+ PLATFORM_EMAIL: /PLATFORM_EMAIL=(.+)/,
63
+ PLATFORM_PASSWORD: /PLATFORM_PASSWORD=(.+)/,
64
+ PAGES_TO_CAPTURE: /PAGES_TO_CAPTURE=(.+)/,
65
+ CAPTURE_MODE: /CAPTURE_MODE=(.+)/,
66
+ MAX_PAGES: /MAX_PAGES=(\d+)/,
67
+ VIEWPORT_WIDTH: /VIEWPORT_WIDTH=(\d+)/,
68
+ VIEWPORT_HEIGHT: /VIEWPORT_HEIGHT=(\d+)/,
69
+ WAIT_AFTER_LOAD: /WAIT_AFTER_LOAD=(\d+)/,
70
+ };
71
+
72
+ for (const [key, pattern] of Object.entries(patterns)) {
73
+ const match = content.match(pattern);
74
+ if (match) {
75
+ const value = match[1].trim();
76
+ if (['MAX_PAGES', 'VIEWPORT_WIDTH', 'VIEWPORT_HEIGHT', 'WAIT_AFTER_LOAD'].includes(key)) {
77
+ config[key] = parseInt(value, 10);
78
+ } else {
79
+ config[key] = value;
80
+ }
81
+ }
82
+ }
83
+
84
+ return config;
85
+ }
86
+
87
+ /**
88
+ * Generate validation script for page load
89
+ */
90
+ function generateValidationScript() {
91
+ return `
92
+ // Pre-screenshot validation
93
+ const validation = {
94
+ status: false,
95
+ errors: [],
96
+ checks: {}
97
+ };
98
+
99
+ try {
100
+ // Check 1: Response status
101
+ validation.checks.statusOk = true; // Will be set by response check
102
+
103
+ // Check 2: Page title exists and not empty
104
+ const title = document.title;
105
+ validation.checks.titleExists = title && title.trim().length > 0;
106
+ if (!validation.checks.titleExists) {
107
+ validation.errors.push('Page title is empty');
108
+ }
109
+
110
+ // Check 3: Document body exists
111
+ validation.checks.bodyExists = !!document.body;
112
+ if (!validation.checks.bodyExists) {
113
+ validation.errors.push('Document body does not exist');
114
+ }
115
+
116
+ // Check 4: Key elements loaded (check for common landmarks)
117
+ const hasMain = !!document.querySelector('main, [role="main"], #main, .main');
118
+ const hasNav = !!document.querySelector('nav, [role="navigation"], #nav, .nav, header');
119
+ const hasContent = !!document.querySelector('[data-testid], .content, #content, main, article');
120
+ validation.checks.keyElementsLoaded = hasMain || hasNav || hasContent;
121
+ if (!validation.checks.keyElementsLoaded) {
122
+ validation.errors.push('No key elements found (main, nav, or content areas)');
123
+ }
124
+
125
+ // Check 5: Page height validation
126
+ const pageHeight = Math.max(
127
+ document.body.scrollHeight,
128
+ document.body.offsetHeight,
129
+ document.documentElement.clientHeight,
130
+ document.documentElement.scrollHeight,
131
+ document.documentElement.offsetHeight
132
+ );
133
+ validation.checks.heightValid = pageHeight > 500;
134
+ validation.checks.pageHeight = pageHeight;
135
+ if (!validation.checks.heightValid) {
136
+ validation.errors.push(\`Page height too small: \${pageHeight}px\`);
137
+ }
138
+
139
+ // Check 6: No error messages visible
140
+ const errorSelectors = [
141
+ '.error', '[class*="error"]',
142
+ '.alert-error', '.alert-danger',
143
+ '[role="alert"]',
144
+ '#error', '#error-message'
145
+ ];
146
+ let hasErrorMessage = false;
147
+ for (const selector of errorSelectors) {
148
+ const el = document.querySelector(selector);
149
+ if (el && el.offsetParent !== null) { // visible check
150
+ const text = el.textContent.toLowerCase();
151
+ if (text.includes('error') || text.includes('404') || text.includes('not found')) {
152
+ hasErrorMessage = true;
153
+ validation.errors.push(\`Error message detected: \${text.substring(0, 100)}\`);
154
+ break;
155
+ }
156
+ }
157
+ }
158
+ validation.checks.noErrorMessages = !hasErrorMessage;
159
+
160
+ // Overall validation status
161
+ validation.status = validation.checks.titleExists &&
162
+ validation.checks.bodyExists &&
163
+ validation.checks.keyElementsLoaded &&
164
+ validation.checks.heightValid &&
165
+ validation.checks.noErrorMessages;
166
+
167
+ } catch (error) {
168
+ validation.errors.push(\`Validation script error: \${error.message}\`);
169
+ validation.status = false;
170
+ }
171
+
172
+ JSON.stringify(validation);
173
+ `.trim();
174
+ }
175
+
176
+ /**
177
+ * Generate retry logic with exponential backoff
178
+ */
179
+ function generateRetryLogic(config) {
180
+ const { maxRetries, timeoutRetries, retryDelayBase } = config;
181
+
182
+ return `
183
+ # Retry function with exponential backoff
184
+ retry_capture() {
185
+ local PAGE_PATH=$1
186
+ local ATTEMPT=0
187
+ local MAX_ATTEMPTS=${maxRetries}
188
+ local TIMEOUT_ATTEMPTS=${timeoutRetries}
189
+ local DELAY=${retryDelayBase}
190
+ local SUCCESS=false
191
+
192
+ while [ $ATTEMPT -lt $MAX_ATTEMPTS ] && [ "$SUCCESS" = "false" ]; do
193
+ ATTEMPT=$((ATTEMPT + 1))
194
+
195
+ if [ $ATTEMPT -gt 1 ]; then
196
+ echo " Retry attempt $ATTEMPT for $PAGE_PATH (waiting \${DELAY}ms)..."
197
+ sleep $(echo "scale=3; $DELAY/1000" | bc)
198
+ DELAY=$((DELAY * 2)) # Exponential backoff
199
+ fi
200
+
201
+ # Attempt capture
202
+ if capture_page_with_validation "$PAGE_PATH"; then
203
+ SUCCESS=true
204
+ echo " ✓ Successfully captured $PAGE_PATH"
205
+ else
206
+ echo " ✗ Failed attempt $ATTEMPT for $PAGE_PATH"
207
+ fi
208
+ done
209
+
210
+ if [ "$SUCCESS" = "false" ]; then
211
+ log_error "$PAGE_PATH" "capture_failed" "Failed after $MAX_ATTEMPTS attempts"
212
+ return 1
213
+ fi
214
+
215
+ return 0
216
+ }
217
+ `.trim();
218
+ }
219
+
220
+ /**
221
+ * Generate error logging function
222
+ */
223
+ function generateErrorLogging(outputDir) {
224
+ const errorLogPath = path.join(outputDir, 'capture-errors.log');
225
+
226
+ return `
227
+ # Error logging function
228
+ ERROR_LOG="${errorLogPath}"
229
+ echo "=== Capture Error Log ===" > "$ERROR_LOG"
230
+ echo "Started: $(date -Iseconds)" >> "$ERROR_LOG"
231
+ echo "" >> "$ERROR_LOG"
232
+
233
+ log_error() {
234
+ local PAGE_PATH=$1
235
+ local ERROR_TYPE=$2
236
+ local ERROR_MESSAGE=$3
237
+ local TIMESTAMP=$(date -Iseconds)
238
+
239
+ echo "[$TIMESTAMP] ERROR: $PAGE_PATH" >> "$ERROR_LOG"
240
+ echo " Type: $ERROR_TYPE" >> "$ERROR_LOG"
241
+ echo " Message: $ERROR_MESSAGE" >> "$ERROR_LOG"
242
+ echo "" >> "$ERROR_LOG"
243
+
244
+ # Also log to console
245
+ echo " ⚠️ ERROR logged for $PAGE_PATH: $ERROR_MESSAGE"
246
+ }
247
+
248
+ log_summary() {
249
+ echo "" >> "$ERROR_LOG"
250
+ echo "=== Capture Summary ===" >> "$ERROR_LOG"
251
+ echo "Completed: $(date -Iseconds)" >> "$ERROR_LOG"
252
+ echo "Total Pages Attempted: $PAGES_ATTEMPTED" >> "$ERROR_LOG"
253
+ echo "Successful Captures: $PAGES_SUCCESS" >> "$ERROR_LOG"
254
+ echo "Failed Captures: $PAGES_FAILED" >> "$ERROR_LOG"
255
+ echo "Success Rate: $PAGES_SUCCESS_RATE%" >> "$ERROR_LOG"
256
+ }
257
+ `.trim();
258
+ }
259
+
260
+ /**
261
+ * Generate the crawl and capture script
262
+ */
263
+ function generateFullCaptureScript(config, outputDir) {
264
+ const {
265
+ PLATFORM_URL,
266
+ PLATFORM_EMAIL,
267
+ PLATFORM_PASSWORD,
268
+ PAGES_TO_CAPTURE,
269
+ CAPTURE_MODE,
270
+ MAX_PAGES,
271
+ VIEWPORT_WIDTH,
272
+ VIEWPORT_HEIGHT,
273
+ WAIT_AFTER_LOAD,
274
+ } = config;
275
+
276
+ if (!PLATFORM_URL) {
277
+ console.error('Error: PLATFORM_URL not found in CLAUDE.md');
278
+ process.exit(1);
279
+ }
280
+
281
+ const isAutoMode = PAGES_TO_CAPTURE === 'auto' || CAPTURE_MODE === 'full';
282
+ const baseUrl = PLATFORM_URL.replace(/\/$/, '');
283
+
284
+ const lines = [];
285
+
286
+ // Header
287
+ lines.push('#!/bin/bash');
288
+ lines.push('# ===========================================');
289
+ lines.push('# FULL SITE CAPTURE SCRIPT - ENHANCED');
290
+ lines.push('# ===========================================');
291
+ lines.push(`# Platform: ${baseUrl}`);
292
+ lines.push(`# Mode: ${isAutoMode ? 'Auto-discover all pages' : 'Manual page list'}`);
293
+ lines.push(`# Max Pages: ${MAX_PAGES}`);
294
+ lines.push(`# Max Retries: ${config.maxRetries}`);
295
+ lines.push(`# Timeout Retries: ${config.timeoutRetries}`);
296
+ lines.push(`# Wait After Load: ${WAIT_AFTER_LOAD}ms`);
297
+ lines.push(`# Max Wait Timeout: ${config.maxWaitTimeout}ms`);
298
+ lines.push('# ');
299
+ lines.push('# Features:');
300
+ lines.push('# - Wait for networkidle0 (all requests complete)');
301
+ lines.push('# - Pre-screenshot validation');
302
+ lines.push('# - Retry with exponential backoff');
303
+ lines.push('# - Comprehensive error logging');
304
+ lines.push('# - Success validation');
305
+ lines.push('# ');
306
+ lines.push('# This is a ONE-TIME capture. Run once to capture');
307
+ lines.push('# the entire platform for future prototyping.');
308
+ lines.push('# ===========================================');
309
+ lines.push('');
310
+
311
+ // Initialize counters
312
+ lines.push('# Initialize tracking variables');
313
+ lines.push('PAGES_ATTEMPTED=0');
314
+ lines.push('PAGES_SUCCESS=0');
315
+ lines.push('PAGES_FAILED=0');
316
+ lines.push('PAGES_SUCCESS_RATE=0');
317
+ lines.push('');
318
+
319
+ // Error logging setup
320
+ lines.push('# Step 1: Setup error logging');
321
+ lines.push(generateErrorLogging(outputDir));
322
+ lines.push('');
323
+
324
+ // Create directories
325
+ lines.push('# Step 2: Create directory structure');
326
+ lines.push(`mkdir -p ${outputDir}/screenshots`);
327
+ lines.push(`mkdir -p ${outputDir}/html`);
328
+ lines.push(`mkdir -p ${outputDir}/styles`);
329
+ lines.push('echo "Created reference directories"');
330
+ lines.push('');
331
+
332
+ // Set viewport
333
+ lines.push('# Step 3: Configure browser');
334
+ lines.push(`agent-browser set viewport ${VIEWPORT_WIDTH} ${VIEWPORT_HEIGHT}`);
335
+ lines.push('');
336
+
337
+ // Authentication
338
+ if (PLATFORM_EMAIL && PLATFORM_PASSWORD) {
339
+ lines.push('# Step 4: Authenticate');
340
+ lines.push(`echo "Navigating to login page..."`);
341
+ lines.push(`agent-browser open ${baseUrl}/login`);
342
+ lines.push(`agent-browser wait ${WAIT_AFTER_LOAD}`);
343
+ lines.push('agent-browser snapshot -i');
344
+ lines.push('echo ""');
345
+ lines.push('echo "=== LOGIN REQUIRED ==="');
346
+ lines.push('echo "Look at the snapshot above and find the element refs for:"');
347
+ lines.push('echo " - Email/username input field"');
348
+ lines.push('echo " - Password input field"');
349
+ lines.push('echo " - Login/Submit button"');
350
+ lines.push('echo ""');
351
+ lines.push('echo "Then run these commands (replace @eX with actual refs):"');
352
+ lines.push(`echo " agent-browser fill @e1 \\"${PLATFORM_EMAIL}\\""`);
353
+ lines.push(`echo " agent-browser fill @e2 \\"${PLATFORM_PASSWORD}\\""`);
354
+ lines.push('echo " agent-browser click @e3"');
355
+ lines.push('echo " agent-browser wait --load networkidle"');
356
+ lines.push('echo ""');
357
+ lines.push('echo "After login succeeds, continue with Step 4"');
358
+ lines.push('echo "======================');
359
+ lines.push('');
360
+ }
361
+
362
+ if (isAutoMode) {
363
+ // Auto-discovery mode
364
+ lines.push('# Step 5: Discover all pages');
365
+ lines.push('echo "Starting page discovery..."');
366
+ lines.push('');
367
+ lines.push('# Get all internal links from current page');
368
+ lines.push(`DISCOVER_SCRIPT='
369
+ const links = new Set();
370
+ const baseUrl = "${baseUrl}";
371
+ const baseDomain = new URL(baseUrl).hostname;
372
+
373
+ document.querySelectorAll("a[href]").forEach(a => {
374
+ try {
375
+ const url = new URL(a.href, baseUrl);
376
+ // Only internal links, no query params or hashes
377
+ if (url.hostname === baseDomain) {
378
+ const cleanPath = url.pathname.replace(/\\/$/, "") || "/";
379
+ links.add(cleanPath);
380
+ }
381
+ } catch(e) {}
382
+ });
383
+
384
+ // Also check for common navigation patterns
385
+ document.querySelectorAll("[data-href], [data-link], [onclick]").forEach(el => {
386
+ const href = el.dataset.href || el.dataset.link;
387
+ if (href && href.startsWith("/")) {
388
+ links.add(href.split("?")[0]);
389
+ }
390
+ });
391
+
392
+ JSON.stringify([...links].slice(0, ${MAX_PAGES}));
393
+ '`);
394
+ lines.push('');
395
+ lines.push('# Navigate to main page first to discover links');
396
+ lines.push(`agent-browser open ${baseUrl}`);
397
+ lines.push(`agent-browser wait ${WAIT_AFTER_LOAD}`);
398
+ lines.push('agent-browser wait --load networkidle');
399
+ lines.push('');
400
+ lines.push('# Extract all internal links');
401
+ lines.push('echo "Extracting internal links..."');
402
+ lines.push('agent-browser eval "$DISCOVER_SCRIPT"');
403
+ lines.push('');
404
+ lines.push('# The above command outputs a JSON array of paths');
405
+ lines.push('# Save that output and iterate through each path');
406
+ lines.push('');
407
+ lines.push('echo ""');
408
+ lines.push('echo "=== DISCOVERED PAGES ==="');
409
+ lines.push('echo "The eval command above outputs a JSON array of paths."');
410
+ lines.push('echo "For each path, run the capture commands in Step 5."');
411
+ lines.push('echo "========================"');
412
+ lines.push('');
413
+ }
414
+
415
+ // Validation script
416
+ lines.push('# Validation script');
417
+ lines.push(`VALIDATION_SCRIPT='${generateValidationScript()}'`);
418
+ lines.push('');
419
+
420
+ // Capture function with validation
421
+ lines.push('# Step 6: Robust capture function with validation');
422
+ lines.push('# For each page path, run these commands:');
423
+ lines.push('');
424
+ lines.push('capture_page_with_validation() {');
425
+ lines.push(' local PAGE_PATH=$1');
426
+ lines.push(' local PAGE_NAME=$(echo "$PAGE_PATH" | sed "s/^\\/*//" | sed "s/\\//-/g")');
427
+ lines.push(' [ -z "$PAGE_NAME" ] && PAGE_NAME="home"');
428
+ lines.push(' ');
429
+ lines.push(' echo "Capturing: $PAGE_PATH -> $PAGE_NAME"');
430
+ lines.push(' ');
431
+ lines.push(' # Navigate to page');
432
+ lines.push(` agent-browser open ${baseUrl}\$PAGE_PATH`);
433
+ lines.push(' ');
434
+ lines.push(' # Wait strategies (multiple layers)');
435
+ lines.push(` # 1. Initial wait after load`);
436
+ lines.push(` agent-browser wait ${WAIT_AFTER_LOAD}`);
437
+ lines.push(' ');
438
+ lines.push(' # 2. Wait for network idle (all requests complete)');
439
+ lines.push(' agent-browser wait --load networkidle');
440
+ lines.push(' ');
441
+ lines.push(' # 3. Wait for load event');
442
+ lines.push(' agent-browser wait --load load');
443
+ lines.push(' ');
444
+ lines.push(' # 4. Wait for DOM content loaded');
445
+ lines.push(' agent-browser wait --load domcontentloaded');
446
+ lines.push(' ');
447
+ lines.push(' # Pre-screenshot validation');
448
+ lines.push(' VALIDATION_RESULT=$(agent-browser eval "$VALIDATION_SCRIPT")');
449
+ lines.push(' VALIDATION_STATUS=$(echo "$VALIDATION_RESULT" | jq -r ".status")');
450
+ lines.push(' ');
451
+ lines.push(' if [ "$VALIDATION_STATUS" != "true" ]; then');
452
+ lines.push(' VALIDATION_ERRORS=$(echo "$VALIDATION_RESULT" | jq -r ".errors | join(\\", \\")")');
453
+ lines.push(' log_error "$PAGE_PATH" "validation_failed" "$VALIDATION_ERRORS"');
454
+ lines.push(' return 1');
455
+ lines.push(' fi');
456
+ lines.push(' ');
457
+ lines.push(' # Capture screenshot');
458
+ lines.push(` agent-browser screenshot --full ${outputDir}/screenshots/\$PAGE_NAME.png`);
459
+ lines.push(' ');
460
+ lines.push(' # Capture HTML');
461
+ lines.push(` agent-browser eval "document.documentElement.outerHTML" > ${outputDir}/html/\$PAGE_NAME.html`);
462
+ lines.push(' ');
463
+ lines.push(' # Post-capture validation');
464
+ lines.push(` SCREENSHOT_SIZE=$(stat -f%z "${outputDir}/screenshots/\$PAGE_NAME.png" 2>/dev/null || stat -c%s "${outputDir}/screenshots/\$PAGE_NAME.png" 2>/dev/null)`);
465
+ lines.push(` HTML_SIZE=$(stat -f%z "${outputDir}/html/\$PAGE_NAME.html" 2>/dev/null || stat -c%s "${outputDir}/html/\$PAGE_NAME.html" 2>/dev/null)`);
466
+ lines.push(' ');
467
+ lines.push(` if [ "$SCREENSHOT_SIZE" -lt ${config.minScreenshotSize} ]; then`);
468
+ lines.push(' log_error "$PAGE_PATH" "screenshot_too_small" "Screenshot size: $SCREENSHOT_SIZE bytes"');
469
+ lines.push(' return 1');
470
+ lines.push(' fi');
471
+ lines.push(' ');
472
+ lines.push(` if [ "$HTML_SIZE" -lt ${config.minHtmlSize} ]; then`);
473
+ lines.push(' log_error "$PAGE_PATH" "html_too_small" "HTML size: $HTML_SIZE bytes"');
474
+ lines.push(' return 1');
475
+ lines.push(' fi');
476
+ lines.push(' ');
477
+ lines.push(' # Get screenshot dimensions');
478
+ lines.push(' PAGE_HEIGHT=$(echo "$VALIDATION_RESULT" | jq -r ".checks.pageHeight")');
479
+ lines.push(` if [ "$PAGE_HEIGHT" -lt ${config.minPageHeight} ]; then`);
480
+ lines.push(' log_error "$PAGE_PATH" "page_too_short" "Page height: $PAGE_HEIGHT pixels"');
481
+ lines.push(' return 1');
482
+ lines.push(' fi');
483
+ lines.push(' ');
484
+ lines.push(' echo " ✓ Validated: Screenshot=$SCREENSHOT_SIZE bytes, HTML=$HTML_SIZE bytes, Height=$PAGE_HEIGHT px"');
485
+ lines.push(' return 0');
486
+ lines.push('}');
487
+ lines.push('');
488
+
489
+ // Retry logic
490
+ lines.push('# Retry logic with exponential backoff');
491
+ lines.push(generateRetryLogic(config));
492
+ lines.push('');
493
+
494
+ // Wrapper function that increments counters
495
+ lines.push('# Capture wrapper with statistics');
496
+ lines.push('capture_page() {');
497
+ lines.push(' local PAGE_PATH=$1');
498
+ lines.push(' PAGES_ATTEMPTED=$((PAGES_ATTEMPTED + 1))');
499
+ lines.push(' ');
500
+ lines.push(' if retry_capture "$PAGE_PATH"; then');
501
+ lines.push(' PAGES_SUCCESS=$((PAGES_SUCCESS + 1))');
502
+ lines.push(' else');
503
+ lines.push(' PAGES_FAILED=$((PAGES_FAILED + 1))');
504
+ lines.push(' fi');
505
+ lines.push(' ');
506
+ lines.push(' # Update success rate');
507
+ lines.push(' if [ $PAGES_ATTEMPTED -gt 0 ]; then');
508
+ lines.push(' PAGES_SUCCESS_RATE=$(echo "scale=2; ($PAGES_SUCCESS * 100) / $PAGES_ATTEMPTED" | bc)');
509
+ lines.push(' fi');
510
+ lines.push('}');
511
+ lines.push('');
512
+
513
+ // Example captures
514
+ if (!isAutoMode && PAGES_TO_CAPTURE && PAGES_TO_CAPTURE !== 'auto') {
515
+ const pages = PAGES_TO_CAPTURE.split(',').map(p => p.trim());
516
+ lines.push('# Capture specified pages:');
517
+ for (const page of pages) {
518
+ lines.push(`capture_page "${page}"`);
519
+ }
520
+ } else {
521
+ lines.push('# Example: Capture common pages');
522
+ lines.push('# Uncomment and modify based on discovered pages:');
523
+ lines.push('# capture_page "/"');
524
+ lines.push('# capture_page "/dashboard"');
525
+ lines.push('# capture_page "/settings"');
526
+ lines.push('# capture_page "/profile"');
527
+ }
528
+ lines.push('');
529
+
530
+ // Extract design tokens
531
+ lines.push('# Step 7: Extract design tokens');
532
+ lines.push('echo "Extracting design tokens..."');
533
+ lines.push(`TOKENS_SCRIPT='
534
+ const styles = getComputedStyle(document.body);
535
+ const root = getComputedStyle(document.documentElement);
536
+
537
+ // Extract CSS variables
538
+ const cssVars = {};
539
+ for (let i = 0; i < root.length; i++) {
540
+ const prop = root[i];
541
+ if (prop.startsWith("--")) {
542
+ cssVars[prop] = root.getPropertyValue(prop).trim();
543
+ }
544
+ }
545
+
546
+ // Extract common style properties
547
+ const tokens = {
548
+ colors: {
549
+ background: styles.backgroundColor,
550
+ text: styles.color,
551
+ cssVariables: cssVars
552
+ },
553
+ typography: {
554
+ fontFamily: styles.fontFamily,
555
+ fontSize: styles.fontSize,
556
+ lineHeight: styles.lineHeight
557
+ },
558
+ spacing: {
559
+ padding: styles.padding,
560
+ margin: styles.margin
561
+ }
562
+ };
563
+
564
+ JSON.stringify(tokens, null, 2);
565
+ '`);
566
+ lines.push('');
567
+ lines.push(`agent-browser eval "$TOKENS_SCRIPT" > ${outputDir}/styles/design-tokens.json`);
568
+ lines.push('');
569
+
570
+ // Generate manifest
571
+ lines.push('# Step 8: Generate manifest');
572
+ lines.push('echo "Generating manifest..."');
573
+ lines.push(`node "$(dirname "$0")/create-manifest.js" "${new URL(baseUrl).hostname}" "${baseUrl}" "${path.dirname(outputDir)}"`);
574
+ lines.push('');
575
+
576
+ // Generate summary
577
+ lines.push('# Step 9: Generate capture summary');
578
+ lines.push('log_summary');
579
+ lines.push('');
580
+
581
+ // Close browser
582
+ lines.push('# Step 10: Close browser');
583
+ lines.push('agent-browser close');
584
+ lines.push('');
585
+
586
+ // Final summary
587
+ lines.push('echo ""');
588
+ lines.push('echo "=== CAPTURE COMPLETE ==="');
589
+ lines.push('echo "Statistics:"');
590
+ lines.push('echo " Pages Attempted: $PAGES_ATTEMPTED"');
591
+ lines.push('echo " Successful: $PAGES_SUCCESS"');
592
+ lines.push('echo " Failed: $PAGES_FAILED"');
593
+ lines.push('echo " Success Rate: $PAGES_SUCCESS_RATE%"');
594
+ lines.push('echo ""');
595
+ lines.push('echo "Output:"');
596
+ lines.push(`echo " Screenshots: ${outputDir}/screenshots/"`);
597
+ lines.push(`echo " HTML files: ${outputDir}/html/"`);
598
+ lines.push(`echo " Styles: ${outputDir}/styles/"`);
599
+ lines.push(`echo " Manifest: ${path.dirname(outputDir)}/manifest.json"`);
600
+ lines.push(`echo " Error Log: ${outputDir}/capture-errors.log"`);
601
+ lines.push('echo ""');
602
+ lines.push('if [ $PAGES_FAILED -gt 0 ]; then');
603
+ lines.push(` echo "⚠️ WARNING: $PAGES_FAILED pages failed to capture. Check ${outputDir}/capture-errors.log for details."`);
604
+ lines.push('else');
605
+ lines.push(' echo "✓ All pages captured successfully!"');
606
+ lines.push('fi');
607
+ lines.push('echo ""');
608
+ lines.push('echo "You can now prototype features using these references!"');
609
+ lines.push('echo "========================="');
610
+
611
+ return lines.join('\n');
612
+ }
613
+
614
+ /**
615
+ * Generate step-by-step instructions for manual execution
616
+ */
617
+ function generateInstructions(config, outputDir) {
618
+ const {
619
+ PLATFORM_URL,
620
+ PLATFORM_EMAIL,
621
+ PLATFORM_PASSWORD,
622
+ MAX_PAGES,
623
+ VIEWPORT_WIDTH,
624
+ VIEWPORT_HEIGHT,
625
+ WAIT_AFTER_LOAD,
626
+ } = config;
627
+
628
+ const baseUrl = PLATFORM_URL.replace(/\/$/, '');
629
+
630
+ return `
631
+ # Full Site Capture - Step by Step Instructions
632
+
633
+ ## Overview
634
+ This captures your entire platform in one session. Run these commands in order.
635
+
636
+ ## Step 1: Setup
637
+ \`\`\`bash
638
+ mkdir -p references/screenshots references/html references/styles
639
+ agent-browser set viewport ${VIEWPORT_WIDTH} ${VIEWPORT_HEIGHT}
640
+ \`\`\`
641
+
642
+ ## Step 2: Login
643
+ \`\`\`bash
644
+ agent-browser open ${baseUrl}/login
645
+ agent-browser wait ${WAIT_AFTER_LOAD}
646
+ agent-browser snapshot -i
647
+ \`\`\`
648
+
649
+ Look at the snapshot output and find element refs, then:
650
+ \`\`\`bash
651
+ agent-browser fill @e<email_ref> "${PLATFORM_EMAIL}"
652
+ agent-browser fill @e<password_ref> "${PLATFORM_PASSWORD}"
653
+ agent-browser click @e<submit_ref>
654
+ agent-browser wait --load networkidle
655
+ \`\`\`
656
+
657
+ ## Step 3: Discover All Pages
658
+ \`\`\`bash
659
+ agent-browser open ${baseUrl}
660
+ agent-browser wait --load networkidle
661
+ agent-browser eval "JSON.stringify([...new Set([...document.querySelectorAll('a[href]')].map(a => { try { const u = new URL(a.href, '${baseUrl}'); return u.hostname === '${new URL(baseUrl).hostname}' ? u.pathname : null; } catch(e) { return null; }}).filter(Boolean))].slice(0, ${MAX_PAGES}))"
662
+ \`\`\`
663
+
664
+ Save the output - this is your list of pages to capture.
665
+
666
+ ## Step 4: Capture Each Page
667
+ For each page path from Step 3:
668
+ \`\`\`bash
669
+ # Replace /path with actual path
670
+ agent-browser open ${baseUrl}/path
671
+ agent-browser wait ${WAIT_AFTER_LOAD}
672
+ agent-browser wait --load networkidle
673
+ agent-browser screenshot --full references/screenshots/path.png
674
+ agent-browser eval "document.documentElement.outerHTML" > references/html/path.html
675
+ \`\`\`
676
+
677
+ ## Step 5: Extract Design Tokens
678
+ \`\`\`bash
679
+ agent-browser eval "JSON.stringify({colors:{bg:getComputedStyle(document.body).backgroundColor,text:getComputedStyle(document.body).color},fonts:{family:getComputedStyle(document.body).fontFamily}},null,2)" > references/styles/tokens.json
680
+ \`\`\`
681
+
682
+ ## Step 6: Generate Manifest
683
+ \`\`\`bash
684
+ node .claude/skills/real-prototypes-skill/scripts/create-manifest.js "${new URL(baseUrl).hostname}" "${baseUrl}" .
685
+ \`\`\`
686
+
687
+ ## Step 7: Cleanup
688
+ \`\`\`bash
689
+ agent-browser close
690
+ \`\`\`
691
+
692
+ ## Done!
693
+ Your platform is now captured. Use these references for all future prototyping.
694
+ `;
695
+ }
696
+
697
+ // Main
698
+ function main() {
699
+ const args = process.argv.slice(2);
700
+ const claudeMdPath = args[0] || path.join(process.cwd(), 'CLAUDE.md');
701
+ const outputDir = args[1] || path.join(process.cwd(), 'references');
702
+
703
+ console.log('===========================================');
704
+ console.log('FULL SITE CAPTURE - Configuration');
705
+ console.log('===========================================');
706
+ console.log(`Config file: ${claudeMdPath}`);
707
+ console.log(`Output dir: ${outputDir}`);
708
+ console.log('');
709
+
710
+ const config = parseClaudeMd(claudeMdPath);
711
+
712
+ console.log('Platform Settings:');
713
+ console.log(` URL: ${config.PLATFORM_URL || 'NOT SET'}`);
714
+ console.log(` Email: ${config.PLATFORM_EMAIL ? '****' : 'NOT SET'}`);
715
+ console.log(` Password: ${config.PLATFORM_PASSWORD ? '****' : 'NOT SET'}`);
716
+ console.log(` Mode: ${config.CAPTURE_MODE || 'full'}`);
717
+ console.log(` Max Pages: ${config.MAX_PAGES}`);
718
+ console.log('');
719
+
720
+ // Generate and output the capture script
721
+ const script = generateFullCaptureScript(config, outputDir);
722
+ console.log('===========================================');
723
+ console.log('CAPTURE SCRIPT (save as capture.sh and run)');
724
+ console.log('===========================================');
725
+ console.log(script);
726
+
727
+ // Also generate instructions
728
+ console.log('');
729
+ console.log(generateInstructions(config, outputDir));
730
+
731
+ // Save the script
732
+ const scriptPath = path.join(path.dirname(claudeMdPath), 'capture-site.sh');
733
+ fs.writeFileSync(scriptPath, script);
734
+ console.log(`\nScript saved to: ${scriptPath}`);
735
+ console.log('Run with: bash capture-site.sh');
736
+ }
737
+
738
+ main();