velloo 0.0.0 → 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 (262) hide show
  1. package/BUN-LICENSE.md +91 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +9 -0
  4. package/README.md +262 -2
  5. package/THIRD-PARTY-NOTICES.md +467 -0
  6. package/assets/elsewhere-alps-9fqhv029.jpg +0 -0
  7. package/assets/elsewhere-bali-vp60g115.jpg +0 -0
  8. package/assets/elsewhere-forest-xgn23zrj.jpg +0 -0
  9. package/assets/elsewhere-japan-qs7qkbr2.jpg +0 -0
  10. package/assets/elsewhere-kyoto-map-n2bvkrya.svg +1 -0
  11. package/assets/elsewhere-kyoto-qemtn6nk.jpg +0 -0
  12. package/assets/elsewhere-room-g1gaw7cs.jpg +0 -0
  13. package/canvas/apple-touch-icon.png +0 -0
  14. package/canvas/assets/index-BCvDZiBo.css +2 -0
  15. package/canvas/assets/index-BcBJ11d2.js +28 -0
  16. package/canvas/assets/lucide-all-BdEyryfF.js +1 -0
  17. package/canvas/assets/radix-C3HaOB-d.js +41 -0
  18. package/canvas/assets/react-D0Ec-185.js +9 -0
  19. package/canvas/assets/rolldown-runtime-hePW80VL.js +1 -0
  20. package/canvas/assets/vendor-CKmQ-Zst.js +53 -0
  21. package/canvas/favicon.ico +0 -0
  22. package/canvas/favicon.svg +12 -0
  23. package/canvas/fonts/OFL-1.1.txt +93 -0
  24. package/canvas/fonts/poppins-700.woff2 +0 -0
  25. package/canvas/icon-192.png +0 -0
  26. package/canvas/icon-512.png +0 -0
  27. package/canvas/index.html +22 -0
  28. package/canvas/site.webmanifest +11 -0
  29. package/chunk-0t68szgr.js +3 -0
  30. package/chunk-1bywxgc5.js +4 -0
  31. package/chunk-1gx45384.js +41 -0
  32. package/chunk-1y50g9vp.js +2 -0
  33. package/chunk-1yhc252b.js +3 -0
  34. package/chunk-2mv65qxs.js +5 -0
  35. package/chunk-2smsg2ct.js +7 -0
  36. package/chunk-2vx420g2.js +442 -0
  37. package/chunk-2z0k59hz.js +3 -0
  38. package/chunk-329e3phg.js +451 -0
  39. package/chunk-40657ggd.js +10 -0
  40. package/chunk-56vqqr8s.js +3 -0
  41. package/chunk-582y60bv.js +2 -0
  42. package/chunk-5js0qw32.js +2 -0
  43. package/chunk-5x173xay.js +2 -0
  44. package/chunk-65wb0g7d.js +3 -0
  45. package/chunk-6tx68d90.js +3 -0
  46. package/chunk-74skmg76.js +2 -0
  47. package/chunk-75wbh438.js +2 -0
  48. package/chunk-79ykzywe.js +4 -0
  49. package/chunk-7dggmqwq.js +53 -0
  50. package/chunk-7e39xe21.js +18 -0
  51. package/chunk-7p7ha0qk.js +3 -0
  52. package/chunk-8ssr8a8w.js +89 -0
  53. package/chunk-946pcnt5.js +5 -0
  54. package/chunk-9vg3yafz.js +3 -0
  55. package/chunk-aapybh30.js +6 -0
  56. package/chunk-b2ebm1t3.js +303 -0
  57. package/chunk-b7j86xq7.js +4 -0
  58. package/chunk-bjnhhsak.js +2 -0
  59. package/chunk-bk8b7f9a.js +62 -0
  60. package/chunk-cep3ktr3.js +4 -0
  61. package/chunk-cxe6jjwj.js +3 -0
  62. package/chunk-d385435m.js +8 -0
  63. package/chunk-dt03awr1.js +2 -0
  64. package/chunk-e2ag33vd.js +226 -0
  65. package/chunk-erwfk47h.js +3 -0
  66. package/chunk-fgw3hp2v.js +3 -0
  67. package/chunk-fjbzk4sw.js +3 -0
  68. package/chunk-g02nd9hn.js +4 -0
  69. package/chunk-h0c36khx.js +2 -0
  70. package/chunk-h6gchare.js +3 -0
  71. package/chunk-hggap8fq.js +3 -0
  72. package/chunk-hs2j6s1v.js +75 -0
  73. package/chunk-jnsfgtn9.js +3 -0
  74. package/chunk-jrsknzjt.js +3 -0
  75. package/chunk-k6ferbam.js +4 -0
  76. package/chunk-k784090q.js +6 -0
  77. package/chunk-kxk5x7g6.js +3 -0
  78. package/chunk-mq4znqv2.js +2 -0
  79. package/chunk-mzhdrawd.js +3 -0
  80. package/chunk-n5007jcz.js +2 -0
  81. package/chunk-nfr3q7mg.js +5 -0
  82. package/chunk-nsqs1bqf.js +2 -0
  83. package/chunk-nwx5700b.js +3 -0
  84. package/chunk-pphgrsxa.js +2 -0
  85. package/chunk-qpvj6kzq.js +6 -0
  86. package/chunk-qwv7xkms.js +2 -0
  87. package/chunk-rksq3w72.js +244 -0
  88. package/chunk-s23gtejf.js +3 -0
  89. package/chunk-t2ttkxe9.js +85 -0
  90. package/chunk-tmtzxcs5.js +2 -0
  91. package/chunk-vbk1qhdz.js +3 -0
  92. package/chunk-w5rzk6ms.js +1229 -0
  93. package/chunk-xr6f94rj.js +2 -0
  94. package/chunk-y0zxzefg.js +5 -0
  95. package/chunk-zf3xc1wz.js +2 -0
  96. package/cli.js +3 -0
  97. package/launcher.cjs +97 -0
  98. package/package.json +58 -5
  99. package/pkgs/helpers/src/box.tsx +21 -0
  100. package/pkgs/helpers/src/cn.ts +32 -0
  101. package/pkgs/helpers/src/descriptors.ts +270 -0
  102. package/pkgs/helpers/src/divider.tsx +123 -0
  103. package/pkgs/helpers/src/gradient.tsx +90 -0
  104. package/pkgs/helpers/src/heading.tsx +20 -0
  105. package/pkgs/helpers/src/icon-data.ts +8009 -0
  106. package/pkgs/helpers/src/icon.tsx +53 -0
  107. package/pkgs/helpers/src/image.tsx +111 -0
  108. package/pkgs/helpers/src/index.ts +29 -0
  109. package/pkgs/helpers/src/layer.tsx +61 -0
  110. package/pkgs/helpers/src/lowering.ts +53 -0
  111. package/pkgs/helpers/src/paths.ts +47 -0
  112. package/pkgs/helpers/src/placeholder.tsx +88 -0
  113. package/pkgs/helpers/src/prose.tsx +42 -0
  114. package/pkgs/helpers/src/registry.ts +41 -0
  115. package/pkgs/helpers/src/svg.tsx +62 -0
  116. package/pkgs/helpers/src/text.tsx +16 -0
  117. package/pkgs/provider-antd/src/index.ts +78 -0
  118. package/pkgs/provider-antd/src/intro.ts +14 -0
  119. package/pkgs/provider-antd/src/manifest.ts +439 -0
  120. package/pkgs/provider-antd/src/overlays.ts +176 -0
  121. package/pkgs/provider-antd/src/registry.ts +104 -0
  122. package/pkgs/provider-antd/src/render-pass.ts +43 -0
  123. package/pkgs/provider-antd/src/tailwind-entry.css +21 -0
  124. package/pkgs/provider-antd/src/theme.ts +132 -0
  125. package/pkgs/provider-antd/src/version.ts +8 -0
  126. package/pkgs/provider-chakra/src/index.ts +80 -0
  127. package/pkgs/provider-chakra/src/intro.ts +14 -0
  128. package/pkgs/provider-chakra/src/manifest.ts +421 -0
  129. package/pkgs/provider-chakra/src/overlays.ts +246 -0
  130. package/pkgs/provider-chakra/src/registry.ts +227 -0
  131. package/pkgs/provider-chakra/src/render-pass.ts +55 -0
  132. package/pkgs/provider-chakra/src/tailwind-entry.css +21 -0
  133. package/pkgs/provider-chakra/src/theme.ts +180 -0
  134. package/pkgs/provider-chakra/src/version.ts +8 -0
  135. package/pkgs/provider-mui/src/index.ts +117 -0
  136. package/pkgs/provider-mui/src/intro.ts +12 -0
  137. package/pkgs/provider-mui/src/manifest.ts +263 -0
  138. package/pkgs/provider-mui/src/overlays.ts +124 -0
  139. package/pkgs/provider-mui/src/registry.ts +120 -0
  140. package/pkgs/provider-mui/src/render-pass.ts +36 -0
  141. package/pkgs/provider-mui/src/tailwind-entry.css +21 -0
  142. package/pkgs/provider-mui/src/theme.ts +129 -0
  143. package/pkgs/provider-mui/src/version.ts +8 -0
  144. package/pkgs/provider-none/src/components-inline.tsx +204 -0
  145. package/pkgs/provider-none/src/components.tsx +155 -0
  146. package/pkgs/provider-none/src/index.ts +57 -0
  147. package/pkgs/provider-none/src/intro.ts +18 -0
  148. package/pkgs/provider-none/src/manifest.ts +163 -0
  149. package/pkgs/provider-none/src/registry-inline.ts +36 -0
  150. package/pkgs/provider-none/src/registry.ts +39 -0
  151. package/pkgs/provider-none/src/tailwind-entry.css +57 -0
  152. package/pkgs/provider-none/src/version.ts +10 -0
  153. package/pkgs/schema/src/annotation.ts +120 -0
  154. package/pkgs/schema/src/asset.ts +66 -0
  155. package/pkgs/schema/src/board.ts +71 -0
  156. package/pkgs/schema/src/comment.ts +107 -0
  157. package/pkgs/schema/src/config.ts +178 -0
  158. package/pkgs/schema/src/css-sanitize.ts +56 -0
  159. package/pkgs/schema/src/extension.ts +105 -0
  160. package/pkgs/schema/src/fonts.ts +690 -0
  161. package/pkgs/schema/src/frame.ts +40 -0
  162. package/pkgs/schema/src/icon-name.ts +21 -0
  163. package/pkgs/schema/src/ids.ts +14 -0
  164. package/pkgs/schema/src/index.ts +161 -0
  165. package/pkgs/schema/src/migrate.ts +244 -0
  166. package/pkgs/schema/src/node.ts +229 -0
  167. package/pkgs/schema/src/paths.ts +28 -0
  168. package/pkgs/schema/src/repo.ts +52 -0
  169. package/pkgs/schema/src/screen.ts +30 -0
  170. package/pkgs/schema/src/snippet-resolve.ts +193 -0
  171. package/pkgs/schema/src/snippet.ts +104 -0
  172. package/pkgs/schema/src/svg-sanitize.ts +74 -0
  173. package/pkgs/schema/src/theme.ts +218 -0
  174. package/pkgs/schema/src/typeset.ts +693 -0
  175. package/pkgs/schema/src/validate-ids.ts +46 -0
  176. package/pkgs/schema/src/viewport.ts +8 -0
  177. package/pkgs/shadcn-snapshot/dist/manifest.json +8109 -0
  178. package/pkgs/shadcn-snapshot/src/components/canvas-portal.tsx +55 -0
  179. package/pkgs/shadcn-snapshot/src/components/ui/accordion.tsx +122 -0
  180. package/pkgs/shadcn-snapshot/src/components/ui/alert-dialog.tsx +164 -0
  181. package/pkgs/shadcn-snapshot/src/components/ui/alert.tsx +74 -0
  182. package/pkgs/shadcn-snapshot/src/components/ui/aspect-ratio.tsx +13 -0
  183. package/pkgs/shadcn-snapshot/src/components/ui/attachment.tsx +197 -0
  184. package/pkgs/shadcn-snapshot/src/components/ui/avatar.tsx +100 -0
  185. package/pkgs/shadcn-snapshot/src/components/ui/badge.tsx +50 -0
  186. package/pkgs/shadcn-snapshot/src/components/ui/breadcrumb.tsx +109 -0
  187. package/pkgs/shadcn-snapshot/src/components/ui/bubble.tsx +130 -0
  188. package/pkgs/shadcn-snapshot/src/components/ui/button-group.tsx +82 -0
  189. package/pkgs/shadcn-snapshot/src/components/ui/button.tsx +72 -0
  190. package/pkgs/shadcn-snapshot/src/components/ui/calendar.tsx +229 -0
  191. package/pkgs/shadcn-snapshot/src/components/ui/card.tsx +92 -0
  192. package/pkgs/shadcn-snapshot/src/components/ui/carousel.tsx +235 -0
  193. package/pkgs/shadcn-snapshot/src/components/ui/chart-option.ts +250 -0
  194. package/pkgs/shadcn-snapshot/src/components/ui/chart.tsx +177 -0
  195. package/pkgs/shadcn-snapshot/src/components/ui/checkbox.tsx +41 -0
  196. package/pkgs/shadcn-snapshot/src/components/ui/collapsible.tsx +32 -0
  197. package/pkgs/shadcn-snapshot/src/components/ui/combobox.tsx +196 -0
  198. package/pkgs/shadcn-snapshot/src/components/ui/context-menu.tsx +227 -0
  199. package/pkgs/shadcn-snapshot/src/components/ui/dialog.tsx +131 -0
  200. package/pkgs/shadcn-snapshot/src/components/ui/direction.tsx +24 -0
  201. package/pkgs/shadcn-snapshot/src/components/ui/drawer.tsx +112 -0
  202. package/pkgs/shadcn-snapshot/src/components/ui/dropdown-menu.tsx +205 -0
  203. package/pkgs/shadcn-snapshot/src/components/ui/empty.tsx +98 -0
  204. package/pkgs/shadcn-snapshot/src/components/ui/field.tsx +228 -0
  205. package/pkgs/shadcn-snapshot/src/components/ui/hover-card.tsx +51 -0
  206. package/pkgs/shadcn-snapshot/src/components/ui/input-group.tsx +148 -0
  207. package/pkgs/shadcn-snapshot/src/components/ui/input.tsx +43 -0
  208. package/pkgs/shadcn-snapshot/src/components/ui/item.tsx +187 -0
  209. package/pkgs/shadcn-snapshot/src/components/ui/kbd.tsx +30 -0
  210. package/pkgs/shadcn-snapshot/src/components/ui/label.tsx +25 -0
  211. package/pkgs/shadcn-snapshot/src/components/ui/marker.tsx +71 -0
  212. package/pkgs/shadcn-snapshot/src/components/ui/menubar.tsx +243 -0
  213. package/pkgs/shadcn-snapshot/src/components/ui/message.tsx +89 -0
  214. package/pkgs/shadcn-snapshot/src/components/ui/native-select.tsx +60 -0
  215. package/pkgs/shadcn-snapshot/src/components/ui/navigation-menu.tsx +165 -0
  216. package/pkgs/shadcn-snapshot/src/components/ui/pagination.tsx +117 -0
  217. package/pkgs/shadcn-snapshot/src/components/ui/popover.tsx +66 -0
  218. package/pkgs/shadcn-snapshot/src/components/ui/progress.tsx +35 -0
  219. package/pkgs/shadcn-snapshot/src/components/ui/radio-group.tsx +48 -0
  220. package/pkgs/shadcn-snapshot/src/components/ui/scroll-area.tsx +59 -0
  221. package/pkgs/shadcn-snapshot/src/components/ui/select.tsx +180 -0
  222. package/pkgs/shadcn-snapshot/src/components/ui/separator.tsx +32 -0
  223. package/pkgs/shadcn-snapshot/src/components/ui/sheet.tsx +107 -0
  224. package/pkgs/shadcn-snapshot/src/components/ui/skeleton.tsx +17 -0
  225. package/pkgs/shadcn-snapshot/src/components/ui/slider.tsx +68 -0
  226. package/pkgs/shadcn-snapshot/src/components/ui/sonner.tsx +91 -0
  227. package/pkgs/shadcn-snapshot/src/components/ui/spinner.tsx +21 -0
  228. package/pkgs/shadcn-snapshot/src/components/ui/switch.tsx +41 -0
  229. package/pkgs/shadcn-snapshot/src/components/ui/table.tsx +93 -0
  230. package/pkgs/shadcn-snapshot/src/components/ui/tabs.tsx +84 -0
  231. package/pkgs/shadcn-snapshot/src/components/ui/textarea.tsx +24 -0
  232. package/pkgs/shadcn-snapshot/src/components/ui/toggle-group.tsx +94 -0
  233. package/pkgs/shadcn-snapshot/src/components/ui/toggle.tsx +50 -0
  234. package/pkgs/shadcn-snapshot/src/components/ui/tooltip.tsx +47 -0
  235. package/pkgs/shadcn-snapshot/src/examples.ts +36 -0
  236. package/pkgs/shadcn-snapshot/src/groups.ts +87 -0
  237. package/pkgs/shadcn-snapshot/src/index.ts +43 -0
  238. package/pkgs/shadcn-snapshot/src/lib/utils.ts +4 -0
  239. package/pkgs/shadcn-snapshot/src/manifest.ts +12 -0
  240. package/pkgs/shadcn-snapshot/src/notes.ts +97 -0
  241. package/pkgs/shadcn-snapshot/src/paths.ts +47 -0
  242. package/pkgs/shadcn-snapshot/src/registry-files.ts +293 -0
  243. package/pkgs/shadcn-snapshot/src/registry.ts +631 -0
  244. package/pkgs/shadcn-snapshot/src/shadcn-tailwind.css +632 -0
  245. package/pkgs/shadcn-snapshot/src/tailwind-entry.css +159 -0
  246. package/pkgs/shadcn-snapshot/src/version.ts +8 -0
  247. package/plugins/claude/velloo/.claude-plugin/plugin.json +6 -0
  248. package/plugins/claude/velloo/agents/velloo-design-reviewer.md +33 -0
  249. package/plugins/claude/velloo/agents/velloo-designer.md +39 -0
  250. package/plugins/claude/velloo/commands/design.md +11 -0
  251. package/plugins/claude/velloo/commands/implement.md +10 -0
  252. package/plugins/claude/velloo/commands/review.md +8 -0
  253. package/plugins/gemini/GEMINI.md +31 -0
  254. package/plugins/gemini/commands/velloo/design.toml +10 -0
  255. package/plugins/gemini/commands/velloo/implement.toml +9 -0
  256. package/plugins/gemini/gemini-extension.json +9 -0
  257. package/skills/velloo-brand/SKILL.md +124 -0
  258. package/skills/velloo-design/SKILL.md +144 -0
  259. package/skills/velloo-design-system/SKILL.md +90 -0
  260. package/skills/velloo-implement/SKILL.md +101 -0
  261. package/skills/velloo-logo/SKILL.md +93 -0
  262. package/skills/velloo-setup/SKILL.md +156 -0
@@ -0,0 +1,40 @@
1
+ import { z } from "zod";
2
+ import { ResourceIdSchema } from "./ids.ts";
3
+
4
+ export const FrameSchemeSchema = z.enum(["light", "dark"]);
5
+ export type FrameScheme = z.infer<typeof FrameSchemeSchema>;
6
+
7
+ /**
8
+ * A Frame is a placement of a Screen on the Board: position, size, optional
9
+ * label, optional group. Multiple frames can reference the same screen at
10
+ * different sizes — edits to that screen's tree update every frame that
11
+ * shows it. The canvas renders visual linkage so siblings are obvious.
12
+ *
13
+ * Frames are freely resizable on the canvas. Snap-to-viewport-preset is a
14
+ * UI affordance; the underlying w/h is just a number.
15
+ */
16
+ export const FrameSchema = z.object({
17
+ id: ResourceIdSchema,
18
+ /** The Screen id this frame renders. */
19
+ screen: z.string().min(1),
20
+ x: z.number(),
21
+ y: z.number(),
22
+ w: z.number().int().positive(),
23
+ h: z.number().int().positive(),
24
+ /** Optional human label shown above the frame on the canvas. */
25
+ label: z.string().optional(),
26
+ /** Optional BoardGroup id. */
27
+ group: z.string().optional(),
28
+ /** Pinned render scheme; absent means follow the canvas default. */
29
+ scheme: FrameSchemeSchema.optional(),
30
+ });
31
+
32
+ export type Frame = z.infer<typeof FrameSchema>;
33
+
34
+ /** Resolve a frame pin against the current canvas-level default. */
35
+ export function resolveFrameScheme(
36
+ frame: Pick<Frame, "scheme">,
37
+ canvasDefault: FrameScheme,
38
+ ): FrameScheme {
39
+ return frame.scheme ?? canvasDefault;
40
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Lucide icon names are PascalCase exports ("SquarePen"), but lucide's
3
+ * own site and most docs present kebab-case ids ("square-pen") — agents
4
+ * pass both. Shared normalizer so the runtime Icon helper, codegen's
5
+ * lucide import resolver, and the server's advisory prop warnings all
6
+ * agree on what resolves.
7
+ */
8
+
9
+ /** "square-pen" / "square_pen" / "square pen" → "SquarePen". PascalCase input passes through. */
10
+ export function pascalizeIconName(name: string): string {
11
+ const trimmed = name.trim();
12
+ if (trimmed === "") return trimmed;
13
+ if (!/[-_\s]/.test(trimmed)) {
14
+ return trimmed.charAt(0).toUpperCase() + trimmed.slice(1);
15
+ }
16
+ return trimmed
17
+ .split(/[-_\s]+/)
18
+ .filter((part) => part !== "")
19
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
20
+ .join("");
21
+ }
@@ -0,0 +1,14 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * The one id format for on-disk resources (screens, boards, groups, frames,
5
+ * snippets, annotations, notes): URL- and filename-safe, no dots (filename
6
+ * stems double as ids and the loader treats dotted stems as sidecars), max 64.
7
+ * Node `$id`s are stricter (letter-led — see `NodeIdSchema`) because they
8
+ * double as `@id` locator references.
9
+ */
10
+ export const ResourceIdSchema = z
11
+ .string()
12
+ .regex(/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/, "ids are [A-Za-z0-9][A-Za-z0-9_-]{0,63}");
13
+
14
+ export type ResourceId = z.infer<typeof ResourceIdSchema>;
@@ -0,0 +1,161 @@
1
+ export {
2
+ type Annotation,
3
+ AnnotationSchema,
4
+ type AnnotationTarget,
5
+ AnnotationTargetSchema,
6
+ type CanvasNote,
7
+ type CanvasNoteAttachment,
8
+ CanvasNoteAttachmentSchema,
9
+ CanvasNoteSchema,
10
+ } from "./annotation.ts";
11
+ export {
12
+ type AssetsFile,
13
+ AssetsFileSchema,
14
+ assetPathFromSrc,
15
+ EMPTY_ASSETS_FILE,
16
+ type GeneratedAsset,
17
+ GeneratedAssetSchema,
18
+ } from "./asset.ts";
19
+ export {
20
+ type Board,
21
+ type BoardGroup,
22
+ BoardGroupSchema,
23
+ BoardSchema,
24
+ isArchived,
25
+ MAX_BOARD_NAME_LENGTH,
26
+ } from "./board.ts";
27
+ export {
28
+ type CommentAnchor,
29
+ CommentAnchorSchema,
30
+ type CommentAnchorState,
31
+ type CommentAuthor,
32
+ CommentAuthorSchema,
33
+ type CommentBounds,
34
+ CommentBoundsSchema,
35
+ type CommentLocator,
36
+ CommentLocatorSchema,
37
+ type CommentMessage,
38
+ CommentMessageSchema,
39
+ type CommentNodeFingerprint,
40
+ CommentNodeFingerprintSchema,
41
+ type CommentOrigin,
42
+ CommentOriginSchema,
43
+ type CommentThread,
44
+ CommentThreadSchema,
45
+ type CommentThreadView,
46
+ } from "./comment.ts";
47
+ export {
48
+ type CodegenConfig,
49
+ type Config,
50
+ ConfigSchema,
51
+ type HostApp,
52
+ HostAppSchema,
53
+ type Library,
54
+ LibrarySchema,
55
+ type ViewportPreset,
56
+ ViewportPresetSchema,
57
+ } from "./config.ts";
58
+ export {
59
+ isCssIdent,
60
+ neutralizeCssText,
61
+ sanitizeCssTokenValue,
62
+ sanitizeGoogleFontSpec,
63
+ } from "./css-sanitize.ts";
64
+ export {
65
+ type Extension,
66
+ type ExtensionPropDescriptor,
67
+ ExtensionPropDescriptorSchema,
68
+ ExtensionSchema,
69
+ } from "./extension.ts";
70
+ export {
71
+ type Frame,
72
+ FrameSchema,
73
+ type FrameScheme,
74
+ FrameSchemeSchema,
75
+ resolveFrameScheme,
76
+ } from "./frame.ts";
77
+ export { pascalizeIconName } from "./icon-name.ts";
78
+ export { type ResourceId, ResourceIdSchema } from "./ids.ts";
79
+ export {
80
+ CURRENT_SCHEMA_VERSION,
81
+ FOLDER_MIGRATIONS,
82
+ type FolderMigration,
83
+ type MigrationRun,
84
+ planMigration,
85
+ schemaVersionOf,
86
+ } from "./migrate.ts";
87
+ export {
88
+ type ComponentNode,
89
+ isComponentNode,
90
+ isParamRef,
91
+ isSnippetInstance,
92
+ type Node,
93
+ NodeIdSchema,
94
+ NodeSchema,
95
+ nodeId,
96
+ type ParamRef,
97
+ type SnippetInstance,
98
+ } from "./node.ts";
99
+ export {
100
+ type FeedbackPrefs,
101
+ FeedbackPrefsSchema,
102
+ REPO_MANIFEST_FILE,
103
+ type RepoManifest,
104
+ RepoManifestSchema,
105
+ } from "./repo.ts";
106
+ export { type Screen, ScreenSchema } from "./screen.ts";
107
+ export { type Snippet, type SnippetParam, SnippetParamSchema, SnippetSchema } from "./snippet.ts";
108
+ export {
109
+ applySnippetExtraClassName,
110
+ applySnippetOverrides,
111
+ type InvalidParamPlacement,
112
+ resolveSnippetArgs,
113
+ substituteSnippetParams,
114
+ } from "./snippet-resolve.ts";
115
+ export { sanitizeSvgMarkup, svgLooksActive } from "./svg-sanitize.ts";
116
+ export {
117
+ type ColorPair,
118
+ type Colors,
119
+ type ColorsOverride,
120
+ ColorsSchema,
121
+ type LooseTokenGroup,
122
+ resolveColors,
123
+ type Theme,
124
+ ThemeSchema,
125
+ TypographySchema,
126
+ } from "./theme.ts";
127
+ export {
128
+ DEFAULT_TYPESET_NAME,
129
+ HEADING_ROLE_BY_LEVEL,
130
+ headingClasses,
131
+ headingInlineStyle,
132
+ isTypesetName,
133
+ type ResolvedTypesetRole,
134
+ resolveHeadingLevel,
135
+ resolveTypeset,
136
+ TEXT_ROLE_BY_VARIANT,
137
+ TEXT_TONE_BY_VARIANT,
138
+ type TextVariant,
139
+ TYPESET_CLASSES,
140
+ TYPESET_DEFAULT,
141
+ TYPESET_INLINE_STYLE,
142
+ TYPESET_RATIOS,
143
+ TYPESET_SCALE_NAMES,
144
+ type Typeset,
145
+ type TypesetRatio,
146
+ type TypesetRole,
147
+ type TypesetScale,
148
+ textClasses,
149
+ textInlineStyle,
150
+ typesetBaseVars,
151
+ typesetCss,
152
+ typesetSafelist,
153
+ typesetScale,
154
+ typesetSizePx,
155
+ typesetThemeTokens,
156
+ typesetUtilityClasses,
157
+ typesetV3FontSize,
158
+ typesetVars,
159
+ } from "./typeset.ts";
160
+ export { type DuplicateId, findDuplicateIds } from "./validate-ids.ts";
161
+ export { type Viewport, ViewportSchema } from "./viewport.ts";
@@ -0,0 +1,244 @@
1
+ /**
2
+ * On-disk format versioning + migrations.
3
+ *
4
+ * A design folder's format version lives in `.design/config.json` →
5
+ * `schemaVersion` (one version for the whole folder; individual files carry
6
+ * none). The loader refuses folders whose version doesn't match
7
+ * {@link CURRENT_SCHEMA_VERSION} — older folders are migrated on disk by
8
+ * `velloo upgrade`, newer ones need a newer binary.
9
+ *
10
+ * Migrations here are PURE raw-JSON → raw-JSON transforms (this package does
11
+ * no I/O). The CLI's `upgrade` command owns reading/writing files and applies
12
+ * these in order; each step migrates exactly one version.
13
+ *
14
+ * History:
15
+ * 1 — the original format: legacy single-`library` config still parsed,
16
+ * `source` was free-form ("embedded:shadcn"/"registry:shadcn" aliases),
17
+ * the vendored `shadcn-react` provider was a valid library id, and
18
+ * `Annotation.author` was optional (absent = "user").
19
+ * 2 — multi-library only (`libraries` + `defaultLibrary`), `source` is the
20
+ * enum "binary" | "cache" | "in-repo", `shadcn-react` retired in favor
21
+ * of `shadcn-upstream` (same canvas runtime, real install deferred to
22
+ * the host app), `author` required.
23
+ * 3 — typography is typesets. The `fontSize` / `fontWeight` / `lineHeight` /
24
+ * `letterSpacing` records are gone and `typography` parses strictly, so
25
+ * a v2 theme file is now a hard validation failure rather than dead
26
+ * weight — hence the version gate.
27
+ */
28
+
29
+ export const CURRENT_SCHEMA_VERSION = 3;
30
+
31
+ /**
32
+ * Read the format version off a raw (unvalidated) config object. Historical
33
+ * folders always wrote `schemaVersion: 1`, so anything absent or malformed is
34
+ * treated as 1 rather than an error — `velloo upgrade` then normalizes it.
35
+ */
36
+ export function schemaVersionOf(rawConfig: unknown): number {
37
+ if (typeof rawConfig !== "object" || rawConfig === null) return 1;
38
+ const v = (rawConfig as Record<string, unknown>).schemaVersion;
39
+ return typeof v === "number" && Number.isInteger(v) && v >= 1 ? v : 1;
40
+ }
41
+
42
+ type RawObject = Record<string, unknown>;
43
+
44
+ export interface FolderMigration {
45
+ /** Migrates from exactly this version to `from + 1`. */
46
+ from: number;
47
+ /** One-line, user-facing description (printed by `velloo upgrade`). */
48
+ summary: string;
49
+ /** Transform the raw config.json object (already shallow-cloned). */
50
+ config?(raw: RawObject): RawObject;
51
+ /** Transform one annotation entry from a `screens/<id>.annotations.json` sidecar. */
52
+ annotation?(raw: RawObject): RawObject;
53
+ /** Transform one `theme/<name>.json` document. */
54
+ theme?(raw: RawObject): RawObject;
55
+ }
56
+
57
+ /** Library id assigned to a legacy single-library config when it is promoted. */
58
+ const LEGACY_LIBRARY_KEY = "default";
59
+
60
+ function migrateLibraryEntry(raw: unknown): unknown {
61
+ if (typeof raw !== "object" || raw === null) return raw;
62
+ const lib = { ...(raw as RawObject) };
63
+ // Pre-v2 source vocabulary: both aliases meant "the snapshot inside the
64
+ // velloo binary".
65
+ if (lib.source === "embedded:shadcn" || lib.source === "registry:shadcn") {
66
+ lib.source = "binary";
67
+ lib.componentsPath = "binary";
68
+ }
69
+ // The vendored snapshot is no longer a user-facing provider. shadcn-upstream
70
+ // keeps the same canvas runtime; a real install into the host app is offered
71
+ // at agent handoff, so `componentsPath: "binary"` remains valid.
72
+ if (lib.id === "shadcn-react") {
73
+ lib.id = "shadcn-upstream";
74
+ }
75
+ return lib;
76
+ }
77
+
78
+ /**
79
+ * The typography records the typeset replaced. All four were declared, written
80
+ * by every preset, and read by nothing that painted — the sizes that actually
81
+ * rendered were literal utility classes. `TypographySchema` is strict now, so
82
+ * they have to go rather than linger as ignored keys.
83
+ *
84
+ * `fontWeight` and `letterSpacing` have no destination: both are per-role
85
+ * constants in the ratio table, deliberately not among the three controls.
86
+ */
87
+ const RETIRED_TYPOGRAPHY_KEYS = ["fontSize", "fontWeight", "lineHeight", "letterSpacing"] as const;
88
+
89
+ /**
90
+ * Font *role* names to bind each typeset face to, in preference order. A theme
91
+ * names its families freely, so rather than guess we look for the keys velloo's
92
+ * own scaffolds, wizard, and CSS import have always written.
93
+ */
94
+ const FACE_ROLE_CANDIDATES: Record<"fontBody" | "fontHeading" | "fontMono", string[]> = {
95
+ fontBody: ["sans", "body", "base"],
96
+ fontHeading: ["display", "heading", "serif"],
97
+ fontMono: ["mono", "code"],
98
+ };
99
+
100
+ /** The base size the ratio table already assumes, in px. */
101
+ const IMPLIED_BASE_PX = 16;
102
+
103
+ function asObject(value: unknown): RawObject | undefined {
104
+ return typeof value === "object" && value !== null && !Array.isArray(value)
105
+ ? (value as RawObject)
106
+ : undefined;
107
+ }
108
+
109
+ function positiveNumber(value: unknown): number | undefined {
110
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
111
+ }
112
+
113
+ /**
114
+ * Read a v2 theme's typography intent into a typeset. Only `fontSize.base` and
115
+ * `lineHeight.normal` carry over — the rest of both records described a ladder
116
+ * the typeset now derives, so restating any of it would freeze proportions that
117
+ * are supposed to move with the three controls.
118
+ */
119
+ function deriveTypeset(typography: RawObject): RawObject {
120
+ const derived: RawObject = {};
121
+
122
+ // 16px is what the ladder scales from anyway, so a folder that never tuned
123
+ // the base keeps the container-relative `1em` default instead of being pinned
124
+ // to an absolute size it never asked for.
125
+ const base = positiveNumber(asObject(typography.fontSize)?.base);
126
+ if (base !== undefined && base !== IMPLIED_BASE_PX) derived.size = base;
127
+
128
+ const leading = positiveNumber(asObject(typography.lineHeight)?.normal);
129
+ if (leading !== undefined) derived.leading = leading;
130
+
131
+ const families = asObject(typography.fontFamily);
132
+ if (families) {
133
+ for (const [face, candidates] of Object.entries(FACE_ROLE_CANDIDATES)) {
134
+ const role = candidates.find((name) => typeof families[name] === "string");
135
+ if (role) derived[face] = role;
136
+ }
137
+ }
138
+
139
+ return derived;
140
+ }
141
+
142
+ export const FOLDER_MIGRATIONS: FolderMigration[] = [
143
+ {
144
+ from: 1,
145
+ summary:
146
+ "multi-library config shape, source enum, shadcn-react → shadcn-upstream, required annotation author",
147
+ config(raw) {
148
+ const out = { ...raw };
149
+ if (out.library !== undefined && out.libraries === undefined) {
150
+ out.libraries = { [LEGACY_LIBRARY_KEY]: out.library };
151
+ out.defaultLibrary = LEGACY_LIBRARY_KEY;
152
+ }
153
+ delete out.library;
154
+ if (typeof out.libraries === "object" && out.libraries !== null) {
155
+ out.libraries = Object.fromEntries(
156
+ Object.entries(out.libraries as RawObject).map(([id, lib]) => [
157
+ id,
158
+ migrateLibraryEntry(lib),
159
+ ]),
160
+ );
161
+ }
162
+ out.schemaVersion = 2;
163
+ return out;
164
+ },
165
+ annotation(raw) {
166
+ if (raw.author === undefined) return { ...raw, author: "user" };
167
+ return raw;
168
+ },
169
+ },
170
+ {
171
+ from: 2,
172
+ summary:
173
+ "typography scales → typesets (font roles bound, dead size/weight/tracking records dropped)",
174
+ config(raw) {
175
+ return { ...raw, schemaVersion: 3 };
176
+ },
177
+ theme(raw) {
178
+ const typography = asObject(raw.typography);
179
+ if (!typography) return raw;
180
+ const next = { ...typography };
181
+
182
+ // Binding the font roles is the load-bearing half of this: without
183
+ // `fontBody` a migrated folder's typeset regions resolve to `inherit` and
184
+ // quietly stop using the theme's own faces.
185
+ const typesets = asObject(next.typesets);
186
+ if (typesets?.default === undefined) {
187
+ const derived = deriveTypeset(next);
188
+ if (Object.keys(derived).length > 0) {
189
+ next.typesets = { ...typesets, default: derived };
190
+ }
191
+ }
192
+
193
+ for (const key of RETIRED_TYPOGRAPHY_KEYS) delete next[key];
194
+ return { ...raw, typography: next };
195
+ },
196
+ },
197
+ ];
198
+
199
+ export interface MigrationRun {
200
+ /** The migrated raw config, ready for `ConfigSchema.parse`. */
201
+ config: RawObject;
202
+ /** Summaries of the steps that ran, in order. Empty ⇒ already current. */
203
+ applied: string[];
204
+ /**
205
+ * Per-annotation transform composed from the same steps — the CLI maps it
206
+ * over every entry of every `*.annotations.json` sidecar it finds.
207
+ */
208
+ annotation: (raw: RawObject) => RawObject;
209
+ /** Per-theme transform, applied to every `theme/<name>.json` in the folder. */
210
+ theme: (raw: RawObject) => RawObject;
211
+ }
212
+
213
+ /**
214
+ * Compose the migration chain from a folder's current version up to
215
+ * {@link CURRENT_SCHEMA_VERSION}. Throws when the folder is FROM THE FUTURE
216
+ * (version > current) — the caller should tell the user to upgrade velloo —
217
+ * or when the chain has a gap (a bug in this module).
218
+ */
219
+ export function planMigration(rawConfig: unknown): MigrationRun {
220
+ const from = schemaVersionOf(rawConfig);
221
+ if (from > CURRENT_SCHEMA_VERSION) {
222
+ throw new Error(
223
+ `Design folder uses schema version ${from}, newer than this velloo (v${CURRENT_SCHEMA_VERSION}). Upgrade velloo.`,
224
+ );
225
+ }
226
+ const steps: FolderMigration[] = [];
227
+ for (let v = from; v < CURRENT_SCHEMA_VERSION; v++) {
228
+ const step = FOLDER_MIGRATIONS.find((m) => m.from === v);
229
+ if (!step) throw new Error(`velloo: no migration step from schema version ${v} — bug.`);
230
+ steps.push(step);
231
+ }
232
+ let config = { ...((rawConfig ?? {}) as RawObject) };
233
+ for (const step of steps) {
234
+ if (step.config) config = step.config(config);
235
+ }
236
+ // Even a no-step run normalizes the version field so `upgrade` is idempotent.
237
+ config.schemaVersion = CURRENT_SCHEMA_VERSION;
238
+ return {
239
+ config,
240
+ applied: steps.map((s) => s.summary),
241
+ annotation: (raw) => steps.reduce((acc, step) => step.annotation?.(acc) ?? acc, raw),
242
+ theme: (raw) => steps.reduce((acc, step) => step.theme?.(acc) ?? acc, raw),
243
+ };
244
+ }