@usevyre/ai-context 0.2.0 → 0.2.2

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.
package/dist/tokens.md ADDED
@@ -0,0 +1,180 @@
1
+ # useVyre Token Reference for AI Agents
2
+ # Version: 0.1.2 | Generated: 2026-05-08
3
+ # Machine-readable version: @usevyre/tokens/ai (ai-tokens.json)
4
+
5
+ ## Usage
6
+
7
+ ```css
8
+ /* CSS */
9
+ @import "@usevyre/tokens/css";
10
+ color: var(--vyre-color-semantic-accent);
11
+ ```
12
+
13
+ ```ts
14
+ /* TypeScript/JS */
15
+ import { tokens, cssVar } from "@usevyre/tokens";
16
+ const accent = tokens["colorSemanticAccent"]; // resolved hex value
17
+ const css = cssVar("color-semantic-accent"); // "var(--vyre-color-semantic-accent)"
18
+ ```
19
+
20
+ ## Rules
21
+
22
+ 1. NEVER use primitive tokens (--vyre-color-primitive-*) in components — use semantic tokens instead.
23
+ 2. Semantic tokens adapt automatically to light/dark theme via [data-theme] attribute on <html>.
24
+ 3. For interactive hover states, use the -hover suffix variant of the token.
25
+ 4. For low-opacity backgrounds (badges, highlights), use -subtle suffix tokens.
26
+ 5. Text hierarchy: text-primary > text-secondary > text-muted > text-disabled.
27
+ 6. For text on accent/colored backgrounds, use text-inverse or accent-foreground.
28
+ 7. Import CSS: @import "@usevyre/tokens/css". Import JS: import { tokens } from "@usevyre/tokens".
29
+ 8. Use cssVar() helper to reference tokens in JS: cssVar('color-semantic-accent') → var(--vyre-color-semantic-accent).
30
+
31
+ ---
32
+
33
+ ## Semantic Color Tokens
34
+
35
+ These are the tokens to use in all component styling. They switch automatically between light/dark.
36
+
37
+ | CSS Variable | Description | Light | Dark | Usage |
38
+ |---|---|---|---|---|
39
+ | `--vyre-color-semantic-background` | Page/app background. Deepest layer. | `#ffffff` | `#09090b` | Page/app root background, Layout wrapper background |
40
+ | `--vyre-color-semantic-surface` | Cards, panels, sidebars. | `#fafafa` | `#18181b` | Card background, Panel background |
41
+ | `--vyre-color-semantic-surface-raised` | Dropdowns, popovers, elevated cards. | `#f4f4f5` | `#27272a` | Dropdown background, Popover background |
42
+ | `--vyre-color-semantic-surface-overlay` | Modals, tooltips, highest elevation. | `#ffffff` | `#333338` | Modal background, Tooltip background |
43
+ | `--vyre-color-semantic-border` | Default border for cards, inputs, dividers. | `#e4e4e7` | `#3f3f46` | Card border, Input border |
44
+ | `--vyre-color-semantic-border-subtle` | Very low contrast border. Section dividers. | `#ebebec` | `#27272a` | Section divider, Low-contrast rule between rows |
45
+ | `--vyre-color-semantic-border-strong` | Focused inputs, selected states. | `#a1a1aa` | `#71717a` | Input focus ring, Selected item border |
46
+ | `--vyre-color-semantic-text-primary` | Headings, body text, primary content. | `#09090b` | `#fafafa` | Heading text, Body copy |
47
+ | `--vyre-color-semantic-text-secondary` | Subtitles, descriptions, supporting text. | `#52525b` | `#d1d1d6` | Subtitle, Description text |
48
+ | `--vyre-color-semantic-text-muted` | Placeholders, timestamps, helper text. | `#a1a1aa` | `#71717a` | Placeholder text, Timestamp |
49
+ | `--vyre-color-semantic-text-disabled` | Disabled state text. | `#d1d1d6` | `#52525b` | Disabled input text, Greyed-out label |
50
+ | `--vyre-color-semantic-text-inverse` | Text on dark/accent backgrounds. | `#ffffff` | `#09090b` | Text on dark/accent background, Text inside accent-colored badge |
51
+ | `--vyre-color-semantic-accent` | Primary brand accent. CTAs, highlights, focus rings. | `#7c3aed` | `#a78bfa` | Button primary background, Link active state |
52
+ | `--vyre-color-semantic-accent-hover` | Hover state for accent elements. | `#6d28d9` | `#c4b5fd` | Button primary hover state |
53
+ | `--vyre-color-semantic-accent-foreground` | Text color on accent background. | `#ffffff` | `#09090b` | Text/icon on accent-colored background |
54
+ | `--vyre-color-semantic-accent-subtle` | Low-opacity accent for badge backgrounds, highlights. | `#f5f3ff` | `rgba(139, 92, 246, 0.12)` | Accent badge background, Highlighted row background |
55
+ | `--vyre-color-semantic-accent-subtle-border` | Border for accent subtle containers. | `#ddd6fe` | `rgba(139, 92, 246, 0.25)` | Border of accent-subtle containers |
56
+ | `--vyre-color-semantic-teal` | Secondary accent. Code, AI-context indicators. | `#14b8a6` | `#2dd4bf` | Button teal variant, Code block accent |
57
+ | `--vyre-color-semantic-teal-hover` | Hover state for teal elements. | `#0d9488` | `#5eead4` | Teal button hover state |
58
+ | `--vyre-color-semantic-teal-subtle` | Low-opacity teal for badge backgrounds. | `rgba(20, 184, 166, 0.08)` | `rgba(45, 212, 191, 0.10)` | Teal badge background |
59
+ | `--vyre-color-semantic-success` | Success states, confirmations. | `#16a34a` | `#4ade80` | Success alert icon/text, Toast success border-left |
60
+ | `--vyre-color-semantic-success-subtle` | Success badge background. | `#f0fdf4` | `rgba(74, 222, 128, 0.10)` | Success alert background, Success badge background |
61
+ | `--vyre-color-semantic-success-subtle-border` | Border for success subtle containers. | `#dcfce7` | `rgba(74, 222, 128, 0.20)` | Success alert border |
62
+ | `--vyre-color-semantic-warning` | Warning states, beta indicators. | `#f59e0b` | `#fbbf24` | Warning alert icon/text, Toast warning border-left |
63
+ | `--vyre-color-semantic-warning-subtle` | Warning badge background. | `#fffbeb` | `rgba(251, 191, 36, 0.10)` | Warning alert background, Warning badge background |
64
+ | `--vyre-color-semantic-warning-subtle-border` | Border for warning subtle containers. | `#fef3c7` | `rgba(251, 191, 36, 0.20)` | Warning alert border |
65
+ | `--vyre-color-semantic-danger` | Error states, destructive actions. | `#dc2626` | `#f87171` | Button danger variant, Error alert icon/text |
66
+ | `--vyre-color-semantic-danger-hover` | Hover state for danger elements. | `#ef4444` | `#ef4444` | Danger button hover state |
67
+ | `--vyre-color-semantic-danger-subtle` | Error badge background. | `#fef2f2` | `rgba(248, 113, 113, 0.10)` | Error alert background, Danger badge background |
68
+ | `--vyre-color-semantic-danger-subtle-border` | Border for danger subtle containers. | `#fee2e2` | `rgba(248, 113, 113, 0.20)` | Error alert border |
69
+
70
+ ---
71
+
72
+ ## Spacing (4px grid)
73
+
74
+ | CSS Variable | Value | Notes |
75
+ |---|---|---|
76
+ | `--vyre-spacing-0` | `0` | |
77
+ | `--vyre-spacing-1` | `0.25rem` | 4px |
78
+ | `--vyre-spacing-2` | `0.5rem` | 8px |
79
+ | `--vyre-spacing-3` | `0.75rem` | 12px |
80
+ | `--vyre-spacing-4` | `1rem` | 16px |
81
+ | `--vyre-spacing-5` | `1.25rem` | 20px |
82
+ | `--vyre-spacing-6` | `1.5rem` | 24px |
83
+ | `--vyre-spacing-8` | `2rem` | 32px |
84
+ | `--vyre-spacing-10` | `2.5rem` | 40px |
85
+ | `--vyre-spacing-12` | `3rem` | 48px |
86
+ | `--vyre-spacing-16` | `4rem` | 64px |
87
+ | `--vyre-spacing-20` | `5rem` | 80px |
88
+ | `--vyre-spacing-24` | `6rem` | 96px |
89
+
90
+ ---
91
+
92
+ ## Border Radius
93
+
94
+ | CSS Variable | Value | Notes |
95
+ |---|---|---|
96
+ | `--vyre-border-radius-none` | `0` | |
97
+ | `--vyre-border-radius-sm` | `0.375rem` | 6px. Tight corners. |
98
+ | `--vyre-border-radius-md` | `0.5rem` | 8px. Default component radius. |
99
+ | `--vyre-border-radius-lg` | `0.75rem` | 12px. Cards, panels. |
100
+ | `--vyre-border-radius-xl` | `1rem` | 16px. Large cards. |
101
+ | `--vyre-border-radius-2xl` | `1.5rem` | 24px. Modals, sheets. |
102
+ | `--vyre-border-radius-full` | `9999px` | Badges, pills, avatars. |
103
+
104
+ ---
105
+
106
+ ## Typography — Font Sizes
107
+
108
+ | CSS Variable | Value | Notes |
109
+ |---|---|---|
110
+ | `--vyre-typography-font-size-2xs` | `0.625rem` | 10px. Tiny labels only. |
111
+ | `--vyre-typography-font-size-xs` | `0.6875rem` | 11px. Badge text, captions. |
112
+ | `--vyre-typography-font-size-sm` | `0.8125rem` | 13px. Default UI text, buttons. |
113
+ | `--vyre-typography-font-size-md` | `0.9375rem` | 15px. Body text. |
114
+ | `--vyre-typography-font-size-lg` | `1.125rem` | 18px. Large body, small headings. |
115
+ | `--vyre-typography-font-size-xl` | `1.375rem` | 22px. Section headings. |
116
+ | `--vyre-typography-font-size-2xl` | `1.75rem` | 28px. Page headings. |
117
+ | `--vyre-typography-font-size-3xl` | `2.25rem` | 36px. Large headings. |
118
+ | `--vyre-typography-font-size-4xl` | `3rem` | 48px. Hero headings. |
119
+ | `--vyre-typography-font-size-5xl` | `4rem` | 64px. Display headings. |
120
+
121
+ **Font weights:** light (300), regular (400), medium (500), semibold (600), bold (700)
122
+ Use `--vyre-typography-font-weight-[name]`.
123
+
124
+ **Font families:**
125
+ - Display/Body: `--vyre-typography-font-family-display` / `--vyre-typography-font-family-body` → Geist, Inter, system-ui
126
+ - Mono: `--vyre-typography-font-family-mono` → Geist Mono, JetBrains Mono
127
+
128
+ ---
129
+
130
+ ## Shadows
131
+
132
+ | CSS Variable | Notes |
133
+ |---|---|
134
+ | `--vyre-shadow-sm` | — |
135
+ | `--vyre-shadow-md` | — |
136
+ | `--vyre-shadow-lg` | — |
137
+ | `--vyre-shadow-xl` | — |
138
+ | `--vyre-shadow-sm-dark` | — |
139
+ | `--vyre-shadow-md-dark` | — |
140
+ | `--vyre-shadow-lg-dark` | — |
141
+ | `--vyre-shadow-xl-dark` | — |
142
+ | `--vyre-shadow-glow-accent` | — |
143
+ | `--vyre-shadow-glow-teal` | — |
144
+
145
+ Use `-dark` variants inside `[data-theme="dark"]`. `glow-accent` and `glow-teal` for focus glows.
146
+
147
+ ---
148
+
149
+ ## Transitions — Duration
150
+
151
+ | CSS Variable | Value |
152
+ |---|---|
153
+ | `--vyre-transition-duration-instant` | `80ms` |
154
+ | `--vyre-transition-duration-fast` | `120ms` |
155
+ | `--vyre-transition-duration-normal` | `200ms` |
156
+ | `--vyre-transition-duration-slow` | `350ms` |
157
+
158
+ **Easing:** `--vyre-transition-easing-out` (default), `-in`, `-inout`, `-spring` (bounce)
159
+
160
+ ---
161
+
162
+ ## Z-Index Scale
163
+
164
+ | CSS Variable | Value | Layer |
165
+ |---|---|---|
166
+ | `--vyre-z-index-base` | `0` | |
167
+ | `--vyre-z-index-raised` | `10` | |
168
+ | `--vyre-z-index-sticky` | `100` | |
169
+ | `--vyre-z-index-overlay` | `200` | |
170
+ | `--vyre-z-index-modal` | `1000` | |
171
+ | `--vyre-z-index-toast` | `2000` | |
172
+
173
+ ---
174
+
175
+ ## Common Mistakes
176
+
177
+ - ❌ Using raw hex values → ✅ Use `var(--vyre-color-semantic-accent)`
178
+ - ❌ `--vyre-color-primitive-violet-600` in a component → ✅ `--vyre-color-semantic-accent`
179
+ - ❌ Custom z-index numbers → ✅ Use `var(--vyre-z-index-modal)`
180
+ - ❌ Hardcoded px spacing → ✅ Use `var(--vyre-spacing-4)` (= 16px)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "0.2.0",
3
3
  "packageVersion": "0.1.1",
4
- "generatedAt": "2026-05-08T05:29:53.473Z",
4
+ "generatedAt": "2026-05-08T13:45:17.100Z",
5
5
  "validFor": [
6
6
  "@usevyre/react@0.1.1+",
7
7
  "@usevyre/vue@0.1.1+"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usevyre/ai-context",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "useVyre AI context — inject into LLM system prompts to eliminate UI hallucinations",
5
5
  "keywords": [
6
6
  "design-system",
@@ -26,11 +26,17 @@
26
26
  "./schema": "./dist/schema.json",
27
27
  "./anti-patterns": "./dist/anti-patterns.json",
28
28
  "./version-info": "./dist/version-info.json",
29
- "./cheat-sheets": "./dist/cheat-sheets/index.md"
29
+ "./cheat-sheets": "./dist/cheat-sheets/index.md",
30
+ "./tokens": "./dist/tokens.json",
31
+ "./tokens-md": "./dist/tokens.md"
30
32
  },
31
33
  "files": [
32
- "dist"
34
+ "dist",
35
+ "scripts"
33
36
  ],
37
+ "bin": {
38
+ "usevyre-ai-context": "./scripts/init.js"
39
+ },
34
40
  "scripts": {
35
41
  "build": "node scripts/build.js",
36
42
  "clean": "rm -rf dist"
@@ -0,0 +1,442 @@
1
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
2
+ import { resolve, dirname } from "path";
3
+ import { fileURLToPath } from "url";
4
+
5
+ const __dirname = dirname(fileURLToPath(import.meta.url));
6
+ const root = resolve(__dirname, "..");
7
+ const src = resolve(root, "src");
8
+ const dist = resolve(root, "dist");
9
+
10
+ mkdirSync(dist, { recursive: true });
11
+
12
+ // ── Load source data ──────────────────────────────────────────────────────────
13
+
14
+ const schema = JSON.parse(readFileSync(resolve(src, "schema/components.json"), "utf8"));
15
+ const staticContext = readFileSync(resolve(src, "full-context.md"), "utf8");
16
+
17
+ // Load AI tokens from @usevyre/tokens (sibling package in monorepo)
18
+ const tokensDistPath = resolve(__dirname, "../../tokens/dist/ai-tokens.json");
19
+ const tokensMDPath = resolve(__dirname, "../../tokens/dist/ai-tokens.md");
20
+ const aiTokens = existsSync(tokensDistPath) ? JSON.parse(readFileSync(tokensDistPath, "utf8")) : null;
21
+ const aiTokensMD = existsSync(tokensMDPath) ? readFileSync(tokensMDPath, "utf8") : null;
22
+
23
+ // ── Helpers ───────────────────────────────────────────────────────────────────
24
+
25
+ function buildComponentSection(name, comp) {
26
+ const lines = [];
27
+
28
+ lines.push(`### ${name}`);
29
+ lines.push("");
30
+ lines.push(comp.description);
31
+ lines.push("");
32
+
33
+ lines.push("```tsx");
34
+ lines.push(comp.import);
35
+ lines.push("");
36
+
37
+ const props = comp.props || {};
38
+ const propNames = Object.keys(props);
39
+ if (propNames.length > 0) {
40
+ lines.push("// Props:");
41
+ for (const [propName, prop] of Object.entries(props)) {
42
+ const vals = prop.values ? `"${prop.values.join('" | "')}"` : prop.type;
43
+ const def = prop.default !== undefined ? ` (default: ${prop.default})` : "";
44
+ lines.push(`// ${propName.padEnd(14)} = ${vals}${def}`);
45
+ }
46
+ lines.push("");
47
+ }
48
+
49
+ if (comp.examples?.length) {
50
+ lines.push("// Examples:");
51
+ for (const ex of comp.examples) {
52
+ lines.push(ex.code);
53
+ }
54
+ }
55
+
56
+ lines.push("```");
57
+ lines.push("");
58
+
59
+ if (comp.antiPatterns?.length) {
60
+ lines.push("**Common mistakes:**");
61
+ for (const ap of comp.antiPatterns) {
62
+ lines.push(`- ❌ \`${ap.pattern}\` → ${ap.fix}`);
63
+ }
64
+ lines.push("");
65
+ }
66
+
67
+ return lines.join("\n");
68
+ }
69
+
70
+ function buildCursorRulesSection(name, comp) {
71
+ const lines = [];
72
+ lines.push(`## ${name}`);
73
+ lines.push(comp.description);
74
+
75
+ // Extract package name from import string
76
+ const pkgMatch = comp.import.match(/"([^"]+)"/);
77
+ const pkg = pkgMatch ? pkgMatch[1] : "@usevyre/react";
78
+ const symbolMatch = comp.import.match(/import \{([^}]+)\}/);
79
+ const symbols = symbolMatch ? symbolMatch[1].trim() : name;
80
+ lines.push(`Import: \`import { ${symbols} } from "${pkg}"\``);
81
+ lines.push("");
82
+
83
+ const props = comp.props || {};
84
+ if (Object.keys(props).length > 0) {
85
+ lines.push("Valid props:");
86
+ for (const [propName, prop] of Object.entries(props)) {
87
+ if (prop.values) {
88
+ const def = prop.default !== undefined ? ` [default: ${prop.default}]` : "";
89
+ lines.push(`- ${propName}: ${prop.values.map(v => `"${v}"`).join(" | ")}${def}`);
90
+ }
91
+ }
92
+ lines.push("");
93
+ }
94
+
95
+ if (comp.antiPatterns?.length) {
96
+ lines.push("Never do:");
97
+ for (const ap of comp.antiPatterns) {
98
+ lines.push(`- ❌ ${ap.pattern} → ✅ ${ap.fix}`);
99
+ }
100
+ lines.push("");
101
+ }
102
+
103
+ return lines.join("\n");
104
+ }
105
+
106
+ // ── Generate component sections from schema ───────────────────────────────────
107
+
108
+ const componentSections = Object.entries(schema.components)
109
+ .map(([name, comp]) => buildComponentSection(name, comp))
110
+ .join("\n---\n\n");
111
+
112
+ const cursorSections = Object.entries(schema.components)
113
+ .map(([name, comp]) => buildCursorRulesSection(name, comp))
114
+ .join("\n");
115
+
116
+ // Collect all anti-patterns for hallucination guard section
117
+ const allAntiPatterns = Object.entries(schema.components).flatMap(([name, comp]) =>
118
+ (comp.antiPatterns || []).map(ap => ({ component: name, ...ap }))
119
+ );
120
+
121
+ const antiPatternBlock = allAntiPatterns
122
+ .map(ap => `- ❌ \`<${ap.component} ${ap.pattern}>\` → ${ap.fix}`)
123
+ .join("\n");
124
+
125
+ // ── Build full-context.md (schema-driven component section, static tokens/rules) ──
126
+
127
+ // Split static content at the Component API Reference section boundary
128
+ const splitMarker = "## Component API Reference";
129
+ const stylingMarker = "## Styling Rules for AI Agents";
130
+
131
+ const staticUpToComponents = staticContext.includes(splitMarker)
132
+ ? staticContext.split(splitMarker)[0].trimEnd()
133
+ : staticContext.split(stylingMarker)[0].trimEnd();
134
+
135
+ const staticStylingOnward = staticContext.includes(stylingMarker)
136
+ ? staticContext.split(stylingMarker)[1].trimStart()
137
+ : "";
138
+
139
+ const generatedFullContext = [
140
+ staticUpToComponents,
141
+ "",
142
+ "## Component API Reference",
143
+ "",
144
+ componentSections,
145
+ "---",
146
+ "",
147
+ "## Hallucination Guard — Common AI Mistakes",
148
+ "",
149
+ "The following prop values and patterns do NOT exist in useVyre.",
150
+ "If you generate these, you are hallucinating.",
151
+ "",
152
+ antiPatternBlock,
153
+ "",
154
+ "---",
155
+ "",
156
+ "## Styling Rules for AI Agents",
157
+ "",
158
+ staticStylingOnward,
159
+ ].join("\n");
160
+
161
+ // Write back to src so full-context.md stays in sync (schema is source of truth for components)
162
+ writeFileSync(resolve(src, "full-context.md"), generatedFullContext);
163
+ writeFileSync(resolve(dist, "full-context.md"), generatedFullContext);
164
+
165
+ // ── cursor-rules.md ───────────────────────────────────────────────────────────
166
+
167
+ const cursorRules = [
168
+ "---",
169
+ "description: useVyre design system rules — follow these when writing UI code",
170
+ "alwaysApply: true",
171
+ "---",
172
+ "",
173
+ "# useVyre Design System — Cursor Rules",
174
+ "# Version: " + schema.version,
175
+ "",
176
+ "You are working in a project using the useVyre design system (@usevyre/react).",
177
+ "Follow these rules strictly when generating any UI code.",
178
+ "",
179
+ "## Critical Rules",
180
+ "- NEVER use color/size values that are not in the valid prop lists below",
181
+ "- ALWAYS use semantic tokens (--vyre-color-semantic-*), never hardcode colors",
182
+ "- ALWAYS add aria-label to Button size=\"icon\" (no visible text)",
183
+ "- NEVER render <Toast> directly — use useToast() hook",
184
+ "- NEVER use <Input type=\"search\"> for search UI — use Command component",
185
+ "",
186
+ "## Component Rules",
187
+ "",
188
+ cursorSections,
189
+ "## Token Rules",
190
+ "",
191
+ "Use --vyre-color-semantic-* for all colors. Never use primitive tokens.",
192
+ "Use --vyre-spacing-* for all spacing. Never use raw px in component code.",
193
+ "Use --vyre-border-radius-* for border radius.",
194
+ ].join("\n");
195
+
196
+ writeFileSync(resolve(dist, "cursor-rules.md"), cursorRules);
197
+
198
+ // ── claude-context.md ─────────────────────────────────────────────────────────
199
+
200
+ const claudeContext = [
201
+ "# useVyre Design System Context",
202
+ "# Version: " + schema.version,
203
+ "",
204
+ "You are working in a codebase that uses the useVyre design system.",
205
+ "Follow the rules below strictly when writing any UI code.",
206
+ "",
207
+ generatedFullContext,
208
+ ].join("\n");
209
+
210
+ writeFileSync(resolve(dist, "claude-context.md"), claudeContext);
211
+
212
+ // ── windsurf-rules.md ─────────────────────────────────────────────────────────
213
+
214
+ const windsurfRules = [
215
+ "# useVyre Rules for Windsurf",
216
+ "# Version: " + schema.version,
217
+ "",
218
+ generatedFullContext,
219
+ ].join("\n");
220
+
221
+ writeFileSync(resolve(dist, "windsurf-rules.md"), windsurfRules);
222
+
223
+ // ── copilot-instructions.md ───────────────────────────────────────────────────
224
+
225
+ const copilotInstructions = [
226
+ "# useVyre Copilot Instructions",
227
+ "# Version: " + schema.version,
228
+ "",
229
+ "When generating UI code in this project, follow the useVyre design system rules below.",
230
+ "",
231
+ generatedFullContext,
232
+ ].join("\n");
233
+
234
+ writeFileSync(resolve(dist, "copilot-instructions.md"), copilotInstructions);
235
+
236
+ // ── schema.json — machine-readable component schema ───────────────────────────
237
+
238
+ writeFileSync(resolve(dist, "schema.json"), JSON.stringify(schema, null, 2));
239
+
240
+ // ── version-info.json — 1.4 AI Context Versioning ────────────────────────────
241
+
242
+ const versionInfo = {
243
+ version: schema.version,
244
+ packageVersion: schema.packageVersion ?? "0.1.1",
245
+ generatedAt: new Date().toISOString(),
246
+ validFor: schema.validFor ?? [],
247
+ changelog: schema.changelog ?? {},
248
+ components: Object.fromEntries(
249
+ Object.entries(schema.components).map(([name, comp]) => [
250
+ name,
251
+ {
252
+ version: comp.meta?.version ?? schema.packageVersion ?? "0.1.1",
253
+ lastUpdated: comp.meta?.lastUpdated ?? schema.generatedAt,
254
+ breaking: comp.meta?.breaking ?? false,
255
+ stable: comp.meta?.stable ?? true,
256
+ changelog: comp.meta?.changelog ?? null,
257
+ },
258
+ ])
259
+ ),
260
+ };
261
+
262
+ writeFileSync(resolve(dist, "version-info.json"), JSON.stringify(versionInfo, null, 2));
263
+
264
+ // ── cheat-sheets/ — 2.1 per-component AI Cheat Sheet (markdown) ──────────────
265
+
266
+ const cheatSheetsDir = resolve(dist, "cheat-sheets");
267
+ mkdirSync(cheatSheetsDir, { recursive: true });
268
+
269
+ function buildCheatSheet(name, comp) {
270
+ const props = comp.props ?? {};
271
+ const enumProps = Object.entries(props).filter(([, p]) => p.values);
272
+ const boolProps = Object.entries(props).filter(([, p]) => p.type === "boolean");
273
+
274
+ const lines = [];
275
+ lines.push(`# ${name} — AI Cheat Sheet`);
276
+ lines.push(`> Quick reference for Claude / Cursor / Copilot`);
277
+ lines.push("");
278
+ lines.push(`**${comp.description}**`);
279
+ lines.push("");
280
+ lines.push(`\`\`\`ts`);
281
+ lines.push(comp.import);
282
+ lines.push(`\`\`\``);
283
+ lines.push("");
284
+
285
+ if (enumProps.length > 0 || boolProps.length > 0) {
286
+ lines.push("## Valid Props");
287
+ lines.push("");
288
+ lines.push("| Prop | Values | Default |");
289
+ lines.push("|------|--------|---------|");
290
+ for (const [propName, prop] of enumProps) {
291
+ const vals = prop.values.map(v => `\`"${v}"\``).join(" \\| ");
292
+ const def = prop.default !== undefined ? `\`${prop.default}\`` : "—";
293
+ lines.push(`| \`${propName}\` | ${vals} | ${def} |`);
294
+ }
295
+ for (const [propName, prop] of boolProps) {
296
+ const def = prop.default !== undefined ? `\`${prop.default}\`` : "—";
297
+ lines.push(`| \`${propName}\` | \`true\` \\| \`false\` | ${def} |`);
298
+ }
299
+ lines.push("");
300
+ }
301
+
302
+ if (comp.antiPatterns?.length) {
303
+ lines.push("## Common AI Mistakes");
304
+ lines.push("");
305
+ for (const ap of comp.antiPatterns) {
306
+ lines.push(`- ❌ \`${ap.pattern}\``);
307
+ lines.push(` → ${ap.fix}`);
308
+ }
309
+ lines.push("");
310
+ }
311
+
312
+ if (comp.examples?.length) {
313
+ lines.push("## Examples");
314
+ lines.push("");
315
+ for (const ex of comp.examples) {
316
+ lines.push(`**${ex.description}**`);
317
+ lines.push("```tsx");
318
+ lines.push(ex.code);
319
+ lines.push("```");
320
+ lines.push("");
321
+ }
322
+ }
323
+
324
+ if (comp.accessibility?.notes?.length) {
325
+ lines.push("## Accessibility");
326
+ lines.push("");
327
+ for (const note of comp.accessibility.notes) {
328
+ lines.push(`- ${note}`);
329
+ }
330
+ lines.push("");
331
+ }
332
+
333
+ return lines.join("\n");
334
+ }
335
+
336
+ // Index of all cheat sheets
337
+ const cheatSheetIndex = ["# useVyre Component Cheat Sheets", "", "Quick reference for AI agents — one file per component.", ""];
338
+
339
+ for (const [name, comp] of Object.entries(schema.components)) {
340
+ const content = buildCheatSheet(name, comp);
341
+ const filename = `${name.toLowerCase()}.md`;
342
+ writeFileSync(resolve(cheatSheetsDir, filename), content);
343
+ cheatSheetIndex.push(`- [${name}](${filename}) — ${comp.description}`);
344
+ }
345
+
346
+ writeFileSync(resolve(cheatSheetsDir, "index.md"), cheatSheetIndex.join("\n") + "\n");
347
+
348
+ // ── anti-patterns.json — hallucination guard, usable by ESLint/validate CLI ──
349
+
350
+ const antiPatternsExport = {
351
+ version: schema.version,
352
+ rules: allAntiPatterns.map(ap => ({
353
+ component: ap.component,
354
+ pattern: ap.pattern,
355
+ reason: ap.reason,
356
+ fix: ap.fix,
357
+ severity: ap.severity ?? "error",
358
+ })),
359
+ };
360
+
361
+ writeFileSync(resolve(dist, "anti-patterns.json"), JSON.stringify(antiPatternsExport, null, 2));
362
+
363
+ // ── index.js — JS entry exporting all context strings + structured data ───────
364
+
365
+ const escape = (s) => s.replace(/`/g, "\\`").replace(/\$/g, "\\$");
366
+
367
+ // Build cheat sheets map for index.js export
368
+ const cheatSheetsMap = Object.fromEntries(
369
+ Object.entries(schema.components).map(([name, comp]) => [name, buildCheatSheet(name, comp)])
370
+ );
371
+
372
+ const indexContent = [
373
+ `// @usevyre/ai-context v${schema.version}`,
374
+ `// Auto-generated — do not edit directly. Edit src/schema/components.json instead.`,
375
+ "",
376
+ `export const version = "${schema.version}";`,
377
+ "",
378
+ `export const fullContext = \`${escape(generatedFullContext)}\`;`,
379
+ `export const cursorRules = \`${escape(cursorRules)}\`;`,
380
+ `export const claudeContext = \`${escape(claudeContext)}\`;`,
381
+ `export const windsurfRules = \`${escape(windsurfRules)}\`;`,
382
+ `export const copilotInstructions = \`${escape(copilotInstructions)}\`;`,
383
+ "",
384
+ `export const schema = ${JSON.stringify(schema, null, 2)};`,
385
+ "",
386
+ `export const antiPatterns = ${JSON.stringify(antiPatternsExport, null, 2)};`,
387
+ "",
388
+ `export const versionInfo = ${JSON.stringify(versionInfo, null, 2)};`,
389
+ "",
390
+ `export const cheatSheets = ${JSON.stringify(cheatSheetsMap, null, 2)};`,
391
+ "",
392
+ ].join("\n");
393
+
394
+ writeFileSync(resolve(dist, "index.js"), indexContent);
395
+
396
+ // ── Copy AI tokens from @usevyre/tokens ──────────────────────────────────────
397
+
398
+ if (aiTokens) {
399
+ writeFileSync(resolve(dist, "tokens.json"), JSON.stringify(aiTokens, null, 2));
400
+ }
401
+ if (aiTokensMD) {
402
+ writeFileSync(resolve(dist, "tokens.md"), aiTokensMD);
403
+ }
404
+
405
+ // ── Update package.json exports to include new files ─────────────────────────
406
+
407
+ const pkg = JSON.parse(readFileSync(resolve(root, "package.json"), "utf8"));
408
+ pkg.exports = {
409
+ ".": "./dist/index.js",
410
+ "./cursor": "./dist/cursor-rules.md",
411
+ "./claude": "./dist/claude-context.md",
412
+ "./windsurf": "./dist/windsurf-rules.md",
413
+ "./copilot": "./dist/copilot-instructions.md",
414
+ "./full": "./dist/full-context.md",
415
+ "./schema": "./dist/schema.json",
416
+ "./anti-patterns": "./dist/anti-patterns.json",
417
+ "./version-info": "./dist/version-info.json",
418
+ "./cheat-sheets": "./dist/cheat-sheets/index.md",
419
+ "./tokens": "./dist/tokens.json",
420
+ "./tokens-md": "./dist/tokens.md",
421
+ };
422
+ writeFileSync(resolve(root, "package.json"), JSON.stringify(pkg, null, 2) + "\n");
423
+
424
+ // ── Summary ───────────────────────────────────────────────────────────────────
425
+
426
+ const componentCount = Object.keys(schema.components).length;
427
+ const antiPatternCount = allAntiPatterns.length;
428
+
429
+ console.log(`@usevyre/ai-context v${schema.version} built successfully`);
430
+ console.log(` ${componentCount} components · ${antiPatternCount} anti-patterns`);
431
+ console.log(` dist/schema.json`);
432
+ console.log(` dist/anti-patterns.json`);
433
+ console.log(` dist/version-info.json`);
434
+ console.log(` dist/cheat-sheets/ (${componentCount} files + index.md)`);
435
+ console.log(` dist/full-context.md`);
436
+ console.log(` dist/cursor-rules.md`);
437
+ console.log(` dist/claude-context.md`);
438
+ console.log(` dist/windsurf-rules.md`);
439
+ console.log(` dist/copilot-instructions.md`);
440
+ console.log(` dist/tokens.json — AI token reference (from @usevyre/tokens)`);
441
+ console.log(` dist/tokens.md — AI token reference markdown`);
442
+ console.log(` dist/index.js`);