openuispec 0.2.14 → 0.2.16

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 (53) hide show
  1. package/README.md +4 -2
  2. package/check/audit.ts +251 -0
  3. package/check/index.ts +19 -3
  4. package/cli/init.ts +1 -0
  5. package/docs/cli.md +82 -3
  6. package/docs/file-formats.md +83 -0
  7. package/docs/implementation-notes.md +8 -0
  8. package/examples/social-app/openuispec/contracts/action_trigger.yaml +8 -0
  9. package/examples/social-app/openuispec/contracts/collection.yaml +8 -0
  10. package/examples/social-app/openuispec/contracts/data_display.yaml +8 -0
  11. package/examples/social-app/openuispec/contracts/feedback.yaml +8 -0
  12. package/examples/social-app/openuispec/contracts/input_field.yaml +8 -0
  13. package/examples/social-app/openuispec/contracts/nav_container.yaml +9 -0
  14. package/examples/social-app/openuispec/contracts/surface.yaml +8 -0
  15. package/examples/social-app/openuispec/openuispec.yaml +40 -0
  16. package/examples/social-app/openuispec/tokens/color.yaml +4 -0
  17. package/examples/social-app/openuispec/tokens/motion.yaml +4 -0
  18. package/examples/social-app/openuispec/tokens/typography.yaml +11 -0
  19. package/examples/taskflow/openuispec/contracts/action_trigger.yaml +9 -1
  20. package/examples/taskflow/openuispec/contracts/collection.yaml +9 -1
  21. package/examples/taskflow/openuispec/contracts/data_display.yaml +9 -1
  22. package/examples/taskflow/openuispec/contracts/feedback.yaml +9 -1
  23. package/examples/taskflow/openuispec/contracts/input_field.yaml +8 -0
  24. package/examples/taskflow/openuispec/contracts/nav_container.yaml +10 -1
  25. package/examples/taskflow/openuispec/contracts/surface.yaml +9 -1
  26. package/examples/taskflow/openuispec/openuispec.yaml +40 -0
  27. package/examples/taskflow/openuispec/tokens/color.yaml +4 -0
  28. package/examples/taskflow/openuispec/tokens/motion.yaml +4 -0
  29. package/examples/taskflow/openuispec/tokens/typography.yaml +11 -0
  30. package/examples/todo-orbit/openuispec/contracts/action_trigger.yaml +7 -0
  31. package/examples/todo-orbit/openuispec/contracts/collection.yaml +7 -0
  32. package/examples/todo-orbit/openuispec/contracts/data_display.yaml +7 -0
  33. package/examples/todo-orbit/openuispec/contracts/feedback.yaml +7 -0
  34. package/examples/todo-orbit/openuispec/contracts/input_field.yaml +7 -0
  35. package/examples/todo-orbit/openuispec/contracts/nav_container.yaml +8 -0
  36. package/examples/todo-orbit/openuispec/contracts/surface.yaml +7 -0
  37. package/examples/todo-orbit/openuispec/openuispec.yaml +40 -0
  38. package/examples/todo-orbit/openuispec/tokens/color.yaml +4 -0
  39. package/examples/todo-orbit/openuispec/tokens/motion.yaml +4 -0
  40. package/examples/todo-orbit/openuispec/tokens/typography.yaml +11 -0
  41. package/mcp-server/index.ts +22 -6
  42. package/mcp-server/screenshot-shared.ts +3 -4
  43. package/mcp-server/screenshot.ts +285 -70
  44. package/package.json +1 -1
  45. package/prepare/index.ts +96 -0
  46. package/schema/component.schema.json +5 -0
  47. package/schema/contract.schema.json +11 -1
  48. package/schema/custom-contract.schema.json +5 -0
  49. package/schema/openuispec.schema.json +47 -0
  50. package/schema/semantic-lint.ts +5 -3
  51. package/schema/tokens/color.schema.json +5 -0
  52. package/schema/tokens/motion.schema.json +5 -0
  53. package/schema/tokens/typography.schema.json +10 -0
@@ -71,6 +71,11 @@
71
71
  "may_handle": {
72
72
  "type": "array",
73
73
  "items": { "type": "string" }
74
+ },
75
+ "must_avoid": {
76
+ "type": "array",
77
+ "items": { "type": "string" },
78
+ "description": "Anti-patterns for AI generators. Strings may start with [web], [ios], or [android] to scope to a platform. Unmarked items apply to all platforms."
74
79
  }
75
80
  },
76
81
  "additionalProperties": false
@@ -116,7 +121,12 @@
116
121
  "properties": {
117
122
  "must_handle": { "type": "array", "items": { "type": "string" } },
118
123
  "should_handle": { "type": "array", "items": { "type": "string" } },
119
- "may_handle": { "type": "array", "items": { "type": "string" } }
124
+ "may_handle": { "type": "array", "items": { "type": "string" } },
125
+ "must_avoid": {
126
+ "type": "array",
127
+ "items": { "type": "string" },
128
+ "description": "Anti-patterns for AI generators. Strings may start with [web], [ios], or [android] to scope to a platform. Unmarked items apply to all platforms."
129
+ }
120
130
  },
121
131
  "additionalProperties": false
122
132
  }
@@ -112,6 +112,11 @@
112
112
  "type": "array",
113
113
  "items": { "type": "string" },
114
114
  "description": "Optional enhancements the generator MAY implement"
115
+ },
116
+ "must_avoid": {
117
+ "type": "array",
118
+ "items": { "type": "string" },
119
+ "description": "Anti-patterns for AI generators. Strings may start with [web], [ios], or [android] to scope to a platform. Unmarked items apply to all platforms."
115
120
  }
116
121
  },
117
122
  "additionalProperties": false
@@ -259,6 +259,53 @@
259
259
  "type": "string"
260
260
  }
261
261
  },
262
+ "design": {
263
+ "type": "object",
264
+ "description": "Design intent and anti-patterns for this project",
265
+ "properties": {
266
+ "personality": { "type": "string", "description": "Brief description of the brand's visual personality" },
267
+ "complexity": {
268
+ "type": "string",
269
+ "enum": ["restrained", "balanced", "elaborate"],
270
+ "default": "balanced",
271
+ "description": "How elaborate animations, effects, and visual details should be"
272
+ },
273
+ "audience": { "type": "string", "description": "Who uses this app — informs tone and complexity" },
274
+ "avoid": {
275
+ "type": "array",
276
+ "items": { "type": "string" },
277
+ "description": "Project-specific anti-patterns. May use [web]/[ios]/[android] scope tags."
278
+ }
279
+ },
280
+ "additionalProperties": false
281
+ },
282
+ "generation_guidance": {
283
+ "type": "object",
284
+ "description": "Universal anti-patterns and audit config for AI generators",
285
+ "properties": {
286
+ "universal_anti_patterns": {
287
+ "type": "object",
288
+ "description": "Cross-contract anti-patterns by domain",
289
+ "properties": {
290
+ "typography": { "type": "array", "items": { "type": "string" } },
291
+ "color": { "type": "array", "items": { "type": "string" } },
292
+ "spacing": { "type": "array", "items": { "type": "string" } },
293
+ "motion": { "type": "array", "items": { "type": "string" } },
294
+ "elevation": { "type": "array", "items": { "type": "string" } },
295
+ "layout": { "type": "array", "items": { "type": "string" } },
296
+ "accessibility": { "type": "array", "items": { "type": "string" } }
297
+ },
298
+ "additionalProperties": false
299
+ },
300
+ "audit_threshold": {
301
+ "type": "integer",
302
+ "minimum": 0,
303
+ "maximum": 100,
304
+ "description": "Minimum design quality score. Default 0 (informational). --min-score CLI flag takes precedence."
305
+ }
306
+ },
307
+ "additionalProperties": false
308
+ },
262
309
  "api": {
263
310
  "type": "object",
264
311
  "description": "API endpoint definitions",
@@ -184,7 +184,8 @@ function collectIconRefs(filePath: string): { refs: Set<string>; suffixes: strin
184
184
  if (!isRecord(data) || !isRecord(data.icons)) return { refs, suffixes };
185
185
 
186
186
  const icons = data.icons as UnknownRecord;
187
- const variantSuffixes = isRecord(icons.variants?.suffixes) ? icons.variants.suffixes : {};
187
+ const variants = isRecord(icons.variants) ? icons.variants : {};
188
+ const variantSuffixes = isRecord(variants.suffixes) ? variants.suffixes : {};
188
189
  for (const suffix of Object.keys(variantSuffixes)) {
189
190
  if (suffix.trim()) suffixes.push(suffix);
190
191
  }
@@ -217,8 +218,9 @@ function collectIconRefs(filePath: string): { refs: Set<string>; suffixes: strin
217
218
  }
218
219
  }
219
220
 
220
- if (typeof icons.fallback?.missing_icon === "string") {
221
- refs.add(icons.fallback.missing_icon);
221
+ const fallback = isRecord(icons.fallback) ? icons.fallback : {};
222
+ if (typeof fallback.missing_icon === "string") {
223
+ refs.add(fallback.missing_icon);
222
224
  }
223
225
 
224
226
  return { refs, suffixes };
@@ -75,6 +75,11 @@
75
75
  },
76
76
  "contrast_min": {
77
77
  "type": "number"
78
+ },
79
+ "generation_notes": {
80
+ "type": "array",
81
+ "items": { "type": "string" },
82
+ "description": "Sparse guidance for AI generators. Use [web]/[ios]/[android] tags for platform-specific notes."
78
83
  }
79
84
  },
80
85
  "required": [
@@ -75,6 +75,11 @@
75
75
  "pattern": {
76
76
  "type": "string",
77
77
  "description": "Named animation pattern"
78
+ },
79
+ "generation_notes": {
80
+ "type": "array",
81
+ "items": { "type": "string" },
82
+ "description": "Sparse guidance for AI generators. Use [web]/[ios]/[android] tags for platform-specific notes."
78
83
  }
79
84
  },
80
85
  "additionalProperties": false
@@ -60,6 +60,11 @@
60
60
  }
61
61
  },
62
62
  "additionalProperties": false
63
+ },
64
+ "generation_notes": {
65
+ "type": "array",
66
+ "items": { "type": "string" },
67
+ "description": "Sparse guidance for AI generators. Use [web]/[ios]/[android] tags for platform-specific notes."
63
68
  }
64
69
  },
65
70
  "required": [
@@ -93,6 +98,11 @@
93
98
  "capitalize",
94
99
  "none"
95
100
  ]
101
+ },
102
+ "generation_notes": {
103
+ "type": "array",
104
+ "items": { "type": "string" },
105
+ "description": "Sparse guidance for AI generators. Use [web]/[ios]/[android] tags for platform-specific notes."
96
106
  }
97
107
  },
98
108
  "required": [