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,499 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * validate-manifest.js
5
+ *
6
+ * Validates a manifest.json file against the manifest schema.
7
+ * Uses only Node.js built-in modules (no external dependencies like Ajv).
8
+ *
9
+ * Usage:
10
+ * node validate-manifest.js <manifest-path>
11
+ * node validate-manifest.js <manifest-path> [schema-path]
12
+ *
13
+ * Arguments:
14
+ * manifest-path Path to the manifest.json file to validate
15
+ * schema-path Optional path to schema file (defaults to manifest-schema.json in same directory)
16
+ *
17
+ * Example:
18
+ * node validate-manifest.js ./references/manifest.json
19
+ */
20
+
21
+ const fs = require('fs');
22
+ const path = require('path');
23
+
24
+ // Validation result tracking
25
+ let errors = [];
26
+ let warnings = [];
27
+
28
+ /**
29
+ * Parse command line arguments
30
+ */
31
+ function parseArgs() {
32
+ const args = process.argv.slice(2);
33
+
34
+ if (args.length < 1) {
35
+ console.error('Usage: node validate-manifest.js <manifest-path> [schema-path]');
36
+ console.error('');
37
+ console.error('Arguments:');
38
+ console.error(' manifest-path Path to the manifest.json file to validate');
39
+ console.error(' schema-path Optional path to schema file (defaults to manifest-schema.json)');
40
+ process.exit(1);
41
+ }
42
+
43
+ const scriptDir = path.dirname(__filename);
44
+
45
+ return {
46
+ manifestPath: path.resolve(args[0]),
47
+ schemaPath: args[1] ? path.resolve(args[1]) : path.join(scriptDir, 'manifest-schema.json')
48
+ };
49
+ }
50
+
51
+ /**
52
+ * Load and parse a JSON file
53
+ */
54
+ function loadJsonFile(filePath, description) {
55
+ if (!fs.existsSync(filePath)) {
56
+ console.error(`Error: ${description} not found: ${filePath}`);
57
+ process.exit(1);
58
+ }
59
+
60
+ try {
61
+ const content = fs.readFileSync(filePath, 'utf8');
62
+ return JSON.parse(content);
63
+ } catch (err) {
64
+ if (err instanceof SyntaxError) {
65
+ console.error(`Error: Invalid JSON in ${description}: ${err.message}`);
66
+ } else {
67
+ console.error(`Error reading ${description}: ${err.message}`);
68
+ }
69
+ process.exit(1);
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Add an error to the validation results
75
+ */
76
+ function addError(path, message) {
77
+ errors.push({ path, message });
78
+ }
79
+
80
+ /**
81
+ * Add a warning to the validation results
82
+ */
83
+ function addWarning(path, message) {
84
+ warnings.push({ path, message });
85
+ }
86
+
87
+ /**
88
+ * Get the type of a value (more specific than typeof)
89
+ */
90
+ function getType(value) {
91
+ if (value === null) return 'null';
92
+ if (Array.isArray(value)) return 'array';
93
+ return typeof value;
94
+ }
95
+
96
+ /**
97
+ * Validate a value matches the expected type
98
+ */
99
+ function validateType(value, expectedType, path) {
100
+ const actualType = getType(value);
101
+
102
+ if (expectedType === 'array') {
103
+ if (!Array.isArray(value)) {
104
+ addError(path, `Expected array, got ${actualType}`);
105
+ return false;
106
+ }
107
+ } else if (expectedType === 'object') {
108
+ if (actualType !== 'object' || Array.isArray(value) || value === null) {
109
+ addError(path, `Expected object, got ${actualType}`);
110
+ return false;
111
+ }
112
+ } else if (expectedType === 'string') {
113
+ if (typeof value !== 'string') {
114
+ addError(path, `Expected string, got ${actualType}`);
115
+ return false;
116
+ }
117
+ } else if (expectedType === 'number') {
118
+ if (typeof value !== 'number') {
119
+ addError(path, `Expected number, got ${actualType}`);
120
+ return false;
121
+ }
122
+ } else if (expectedType === 'boolean') {
123
+ if (typeof value !== 'boolean') {
124
+ addError(path, `Expected boolean, got ${actualType}`);
125
+ return false;
126
+ }
127
+ } else if (expectedType === 'integer') {
128
+ if (typeof value !== 'number' || !Number.isInteger(value)) {
129
+ addError(path, `Expected integer, got ${actualType}`);
130
+ return false;
131
+ }
132
+ }
133
+
134
+ return true;
135
+ }
136
+
137
+ /**
138
+ * Validate string format
139
+ */
140
+ function validateFormat(value, format, path) {
141
+ if (typeof value !== 'string') return true;
142
+
143
+ switch (format) {
144
+ case 'uri':
145
+ try {
146
+ new URL(value);
147
+ } catch {
148
+ addError(path, `Invalid URI format: ${value}`);
149
+ return false;
150
+ }
151
+ break;
152
+ case 'date-time':
153
+ const date = new Date(value);
154
+ if (isNaN(date.getTime())) {
155
+ addError(path, `Invalid date-time format: ${value}`);
156
+ return false;
157
+ }
158
+ break;
159
+ case 'email':
160
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
161
+ addWarning(path, `Possibly invalid email format: ${value}`);
162
+ }
163
+ break;
164
+ }
165
+
166
+ return true;
167
+ }
168
+
169
+ /**
170
+ * Validate a string against a pattern
171
+ */
172
+ function validatePattern(value, pattern, path) {
173
+ if (typeof value !== 'string') return true;
174
+
175
+ try {
176
+ const regex = new RegExp(pattern);
177
+ if (!regex.test(value)) {
178
+ addError(path, `Value "${value}" does not match pattern: ${pattern}`);
179
+ return false;
180
+ }
181
+ } catch (err) {
182
+ addWarning(path, `Invalid pattern in schema: ${pattern}`);
183
+ }
184
+
185
+ return true;
186
+ }
187
+
188
+ /**
189
+ * Validate enum values
190
+ */
191
+ function validateEnum(value, enumValues, path) {
192
+ if (!enumValues.includes(value)) {
193
+ addError(path, `Value "${value}" not in allowed values: ${enumValues.join(', ')}`);
194
+ return false;
195
+ }
196
+ return true;
197
+ }
198
+
199
+ /**
200
+ * Validate string length constraints
201
+ */
202
+ function validateStringLength(value, schema, path) {
203
+ if (typeof value !== 'string') return true;
204
+
205
+ if (schema.minLength !== undefined && value.length < schema.minLength) {
206
+ addError(path, `String length ${value.length} is less than minimum ${schema.minLength}`);
207
+ return false;
208
+ }
209
+
210
+ if (schema.maxLength !== undefined && value.length > schema.maxLength) {
211
+ addError(path, `String length ${value.length} exceeds maximum ${schema.maxLength}`);
212
+ return false;
213
+ }
214
+
215
+ return true;
216
+ }
217
+
218
+ /**
219
+ * Validate array constraints
220
+ */
221
+ function validateArray(value, schema, path) {
222
+ if (!Array.isArray(value)) return true;
223
+
224
+ let valid = true;
225
+
226
+ if (schema.minItems !== undefined && value.length < schema.minItems) {
227
+ addError(path, `Array length ${value.length} is less than minimum ${schema.minItems}`);
228
+ valid = false;
229
+ }
230
+
231
+ if (schema.maxItems !== undefined && value.length > schema.maxItems) {
232
+ addError(path, `Array length ${value.length} exceeds maximum ${schema.maxItems}`);
233
+ valid = false;
234
+ }
235
+
236
+ // Validate items
237
+ if (schema.items && value.length > 0) {
238
+ for (let i = 0; i < value.length; i++) {
239
+ if (!validateValue(value[i], schema.items, `${path}[${i}]`)) {
240
+ valid = false;
241
+ }
242
+ }
243
+ }
244
+
245
+ return valid;
246
+ }
247
+
248
+ /**
249
+ * Validate object against schema
250
+ */
251
+ function validateObject(value, schema, path) {
252
+ if (getType(value) !== 'object') return true;
253
+
254
+ let valid = true;
255
+
256
+ // Check required properties
257
+ if (schema.required) {
258
+ for (const prop of schema.required) {
259
+ if (!(prop in value)) {
260
+ addError(path, `Missing required property: ${prop}`);
261
+ valid = false;
262
+ }
263
+ }
264
+ }
265
+
266
+ // Validate defined properties
267
+ if (schema.properties) {
268
+ for (const [propName, propSchema] of Object.entries(schema.properties)) {
269
+ if (propName in value) {
270
+ if (!validateValue(value[propName], propSchema, `${path}.${propName}`)) {
271
+ valid = false;
272
+ }
273
+ }
274
+ }
275
+ }
276
+
277
+ // Check for additional properties
278
+ if (schema.additionalProperties === false) {
279
+ const allowedProps = new Set(Object.keys(schema.properties || {}));
280
+ for (const prop of Object.keys(value)) {
281
+ if (!allowedProps.has(prop)) {
282
+ addWarning(path, `Unexpected property: ${prop}`);
283
+ }
284
+ }
285
+ } else if (typeof schema.additionalProperties === 'object') {
286
+ // Validate additional properties against schema
287
+ const definedProps = new Set(Object.keys(schema.properties || {}));
288
+ for (const [propName, propValue] of Object.entries(value)) {
289
+ if (!definedProps.has(propName)) {
290
+ if (!validateValue(propValue, schema.additionalProperties, `${path}.${propName}`)) {
291
+ valid = false;
292
+ }
293
+ }
294
+ }
295
+ }
296
+
297
+ return valid;
298
+ }
299
+
300
+ /**
301
+ * Main validation function for any value
302
+ */
303
+ function validateValue(value, schema, path = '$') {
304
+ if (!schema) return true;
305
+
306
+ let valid = true;
307
+
308
+ // Handle type validation
309
+ if (schema.type) {
310
+ if (!validateType(value, schema.type, path)) {
311
+ return false; // Stop validation if type doesn't match
312
+ }
313
+ }
314
+
315
+ // Handle format validation
316
+ if (schema.format) {
317
+ if (!validateFormat(value, schema.format, path)) {
318
+ valid = false;
319
+ }
320
+ }
321
+
322
+ // Handle pattern validation
323
+ if (schema.pattern) {
324
+ if (!validatePattern(value, schema.pattern, path)) {
325
+ valid = false;
326
+ }
327
+ }
328
+
329
+ // Handle enum validation
330
+ if (schema.enum) {
331
+ if (!validateEnum(value, schema.enum, path)) {
332
+ valid = false;
333
+ }
334
+ }
335
+
336
+ // Handle string constraints
337
+ if (schema.type === 'string') {
338
+ if (!validateStringLength(value, schema, path)) {
339
+ valid = false;
340
+ }
341
+ }
342
+
343
+ // Handle array validation
344
+ if (schema.type === 'array' || Array.isArray(value)) {
345
+ if (!validateArray(value, schema, path)) {
346
+ valid = false;
347
+ }
348
+ }
349
+
350
+ // Handle object validation
351
+ if (schema.type === 'object' || (getType(value) === 'object' && schema.properties)) {
352
+ if (!validateObject(value, schema, path)) {
353
+ valid = false;
354
+ }
355
+ }
356
+
357
+ return valid;
358
+ }
359
+
360
+ /**
361
+ * Additional semantic validations specific to manifest files
362
+ */
363
+ function validateManifestSemantics(manifest) {
364
+ // Check for duplicate page IDs
365
+ if (manifest.pages && Array.isArray(manifest.pages)) {
366
+ const pageIds = new Set();
367
+ for (const page of manifest.pages) {
368
+ if (page.id) {
369
+ if (pageIds.has(page.id)) {
370
+ addError('$.pages', `Duplicate page ID: ${page.id}`);
371
+ }
372
+ pageIds.add(page.id);
373
+ }
374
+ }
375
+ }
376
+
377
+ // Validate screenshot files exist (warning only)
378
+ if (manifest.pages) {
379
+ for (const page of manifest.pages) {
380
+ if (page.screenshots) {
381
+ for (const screenshot of page.screenshots) {
382
+ if (screenshot.file && !screenshot.file.match(/\.(png|jpg|jpeg|webp|gif)$/i)) {
383
+ addWarning(`$.pages[${page.id}].screenshots`,
384
+ `Unusual screenshot extension: ${screenshot.file}`);
385
+ }
386
+ }
387
+ }
388
+ }
389
+ }
390
+
391
+ // Check platform URL is valid
392
+ if (manifest.platform && manifest.platform.url) {
393
+ try {
394
+ new URL(manifest.platform.url);
395
+ } catch {
396
+ addError('$.platform.url', `Invalid URL: ${manifest.platform.url}`);
397
+ }
398
+ }
399
+
400
+ // Warn if no pages defined
401
+ if (!manifest.pages || manifest.pages.length === 0) {
402
+ addWarning('$.pages', 'Manifest has no pages defined');
403
+ }
404
+
405
+ // Warn if design tokens are empty
406
+ if (manifest.designTokens) {
407
+ const hasColors = manifest.designTokens.colors &&
408
+ Object.keys(manifest.designTokens.colors).length > 0;
409
+ const hasTypography = manifest.designTokens.typography &&
410
+ Object.keys(manifest.designTokens.typography).length > 0;
411
+
412
+ if (!hasColors && !hasTypography) {
413
+ addWarning('$.designTokens', 'Design tokens are empty - consider adding colors and typography');
414
+ }
415
+ }
416
+ }
417
+
418
+ /**
419
+ * Print validation results
420
+ */
421
+ function printResults() {
422
+ const hasErrors = errors.length > 0;
423
+ const hasWarnings = warnings.length > 0;
424
+
425
+ if (!hasErrors && !hasWarnings) {
426
+ console.log('Validation passed! No errors or warnings.');
427
+ return true;
428
+ }
429
+
430
+ if (hasErrors) {
431
+ console.log(`\nErrors (${errors.length}):`);
432
+ for (const error of errors) {
433
+ console.log(` [ERROR] ${error.path}: ${error.message}`);
434
+ }
435
+ }
436
+
437
+ if (hasWarnings) {
438
+ console.log(`\nWarnings (${warnings.length}):`);
439
+ for (const warning of warnings) {
440
+ console.log(` [WARN] ${warning.path}: ${warning.message}`);
441
+ }
442
+ }
443
+
444
+ console.log('');
445
+
446
+ if (hasErrors) {
447
+ console.log('Validation FAILED with errors.');
448
+ return false;
449
+ } else {
450
+ console.log('Validation passed with warnings.');
451
+ return true;
452
+ }
453
+ }
454
+
455
+ /**
456
+ * Main execution
457
+ */
458
+ function main() {
459
+ const { manifestPath, schemaPath } = parseArgs();
460
+
461
+ console.log('Manifest Validation');
462
+ console.log('===================');
463
+ console.log(`Manifest: ${manifestPath}`);
464
+ console.log(`Schema: ${schemaPath}`);
465
+ console.log('');
466
+
467
+ // Reset validation state
468
+ errors = [];
469
+ warnings = [];
470
+
471
+ // Load files
472
+ const manifest = loadJsonFile(manifestPath, 'Manifest file');
473
+ const schema = loadJsonFile(schemaPath, 'Schema file');
474
+
475
+ // Validate against schema
476
+ console.log('Validating against schema...');
477
+ validateValue(manifest, schema);
478
+
479
+ // Run semantic validations
480
+ console.log('Running semantic validations...');
481
+ validateManifestSemantics(manifest);
482
+
483
+ // Print results
484
+ const success = printResults();
485
+
486
+ process.exit(success ? 0 : 1);
487
+ }
488
+
489
+ // Run if executed directly
490
+ if (require.main === module) {
491
+ main();
492
+ }
493
+
494
+ // Export for testing
495
+ module.exports = {
496
+ validateValue,
497
+ validateManifestSemantics,
498
+ loadJsonFile
499
+ };