@texturehq/edges 1.7.1 → 1.7.3
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/components.manifest.json +914 -1406
- package/dist/index.cjs +9 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +98 -275
- package/dist/index.d.ts +98 -275
- package/dist/index.js +9 -9
- package/dist/index.js.map +1 -1
- package/dist/{server-DAd0A202.d.cts → server-7ZzifHri.d.cts} +191 -8
- package/dist/{server-DAd0A202.d.ts → server-7ZzifHri.d.ts} +191 -8
- package/dist/server.cjs +13 -13
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +13 -13
- package/dist/server.js.map +1 -1
- package/dist/styles.css +5 -16
- package/dist/utilities.manifest.json +4 -1039
- package/package.json +2 -2
- package/scripts/generate-edges-docs.js +970 -0
- package/scripts/setup-cursor-rules.js +18 -0
- package/scripts/generate-components-manifest.js +0 -188
- package/scripts/generate-utilities-manifest.js +0 -392
|
@@ -0,0 +1,970 @@
|
|
|
1
|
+
// generate-edges-docs.js
|
|
2
|
+
// Unified AI Context Generator for @texturehq/edges
|
|
3
|
+
//
|
|
4
|
+
// Consolidates and enhances:
|
|
5
|
+
// - generate-components-manifest.js
|
|
6
|
+
// - generate-utilities-manifest.js
|
|
7
|
+
//
|
|
8
|
+
// Generates:
|
|
9
|
+
// - Component, utility, and hook manifests
|
|
10
|
+
// - docs/ai/edges/ markdown documentation
|
|
11
|
+
// - .agent-fragments/edges.md (for merging with other fragments)
|
|
12
|
+
// - .cursor/rules/edges-components.mdc
|
|
13
|
+
// - Distributable context files for consuming apps
|
|
14
|
+
|
|
15
|
+
import { execSync } from "child_process";
|
|
16
|
+
import fs from "fs";
|
|
17
|
+
import path from "path";
|
|
18
|
+
|
|
19
|
+
const ROOT = process.cwd();
|
|
20
|
+
const SRC_DIR = path.join(ROOT, "src");
|
|
21
|
+
const DIST_DIR = path.join(ROOT, "dist");
|
|
22
|
+
const MONO_ROOT = path.join(ROOT, "../..");
|
|
23
|
+
const DOCS_AI_EDGES = path.join(MONO_ROOT, "docs/ai/edges");
|
|
24
|
+
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// UTILITIES
|
|
27
|
+
// ============================================================================
|
|
28
|
+
|
|
29
|
+
function read(file) {
|
|
30
|
+
return fs.existsSync(file) ? fs.readFileSync(file, "utf8") : "";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function ensureDir(dir) {
|
|
34
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function writeFile(filePath, content) {
|
|
38
|
+
ensureDir(path.dirname(filePath));
|
|
39
|
+
fs.writeFileSync(filePath, content, "utf8");
|
|
40
|
+
console.log(`✓ Generated: ${filePath}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// COMPONENT MANIFEST GENERATION
|
|
45
|
+
// ============================================================================
|
|
46
|
+
|
|
47
|
+
function extractExportsFromIndex(indexContent) {
|
|
48
|
+
const re = /export\s+\{\s*([A-Za-z0-9_,\s]+)\s*\}\s+from\s+"\.\/components\/([A-Za-z0-9_/.-]+)"/g;
|
|
49
|
+
const results = [];
|
|
50
|
+
let m;
|
|
51
|
+
while ((m = re.exec(indexContent))) {
|
|
52
|
+
const exported = m[1]
|
|
53
|
+
.split(",")
|
|
54
|
+
.map((s) => s.trim())
|
|
55
|
+
.filter(Boolean);
|
|
56
|
+
const rel = m[2];
|
|
57
|
+
for (const name of exported) {
|
|
58
|
+
results.push({ name, relPath: rel });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return results;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function findComponentFile(relPath) {
|
|
65
|
+
const base = path.join(SRC_DIR, "components", relPath);
|
|
66
|
+
const componentName = relPath.split("/").pop();
|
|
67
|
+
const candidates = [
|
|
68
|
+
path.join(base, `${componentName}.tsx`),
|
|
69
|
+
path.join(base, `${componentName}.ts`),
|
|
70
|
+
path.join(base, `index.tsx`),
|
|
71
|
+
path.join(base, `index.ts`),
|
|
72
|
+
];
|
|
73
|
+
for (const f of candidates) {
|
|
74
|
+
if (fs.existsSync(f)) return f;
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function findStorybookFile(relPath) {
|
|
80
|
+
const base = path.join(SRC_DIR, "components", relPath);
|
|
81
|
+
const componentName = relPath.split("/").pop();
|
|
82
|
+
const candidates = [path.join(base, `${componentName}.stories.tsx`), path.join(base, `${componentName}.stories.ts`)];
|
|
83
|
+
for (const f of candidates) {
|
|
84
|
+
if (fs.existsSync(f)) return f;
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function extractStorybookCategory(storyContent) {
|
|
90
|
+
// Extract: title: "Form Controls/Button"
|
|
91
|
+
const titleMatch = storyContent.match(/title:\s*["']([^"']+)["']/);
|
|
92
|
+
if (titleMatch) {
|
|
93
|
+
const fullTitle = titleMatch[1];
|
|
94
|
+
const parts = fullTitle.split("/");
|
|
95
|
+
if (parts.length > 1) {
|
|
96
|
+
return parts[0]; // "Form Controls"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function extractRelatedComponents(storyContent) {
|
|
103
|
+
// Find other component imports in the story file
|
|
104
|
+
const importMatch = storyContent.match(/import\s*\{([^}]+)\}\s*from\s*["']\.\.\/(\w+)["']/g);
|
|
105
|
+
const related = new Set();
|
|
106
|
+
if (importMatch) {
|
|
107
|
+
for (const imp of importMatch) {
|
|
108
|
+
const m = imp.match(/import\s*\{([^}]+)\}/);
|
|
109
|
+
if (m) {
|
|
110
|
+
const imports = m[1].split(",").map((s) => s.trim());
|
|
111
|
+
for (const name of imports) {
|
|
112
|
+
if (/^[A-Z]/.test(name)) {
|
|
113
|
+
related.add(name);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return Array.from(related);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function getJsdocAbove(content, idx) {
|
|
123
|
+
const upTo = content.slice(0, idx);
|
|
124
|
+
const start = upTo.lastIndexOf("/**");
|
|
125
|
+
const end = upTo.lastIndexOf("*/");
|
|
126
|
+
if (start !== -1 && end !== -1 && end > start) {
|
|
127
|
+
const block = upTo.slice(start + 3, end).trim();
|
|
128
|
+
return block
|
|
129
|
+
.split("\n")
|
|
130
|
+
.map((l) => l.replace(/^\s*\*\s?/, "").trim())
|
|
131
|
+
.join(" ")
|
|
132
|
+
.trim();
|
|
133
|
+
}
|
|
134
|
+
return "";
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function extractProps(content, componentName) {
|
|
138
|
+
const ifaceRe = new RegExp(
|
|
139
|
+
`export\\s+interface\\s+${componentName}Props\\s*(?:extends\\s+[^{]+)?\\{([\\s\\S]*?)\\}`,
|
|
140
|
+
"m",
|
|
141
|
+
);
|
|
142
|
+
let m = ifaceRe.exec(content);
|
|
143
|
+
if (!m) {
|
|
144
|
+
const anyIfaceRe = /export\s+interface\s+([A-Za-z0-9_]+Props)\s*(?:extends\s+[^{]+)?\{([\s\S]*?)\}/m;
|
|
145
|
+
m = anyIfaceRe.exec(content);
|
|
146
|
+
}
|
|
147
|
+
if (!m) {
|
|
148
|
+
const typeRe = new RegExp(`export\\s+type\\s+${componentName}Props\\s*=\\s*(?:[^{&]+&\s*)?([\\s\\S]*?)\\}`, "m");
|
|
149
|
+
m = typeRe.exec(content);
|
|
150
|
+
}
|
|
151
|
+
const props = [];
|
|
152
|
+
if (m) {
|
|
153
|
+
const body = m[2] || m[1] || "";
|
|
154
|
+
// Parse props more carefully to handle nested types
|
|
155
|
+
let currentProp = "";
|
|
156
|
+
let braceDepth = 0;
|
|
157
|
+
const lines = body.split("\n");
|
|
158
|
+
|
|
159
|
+
for (const line of lines) {
|
|
160
|
+
const trimmed = line.trim();
|
|
161
|
+
if (!trimmed || trimmed.startsWith("//")) continue;
|
|
162
|
+
|
|
163
|
+
// Count braces to track nested objects
|
|
164
|
+
for (const char of trimmed) {
|
|
165
|
+
if (char === "{") braceDepth++;
|
|
166
|
+
if (char === "}") braceDepth--;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
currentProp += (currentProp ? " " : "") + trimmed;
|
|
170
|
+
|
|
171
|
+
// If we're at depth 0 and the line ends with semicolon or we're complete, process the prop
|
|
172
|
+
if (braceDepth === 0 && (trimmed.endsWith(";") || trimmed.endsWith(","))) {
|
|
173
|
+
const pm = /^(readonly\s+)?([A-Za-z0-9_]+)\??:\s*(.+?)[;,]?\s*$/.exec(currentProp.trim());
|
|
174
|
+
if (pm) {
|
|
175
|
+
const name = pm[2];
|
|
176
|
+
let type = pm[3].trim();
|
|
177
|
+
// Clean up type - remove trailing semicolon/comma
|
|
178
|
+
type = type.replace(/[;,]\s*$/, "");
|
|
179
|
+
// Simplify very long nested types for readability
|
|
180
|
+
if (type.includes("{") && type.length > 100) {
|
|
181
|
+
// For nested object types, show simplified version
|
|
182
|
+
type = type.substring(0, 80) + "...}";
|
|
183
|
+
}
|
|
184
|
+
props.push({ name, type });
|
|
185
|
+
}
|
|
186
|
+
currentProp = "";
|
|
187
|
+
braceDepth = 0;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return props;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function generateComponentsManifest() {
|
|
195
|
+
console.log("\n📦 Generating components manifest...");
|
|
196
|
+
|
|
197
|
+
const indexPath = path.join(SRC_DIR, "index.ts");
|
|
198
|
+
const indexContent = read(indexPath);
|
|
199
|
+
const exports = extractExportsFromIndex(indexContent);
|
|
200
|
+
|
|
201
|
+
const components = [];
|
|
202
|
+
const categories = {};
|
|
203
|
+
|
|
204
|
+
for (const { name, relPath } of exports) {
|
|
205
|
+
if (!/^[A-Z]/.test(name)) continue;
|
|
206
|
+
|
|
207
|
+
const componentFile = findComponentFile(relPath);
|
|
208
|
+
if (!componentFile) continue;
|
|
209
|
+
const content = read(componentFile);
|
|
210
|
+
|
|
211
|
+
// Extract description from JSDoc
|
|
212
|
+
let idx = -1;
|
|
213
|
+
let description = "";
|
|
214
|
+
const patterns = [
|
|
215
|
+
`export function ${name}`,
|
|
216
|
+
`export const ${name}:`,
|
|
217
|
+
`export const ${name} =`,
|
|
218
|
+
`export class ${name}`,
|
|
219
|
+
new RegExp(`export\\s+const\\s+${name}\\s*[:=]`),
|
|
220
|
+
new RegExp(`export\\s+function\\s+${name}\\s*[(<]`),
|
|
221
|
+
];
|
|
222
|
+
|
|
223
|
+
for (const pattern of patterns) {
|
|
224
|
+
if (typeof pattern === "string") {
|
|
225
|
+
idx = content.indexOf(pattern);
|
|
226
|
+
} else {
|
|
227
|
+
const match = content.search(pattern);
|
|
228
|
+
if (match !== -1) idx = match;
|
|
229
|
+
}
|
|
230
|
+
if (idx !== -1) break;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (idx !== -1) {
|
|
234
|
+
description = getJsdocAbove(content, idx);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Extract props
|
|
238
|
+
const props = extractProps(content, name);
|
|
239
|
+
|
|
240
|
+
// Extract Storybook metadata
|
|
241
|
+
const storyFile = findStorybookFile(relPath);
|
|
242
|
+
let category = "Uncategorized";
|
|
243
|
+
let relatedComponents = [];
|
|
244
|
+
|
|
245
|
+
if (storyFile) {
|
|
246
|
+
const storyContent = read(storyFile);
|
|
247
|
+
const storyCategory = extractStorybookCategory(storyContent);
|
|
248
|
+
if (storyCategory) category = storyCategory;
|
|
249
|
+
relatedComponents = extractRelatedComponents(storyContent);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const component = {
|
|
253
|
+
name,
|
|
254
|
+
category,
|
|
255
|
+
description,
|
|
256
|
+
importRoot: "@texturehq/edges",
|
|
257
|
+
importPath: `@texturehq/edges/components/${name}`,
|
|
258
|
+
props,
|
|
259
|
+
relatedComponents,
|
|
260
|
+
storybookPath: category + "/" + name,
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
components.push(component);
|
|
264
|
+
|
|
265
|
+
// Organize by category
|
|
266
|
+
if (!categories[category]) {
|
|
267
|
+
categories[category] = [];
|
|
268
|
+
}
|
|
269
|
+
categories[category].push(name);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Sort components by name
|
|
273
|
+
components.sort((a, b) => a.name.localeCompare(b.name));
|
|
274
|
+
|
|
275
|
+
// Sort category arrays
|
|
276
|
+
for (const cat in categories) {
|
|
277
|
+
categories[cat].sort();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const manifest = {
|
|
281
|
+
version: process.env.npm_package_version || "unknown",
|
|
282
|
+
generatedAt: new Date().toISOString(),
|
|
283
|
+
components: components,
|
|
284
|
+
categories: categories,
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
ensureDir(DIST_DIR);
|
|
288
|
+
writeFile(path.join(DIST_DIR, "components.manifest.json"), JSON.stringify(manifest, null, 2));
|
|
289
|
+
|
|
290
|
+
console.log(` Found ${components.length} components in ${Object.keys(categories).length} categories`);
|
|
291
|
+
return manifest;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// ============================================================================
|
|
295
|
+
// UTILITIES & HOOKS MANIFEST GENERATION
|
|
296
|
+
// ============================================================================
|
|
297
|
+
|
|
298
|
+
function extractJSDoc(content, functionName) {
|
|
299
|
+
const patterns = [
|
|
300
|
+
new RegExp(`\\/\\*\\*([^*]|\\*(?!\\/))*\\*\\/\\s*export\\s+(?:async\\s+)?function\\s+${functionName}\\b`, "s"),
|
|
301
|
+
new RegExp(`\\/\\*\\*([^*]|\\*(?!\\/))*\\*\\/\\s*export\\s+const\\s+${functionName}\\s*=`, "s"),
|
|
302
|
+
];
|
|
303
|
+
|
|
304
|
+
for (const pattern of patterns) {
|
|
305
|
+
const match = content.match(pattern);
|
|
306
|
+
if (match) {
|
|
307
|
+
const jsdocMatch = match[0].match(/\/\*\*([\s\S]*?)\*\//);
|
|
308
|
+
if (jsdocMatch) {
|
|
309
|
+
const cleaned = jsdocMatch[1]
|
|
310
|
+
.split("\n")
|
|
311
|
+
.map((line) => line.replace(/^\s*\*\s?/, "").trim())
|
|
312
|
+
.filter((line) => line && !line.startsWith("@"))
|
|
313
|
+
.join(" ")
|
|
314
|
+
.trim();
|
|
315
|
+
return cleaned;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return "";
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function extractExportsFromFile(filePath) {
|
|
323
|
+
const content = read(filePath);
|
|
324
|
+
if (!content) return [];
|
|
325
|
+
|
|
326
|
+
const utilities = [];
|
|
327
|
+
|
|
328
|
+
// Match export function declarations
|
|
329
|
+
const functionPattern = /export\s+(?:async\s+)?function\s+(\w+)/g;
|
|
330
|
+
let match;
|
|
331
|
+
while ((match = functionPattern.exec(content))) {
|
|
332
|
+
const name = match[1];
|
|
333
|
+
utilities.push({
|
|
334
|
+
name,
|
|
335
|
+
type: "function",
|
|
336
|
+
description: extractJSDoc(content, name),
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Match export const arrow functions and constants
|
|
341
|
+
const constPattern = /export\s+const\s+(\w+)\s*(?::\s*[^=]+)?\s*=/g;
|
|
342
|
+
while ((match = constPattern.exec(content))) {
|
|
343
|
+
const name = match[1];
|
|
344
|
+
const afterMatch = content.slice(match.index + match[0].length, match.index + match[0].length + 50);
|
|
345
|
+
const isFunction = afterMatch.includes("=>") || afterMatch.includes("function");
|
|
346
|
+
|
|
347
|
+
utilities.push({
|
|
348
|
+
name,
|
|
349
|
+
type: isFunction ? "function" : "constant",
|
|
350
|
+
description: extractJSDoc(content, name),
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return utilities;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function scanDirectory(dir, category) {
|
|
358
|
+
const utilities = [];
|
|
359
|
+
|
|
360
|
+
if (!fs.existsSync(dir)) return utilities;
|
|
361
|
+
|
|
362
|
+
const files = fs.readdirSync(dir);
|
|
363
|
+
|
|
364
|
+
for (const file of files) {
|
|
365
|
+
const filePath = path.join(dir, file);
|
|
366
|
+
const stat = fs.statSync(filePath);
|
|
367
|
+
|
|
368
|
+
if (stat.isDirectory() && file !== "__tests__" && file !== "tests") {
|
|
369
|
+
utilities.push(...scanDirectory(filePath, `${category}/${file}`));
|
|
370
|
+
} else if ((file.endsWith(".ts") || file.endsWith(".tsx")) && !file.endsWith(".d.ts")) {
|
|
371
|
+
if (file.includes(".test.") || file.includes(".spec.") || file.includes(".stories.")) {
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const funcs = extractExportsFromFile(filePath);
|
|
376
|
+
for (const func of funcs) {
|
|
377
|
+
utilities.push({
|
|
378
|
+
...func,
|
|
379
|
+
category,
|
|
380
|
+
file: path.relative(SRC_DIR, filePath),
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return utilities;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function generateUtilitiesManifest() {
|
|
390
|
+
console.log("\n🔧 Generating utilities manifest...");
|
|
391
|
+
|
|
392
|
+
const manifest = {
|
|
393
|
+
version: process.env.npm_package_version || "unknown",
|
|
394
|
+
generatedAt: new Date().toISOString(),
|
|
395
|
+
categories: {},
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
// Scan hooks directory
|
|
399
|
+
const hooksDir = path.join(SRC_DIR, "hooks");
|
|
400
|
+
const hooks = scanDirectory(hooksDir, "hooks");
|
|
401
|
+
if (hooks.length > 0) {
|
|
402
|
+
manifest.categories.hooks = {
|
|
403
|
+
description:
|
|
404
|
+
"React hooks for common functionality like breakpoints, debouncing, local storage, and media queries",
|
|
405
|
+
utilities: hooks.sort((a, b) => a.name.localeCompare(b.name)),
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Scan formatting utilities
|
|
410
|
+
const formattingDir = path.join(SRC_DIR, "utils/formatting");
|
|
411
|
+
const formatting = scanDirectory(formattingDir, "formatting");
|
|
412
|
+
if (formatting.length > 0) {
|
|
413
|
+
manifest.categories.formatting = {
|
|
414
|
+
description:
|
|
415
|
+
"Comprehensive formatting utilities for text, numbers, dates, currency, energy, temperature, distance, and more",
|
|
416
|
+
utilities: formatting.sort((a, b) => a.name.localeCompare(b.name)),
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Chart utilities
|
|
421
|
+
const chartsDir = path.join(SRC_DIR, "utils/charts");
|
|
422
|
+
const charts = scanDirectory(chartsDir, "charts");
|
|
423
|
+
const chartExportUtils = extractExportsFromFile(path.join(SRC_DIR, "utils/chartExport.ts"));
|
|
424
|
+
const chartUtils = extractExportsFromFile(path.join(SRC_DIR, "utils/charts.ts"));
|
|
425
|
+
const allChartUtils = [
|
|
426
|
+
...charts,
|
|
427
|
+
...chartExportUtils.map((f) => ({ ...f, category: "charts", file: "utils/chartExport.ts" })),
|
|
428
|
+
...chartUtils.map((f) => ({ ...f, category: "charts", file: "utils/charts.ts" })),
|
|
429
|
+
];
|
|
430
|
+
|
|
431
|
+
if (allChartUtils.length > 0) {
|
|
432
|
+
manifest.categories.charts = {
|
|
433
|
+
description: "Chart utilities for data visualization, scaling, and export functionality",
|
|
434
|
+
utilities: allChartUtils.sort((a, b) => a.name.localeCompare(b.name)),
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Color utilities
|
|
439
|
+
const colorUtils = extractExportsFromFile(path.join(SRC_DIR, "utils/colors.ts"));
|
|
440
|
+
if (colorUtils.length > 0) {
|
|
441
|
+
manifest.categories.colors = {
|
|
442
|
+
description:
|
|
443
|
+
"Color management utilities for theme-aware color resolution, contrast calculation, and palette generation",
|
|
444
|
+
utilities: colorUtils
|
|
445
|
+
.map((f) => ({ ...f, category: "colors", file: "utils/colors.ts" }))
|
|
446
|
+
.sort((a, b) => a.name.localeCompare(b.name)),
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const totalUtilities = Object.values(manifest.categories).reduce((sum, cat) => sum + cat.utilities.length, 0);
|
|
451
|
+
|
|
452
|
+
ensureDir(DIST_DIR);
|
|
453
|
+
writeFile(path.join(DIST_DIR, "utilities.manifest.json"), JSON.stringify(manifest, null, 2));
|
|
454
|
+
|
|
455
|
+
console.log(` Found ${totalUtilities} utilities in ${Object.keys(manifest.categories).length} categories`);
|
|
456
|
+
return manifest;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// ============================================================================
|
|
460
|
+
// THEME PARSING
|
|
461
|
+
// ============================================================================
|
|
462
|
+
|
|
463
|
+
function parseThemeColors() {
|
|
464
|
+
console.log("\n🎨 Parsing theme colors...");
|
|
465
|
+
|
|
466
|
+
const themePath = path.join(DIST_DIR, "theme.css");
|
|
467
|
+
if (!fs.existsSync(themePath)) {
|
|
468
|
+
console.log(" ⚠️ theme.css not found, skipping color extraction");
|
|
469
|
+
return {};
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
const themeContent = read(themePath);
|
|
473
|
+
const colorVars = {};
|
|
474
|
+
const colorRegex = /--color-([a-z-]+):\s*([^;]+);/g;
|
|
475
|
+
let match;
|
|
476
|
+
|
|
477
|
+
while ((match = colorRegex.exec(themeContent))) {
|
|
478
|
+
const varName = match[1];
|
|
479
|
+
const value = match[2].trim();
|
|
480
|
+
colorVars[varName] = value;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
console.log(` Found ${Object.keys(colorVars).length} color variables`);
|
|
484
|
+
return colorVars;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// ============================================================================
|
|
488
|
+
// MARKDOWN DOCUMENTATION GENERATION
|
|
489
|
+
// ============================================================================
|
|
490
|
+
|
|
491
|
+
function generateComponentsReference(componentsManifest) {
|
|
492
|
+
console.log("\n📝 Generating components reference...");
|
|
493
|
+
|
|
494
|
+
const { components, categories } = componentsManifest;
|
|
495
|
+
|
|
496
|
+
let content = `# Edges Components Reference
|
|
497
|
+
|
|
498
|
+
> **Auto-generated** - Do not edit manually. Run \`yarn generate:edges-docs\` to regenerate.
|
|
499
|
+
|
|
500
|
+
This document provides a complete reference of all ${components.length} components in the @texturehq/edges design system, organized by functional category.
|
|
501
|
+
|
|
502
|
+
## Quick Navigation
|
|
503
|
+
|
|
504
|
+
`;
|
|
505
|
+
|
|
506
|
+
// Table of contents by category
|
|
507
|
+
const sortedCategories = Object.keys(categories).sort();
|
|
508
|
+
for (const category of sortedCategories) {
|
|
509
|
+
const count = categories[category].length;
|
|
510
|
+
content += `- [${category}](#${category.toLowerCase().replace(/\s+/g, "-")}) (${count} component${count > 1 ? "s" : ""})\n`;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
content += `\n---\n\n`;
|
|
514
|
+
|
|
515
|
+
// Generate content by category
|
|
516
|
+
for (const category of sortedCategories) {
|
|
517
|
+
content += `## ${category}\n\n`;
|
|
518
|
+
|
|
519
|
+
const categoryComponents = components.filter((c) => c.category === category);
|
|
520
|
+
categoryComponents.sort((a, b) => a.name.localeCompare(b.name));
|
|
521
|
+
|
|
522
|
+
for (const component of categoryComponents) {
|
|
523
|
+
content += `### ${component.name}\n\n`;
|
|
524
|
+
|
|
525
|
+
if (component.description) {
|
|
526
|
+
content += `${component.description}\n\n`;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
content += `**Import:**\n\n`;
|
|
530
|
+
content += `\`\`\`typescript\n`;
|
|
531
|
+
content += `import { ${component.name} } from "${component.importRoot}";\n`;
|
|
532
|
+
content += `// or\n`;
|
|
533
|
+
content += `import { ${component.name} } from "${component.importPath}";\n`;
|
|
534
|
+
content += `\`\`\`\n\n`;
|
|
535
|
+
|
|
536
|
+
if (component.props && component.props.length > 0) {
|
|
537
|
+
content += `**Props:**\n\n`;
|
|
538
|
+
content += `| Prop | Type |\n`;
|
|
539
|
+
content += `|------|------|\n`;
|
|
540
|
+
for (const prop of component.props) {
|
|
541
|
+
content += `| \`${prop.name}\` | \`${prop.type}\` |\n`;
|
|
542
|
+
}
|
|
543
|
+
content += `\n`;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
if (component.relatedComponents && component.relatedComponents.length > 0) {
|
|
547
|
+
content += `**Related:** ${component.relatedComponents.join(", ")}\n\n`;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
if (component.storybookPath) {
|
|
551
|
+
content += `**Storybook:** \`${component.storybookPath}\`\n\n`;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
content += `---\n\n`;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
writeFile(path.join(DOCS_AI_EDGES, "components-reference.md"), content);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
function generateHooksReference(utilitiesManifest) {
|
|
562
|
+
console.log("\n🪝 Generating hooks reference...");
|
|
563
|
+
|
|
564
|
+
const hooksCategory = utilitiesManifest.categories.hooks;
|
|
565
|
+
if (!hooksCategory) {
|
|
566
|
+
console.log(" No hooks found");
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
const hooks = hooksCategory.utilities;
|
|
571
|
+
|
|
572
|
+
let content = `# Edges Hooks Reference
|
|
573
|
+
|
|
574
|
+
> **Auto-generated** - Do not edit manually. Run \`yarn generate:edges-docs\` to regenerate.
|
|
575
|
+
|
|
576
|
+
This document provides a complete reference of all ${hooks.length} React hooks in the @texturehq/edges design system.
|
|
577
|
+
|
|
578
|
+
${hooksCategory.description}
|
|
579
|
+
|
|
580
|
+
## Available Hooks
|
|
581
|
+
|
|
582
|
+
`;
|
|
583
|
+
|
|
584
|
+
for (const hook of hooks) {
|
|
585
|
+
content += `### ${hook.name}\n\n`;
|
|
586
|
+
|
|
587
|
+
if (hook.description) {
|
|
588
|
+
content += `${hook.description}\n\n`;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
content += `**Import:**\n\n`;
|
|
592
|
+
content += `\`\`\`typescript\n`;
|
|
593
|
+
content += `import { ${hook.name} } from "@texturehq/edges";\n`;
|
|
594
|
+
content += `\`\`\`\n\n`;
|
|
595
|
+
|
|
596
|
+
content += `**Source:** \`src/${hook.file}\`\n\n`;
|
|
597
|
+
content += `---\n\n`;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
writeFile(path.join(DOCS_AI_EDGES, "hooks-reference.md"), content);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function generateUtilitiesReference(utilitiesManifest) {
|
|
604
|
+
console.log("\n🛠️ Generating utilities reference...");
|
|
605
|
+
|
|
606
|
+
const categories = Object.keys(utilitiesManifest.categories).filter((c) => c !== "hooks");
|
|
607
|
+
if (categories.length === 0) {
|
|
608
|
+
console.log(" No utilities found");
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
let content = `# Edges Utilities Reference
|
|
613
|
+
|
|
614
|
+
> **Auto-generated** - Do not edit manually. Run \`yarn generate:edges-docs\` to regenerate.
|
|
615
|
+
|
|
616
|
+
This document provides a complete reference of all utility functions in the @texturehq/edges design system.
|
|
617
|
+
|
|
618
|
+
## Categories
|
|
619
|
+
|
|
620
|
+
`;
|
|
621
|
+
|
|
622
|
+
for (const category of categories) {
|
|
623
|
+
const cat = utilitiesManifest.categories[category];
|
|
624
|
+
content += `- [${category}](#${category}) (${cat.utilities.length} utilities)\n`;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
content += `\n---\n\n`;
|
|
628
|
+
|
|
629
|
+
for (const category of categories) {
|
|
630
|
+
const cat = utilitiesManifest.categories[category];
|
|
631
|
+
content += `## ${category}\n\n`;
|
|
632
|
+
content += `${cat.description}\n\n`;
|
|
633
|
+
|
|
634
|
+
for (const util of cat.utilities) {
|
|
635
|
+
content += `### ${util.name}\n\n`;
|
|
636
|
+
|
|
637
|
+
if (util.description) {
|
|
638
|
+
content += `${util.description}\n\n`;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
content += `**Type:** ${util.type}\n\n`;
|
|
642
|
+
content += `**Import:**\n\n`;
|
|
643
|
+
content += `\`\`\`typescript\n`;
|
|
644
|
+
content += `import { ${util.name} } from "@texturehq/edges";\n`;
|
|
645
|
+
content += `\`\`\`\n\n`;
|
|
646
|
+
|
|
647
|
+
content += `**Source:** \`src/${util.file}\`\n\n`;
|
|
648
|
+
content += `---\n\n`;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
writeFile(path.join(DOCS_AI_EDGES, "utilities-reference.md"), content);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
function generateThemeSystemDoc(colorVars) {
|
|
656
|
+
console.log("\n🎨 Generating theme system documentation...");
|
|
657
|
+
|
|
658
|
+
let content = `# Edges Theme System
|
|
659
|
+
|
|
660
|
+
> **Auto-generated** - Do not edit manually. Run \`yarn generate:edges-docs\` to regenerate.
|
|
661
|
+
|
|
662
|
+
## Overview
|
|
663
|
+
|
|
664
|
+
The @texturehq/edges design system uses Tailwind 4 with CSS variables. All design tokens are defined as CSS variables and automatically become available as Tailwind utility classes.
|
|
665
|
+
|
|
666
|
+
## Setup
|
|
667
|
+
|
|
668
|
+
\`\`\`css
|
|
669
|
+
@import "@texturehq/edges/theme.css";
|
|
670
|
+
\`\`\`
|
|
671
|
+
|
|
672
|
+
## How It Works
|
|
673
|
+
|
|
674
|
+
CSS variables automatically become Tailwind classes:
|
|
675
|
+
- \`--color-brand-primary\` → \`bg-brand-primary\`, \`text-brand-primary\`, \`border-brand-primary\`
|
|
676
|
+
- \`--spacing-md\` → \`p-md\`, \`m-md\`, \`gap-md\`
|
|
677
|
+
- \`--text-lg\` → \`text-lg\`
|
|
678
|
+
- \`--radius-lg\` → \`rounded-lg\`
|
|
679
|
+
|
|
680
|
+
## Color System
|
|
681
|
+
|
|
682
|
+
The theme includes ${Object.keys(colorVars).length} color variables organized by purpose:
|
|
683
|
+
|
|
684
|
+
### Brand Colors
|
|
685
|
+
- \`brand-primary\` - Primary brand color
|
|
686
|
+
- \`brand-light\` - Light brand variant
|
|
687
|
+
- \`brand-dark\` - Dark brand variant
|
|
688
|
+
|
|
689
|
+
### Text Colors
|
|
690
|
+
- \`text-body\` - Body text
|
|
691
|
+
- \`text-heading\` - Heading text
|
|
692
|
+
- \`text-muted\` - Muted/secondary text
|
|
693
|
+
- \`text-caption\` - Caption/helper text
|
|
694
|
+
- \`text-on-primary\` - Text on primary backgrounds
|
|
695
|
+
|
|
696
|
+
### Background Colors
|
|
697
|
+
- \`background-body\` - Main page background
|
|
698
|
+
- \`background-surface\` - Card/surface background
|
|
699
|
+
- \`background-muted\` - Muted background
|
|
700
|
+
- \`background-subtle\` - Subtle background
|
|
701
|
+
|
|
702
|
+
### Border Colors
|
|
703
|
+
- \`border-default\` - Default border
|
|
704
|
+
- \`border-focus\` - Focused border
|
|
705
|
+
- \`border-muted\` - Muted border
|
|
706
|
+
- \`border-subtle\` - Subtle border
|
|
707
|
+
|
|
708
|
+
### Action Colors
|
|
709
|
+
- \`action-primary\` - Primary actions
|
|
710
|
+
- \`action-secondary\` - Secondary actions
|
|
711
|
+
- \`action-destructive\` - Destructive actions
|
|
712
|
+
|
|
713
|
+
### Feedback Colors
|
|
714
|
+
- \`feedback-success\` - Success state
|
|
715
|
+
- \`feedback-error\` - Error state
|
|
716
|
+
- \`feedback-warning\` - Warning state
|
|
717
|
+
- \`feedback-info\` - Info state
|
|
718
|
+
|
|
719
|
+
## Usage Guidelines
|
|
720
|
+
|
|
721
|
+
**✅ Good - Use semantic classes:**
|
|
722
|
+
\`\`\`tsx
|
|
723
|
+
<div className="bg-brand-primary text-text-on-primary p-md rounded-lg shadow-md">
|
|
724
|
+
<h2 className="text-text-heading text-lg font-medium">Title</h2>
|
|
725
|
+
<p className="text-text-body text-base">Content</p>
|
|
726
|
+
</div>
|
|
727
|
+
\`\`\`
|
|
728
|
+
|
|
729
|
+
**❌ Avoid - Arbitrary values:**
|
|
730
|
+
\`\`\`tsx
|
|
731
|
+
<div className="bg-[#444ae1] text-[#ffffff] p-[1rem] rounded-[0.5rem]">
|
|
732
|
+
<h2 className="text-[#111827] text-[1.125rem] font-[500]">Title</h2>
|
|
733
|
+
<p className="text-[#333333] text-[1rem]">Content</p>
|
|
734
|
+
</div>
|
|
735
|
+
\`\`\`
|
|
736
|
+
|
|
737
|
+
## Spacing Scale
|
|
738
|
+
|
|
739
|
+
- \`xs\`, \`sm\`, \`md\`, \`lg\`, \`xl\`, \`2xl\`, \`3xl\`, \`4xl\`
|
|
740
|
+
|
|
741
|
+
## Typography Scale
|
|
742
|
+
|
|
743
|
+
- \`xs\`, \`sm\`, \`base\`, \`lg\`, \`xl\`, \`2xl\`, \`3xl\`, \`4xl\`
|
|
744
|
+
|
|
745
|
+
## Border Radius Scale
|
|
746
|
+
|
|
747
|
+
- \`xs\`, \`sm\`, \`md\`, \`lg\`, \`xl\`, \`2xl\`, \`3xl\`, \`4xl\`
|
|
748
|
+
|
|
749
|
+
## Dark Mode
|
|
750
|
+
|
|
751
|
+
All colors automatically adapt to dark mode when the \`.theme-dark\` class is present on a parent element.
|
|
752
|
+
|
|
753
|
+
## Available Variables
|
|
754
|
+
|
|
755
|
+
The theme includes:
|
|
756
|
+
- Complete color system (${Object.keys(colorVars).length} color variables)
|
|
757
|
+
- Spacing scale
|
|
758
|
+
- Typography scale
|
|
759
|
+
- Border radius scale
|
|
760
|
+
- Shadow system
|
|
761
|
+
- Animation definitions
|
|
762
|
+
- Form control specifications
|
|
763
|
+
`;
|
|
764
|
+
|
|
765
|
+
writeFile(path.join(DOCS_AI_EDGES, "theme-system.md"), content);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
function generateEdgesReadme(componentsManifest, utilitiesManifest) {
|
|
769
|
+
console.log("\n📄 Generating edges README...");
|
|
770
|
+
|
|
771
|
+
const componentCount = componentsManifest.components.length;
|
|
772
|
+
const categoryCount = Object.keys(componentsManifest.categories).length;
|
|
773
|
+
const hookCount = utilitiesManifest.categories.hooks?.utilities.length || 0;
|
|
774
|
+
|
|
775
|
+
let utilityCount = 0;
|
|
776
|
+
for (const cat in utilitiesManifest.categories) {
|
|
777
|
+
if (cat !== "hooks") {
|
|
778
|
+
utilityCount += utilitiesManifest.categories[cat].utilities.length;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
let content = `# Edges Design System - AI Context
|
|
783
|
+
|
|
784
|
+
> **Auto-generated** - Do not edit manually. Run \`yarn generate:edges-docs\` to regenerate.
|
|
785
|
+
|
|
786
|
+
👋 **AI Agents: Start here!**
|
|
787
|
+
|
|
788
|
+
Complete documentation for the @texturehq/edges design system.
|
|
789
|
+
|
|
790
|
+
## What's Inside
|
|
791
|
+
|
|
792
|
+
- **${componentCount} Components** across ${categoryCount} categories
|
|
793
|
+
- **${hookCount} React Hooks** for common functionality
|
|
794
|
+
- **${utilityCount} Utility Functions** for formatting, charts, colors, and more
|
|
795
|
+
- **Complete Theme System** with Tailwind 4 + CSS variables
|
|
796
|
+
|
|
797
|
+
## Quick Links
|
|
798
|
+
|
|
799
|
+
### Component Library
|
|
800
|
+
- [Components Reference](components-reference.md) - All ${componentCount} components organized by category
|
|
801
|
+
- [Component Categories](#component-categories) - Quick navigation by function
|
|
802
|
+
|
|
803
|
+
### Utilities & Hooks
|
|
804
|
+
- [Hooks Reference](hooks-reference.md) - All ${hookCount} React hooks
|
|
805
|
+
- [Utilities Reference](utilities-reference.md) - All ${utilityCount} utility functions
|
|
806
|
+
|
|
807
|
+
### Design System
|
|
808
|
+
- [Theme System](theme-system.md) - Colors, spacing, typography with Tailwind 4
|
|
809
|
+
- [Patterns](patterns.md) - Common UI patterns and best practices
|
|
810
|
+
|
|
811
|
+
## Component Categories
|
|
812
|
+
|
|
813
|
+
`;
|
|
814
|
+
|
|
815
|
+
const sortedCategories = Object.keys(componentsManifest.categories).sort();
|
|
816
|
+
for (const category of sortedCategories) {
|
|
817
|
+
const components = componentsManifest.categories[category];
|
|
818
|
+
content += `### ${category}\n\n`;
|
|
819
|
+
content += `${components.join(", ")}\n\n`;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
content += `## Installation
|
|
823
|
+
|
|
824
|
+
\`\`\`bash
|
|
825
|
+
yarn add @texturehq/edges
|
|
826
|
+
\`\`\`
|
|
827
|
+
|
|
828
|
+
## Setup
|
|
829
|
+
|
|
830
|
+
\`\`\`css
|
|
831
|
+
@import "@texturehq/edges/theme.css";
|
|
832
|
+
\`\`\`
|
|
833
|
+
|
|
834
|
+
\`\`\`typescript
|
|
835
|
+
import { Button, TextField, DataTable } from "@texturehq/edges";
|
|
836
|
+
\`\`\`
|
|
837
|
+
|
|
838
|
+
## For Dashboard Development
|
|
839
|
+
|
|
840
|
+
When building UI in \`apps/dashboard\`, reference:
|
|
841
|
+
- **Components**: \`docs/ai/edges/components-reference.md\`
|
|
842
|
+
- **Hooks**: \`docs/ai/edges/hooks-reference.md\`
|
|
843
|
+
- **Utilities**: \`docs/ai/edges/utilities-reference.md\`
|
|
844
|
+
- **Theme**: \`docs/ai/edges/theme-system.md\`
|
|
845
|
+
- **Patterns**: \`docs/ai/edges/patterns.md\`
|
|
846
|
+
|
|
847
|
+
---
|
|
848
|
+
|
|
849
|
+
**Package Version:** ${componentsManifest.version}
|
|
850
|
+
**Generated:** ${new Date().toISOString()}
|
|
851
|
+
`;
|
|
852
|
+
|
|
853
|
+
writeFile(path.join(DOCS_AI_EDGES, "README.md"), content);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// ============================================================================
|
|
857
|
+
// AGENT INSTRUCTION FRAGMENT
|
|
858
|
+
// ============================================================================
|
|
859
|
+
|
|
860
|
+
function generateEdgesFragment(componentsManifest, utilitiesManifest) {
|
|
861
|
+
console.log("\n📄 Generating edges fragment...");
|
|
862
|
+
|
|
863
|
+
const componentCount = componentsManifest.components.length;
|
|
864
|
+
const hookCount = utilitiesManifest.categories.hooks?.utilities.length || 0;
|
|
865
|
+
|
|
866
|
+
let utilityCount = 0;
|
|
867
|
+
for (const cat in utilitiesManifest.categories) {
|
|
868
|
+
if (cat !== "hooks") {
|
|
869
|
+
utilityCount += utilitiesManifest.categories[cat].utilities.length;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
const content = `<!-- priority: 20 -->
|
|
874
|
+
## Edges Design System Context
|
|
875
|
+
|
|
876
|
+
The @texturehq/edges design system provides ${componentCount} React components, ${hookCount} hooks, and ${utilityCount} utility functions.
|
|
877
|
+
|
|
878
|
+
**Complete component documentation is in**: \`docs/ai/edges/\`
|
|
879
|
+
|
|
880
|
+
### Quick Start
|
|
881
|
+
|
|
882
|
+
1. Read \`docs/ai/edges/README.md\` for an overview and component categories
|
|
883
|
+
2. Reference \`docs/ai/edges/components-reference.md\` for detailed component API
|
|
884
|
+
3. Review \`docs/ai/edges/patterns.md\` for common UI patterns and best practices
|
|
885
|
+
4. Check \`docs/ai/edges/theme-system.md\` for Tailwind 4 color tokens and styling
|
|
886
|
+
|
|
887
|
+
### Additional Resources
|
|
888
|
+
|
|
889
|
+
- Hooks: \`docs/ai/edges/hooks-reference.md\`
|
|
890
|
+
- Utilities: \`docs/ai/edges/utilities-reference.md\`
|
|
891
|
+
|
|
892
|
+
### For Dashboard Development
|
|
893
|
+
|
|
894
|
+
**UI (Edges)**:
|
|
895
|
+
- All components, hooks, and utilities from \`@texturehq/edges\`
|
|
896
|
+
- Use semantic Tailwind classes from theme (see theme-system.md)
|
|
897
|
+
- Follow patterns from \`docs/ai/edges/patterns.md\`
|
|
898
|
+
|
|
899
|
+
### Common Patterns
|
|
900
|
+
|
|
901
|
+
**Import**: \`import { Button, TextField } from "@texturehq/edges"\`
|
|
902
|
+
**Styling**: Use semantic classes like \`bg-brand-primary\`, \`text-text-body\`
|
|
903
|
+
**Forms**: Wrap in \`<Form>\`, use validation with \`errorMessage\`
|
|
904
|
+
**Loading**: Show \`<Skeleton>\` during data fetching
|
|
905
|
+
**Responsive**: Use \`useBreakpoint()\` hook or responsive grid cols
|
|
906
|
+
`;
|
|
907
|
+
|
|
908
|
+
const fragmentsDir = path.join(MONO_ROOT, ".agent-fragments");
|
|
909
|
+
ensureDir(fragmentsDir);
|
|
910
|
+
writeFile(path.join(fragmentsDir, "edges.md"), content);
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// ============================================================================
|
|
914
|
+
// MAIN
|
|
915
|
+
// ============================================================================
|
|
916
|
+
|
|
917
|
+
async function main() {
|
|
918
|
+
console.log("🚀 Generating Edges AI Context...\n");
|
|
919
|
+
|
|
920
|
+
// Ensure output directories exist
|
|
921
|
+
ensureDir(DOCS_AI_EDGES);
|
|
922
|
+
ensureDir(DIST_DIR);
|
|
923
|
+
|
|
924
|
+
// Generate manifests
|
|
925
|
+
const componentsManifest = generateComponentsManifest();
|
|
926
|
+
const utilitiesManifest = generateUtilitiesManifest();
|
|
927
|
+
|
|
928
|
+
// Parse theme
|
|
929
|
+
const colorVars = parseThemeColors();
|
|
930
|
+
|
|
931
|
+
// Generate markdown documentation
|
|
932
|
+
generateComponentsReference(componentsManifest);
|
|
933
|
+
generateHooksReference(utilitiesManifest);
|
|
934
|
+
generateUtilitiesReference(utilitiesManifest);
|
|
935
|
+
generateThemeSystemDoc(colorVars);
|
|
936
|
+
generateEdgesReadme(componentsManifest, utilitiesManifest);
|
|
937
|
+
|
|
938
|
+
// Generate agent instruction fragment
|
|
939
|
+
generateEdgesFragment(componentsManifest, utilitiesManifest);
|
|
940
|
+
|
|
941
|
+
// Merge all agent instruction fragments
|
|
942
|
+
console.log("\n🔀 Merging agent instruction fragments...");
|
|
943
|
+
try {
|
|
944
|
+
execSync("ts-node scripts/merge-agent-instructions.ts", {
|
|
945
|
+
cwd: MONO_ROOT,
|
|
946
|
+
stdio: "inherit",
|
|
947
|
+
});
|
|
948
|
+
} catch (err) {
|
|
949
|
+
console.log("⚠️ Note: Could not merge agent instructions (merge script may not be available yet)");
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
console.log("\n✅ Edges AI context generation complete!");
|
|
953
|
+
console.log("\nGenerated files:");
|
|
954
|
+
console.log(" - dist/components.manifest.json");
|
|
955
|
+
console.log(" - dist/utilities.manifest.json");
|
|
956
|
+
console.log(" - docs/ai/edges/README.md");
|
|
957
|
+
console.log(" - docs/ai/edges/components-reference.md");
|
|
958
|
+
console.log(" - docs/ai/edges/hooks-reference.md");
|
|
959
|
+
console.log(" - docs/ai/edges/utilities-reference.md");
|
|
960
|
+
console.log(" - docs/ai/edges/theme-system.md");
|
|
961
|
+
console.log(" - .agent-fragments/edges.md");
|
|
962
|
+
console.log(" - .claude/instructions.md (merged)");
|
|
963
|
+
console.log(" - .codex/instructions.md (merged)");
|
|
964
|
+
console.log(" - .github/copilot-instructions.md (merged)");
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
main().catch((err) => {
|
|
968
|
+
console.error("❌ Failed to generate AI context:", err);
|
|
969
|
+
process.exit(1);
|
|
970
|
+
});
|