mycontext-cli 0.2.39 → 0.4.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 (55) hide show
  1. package/dist/agents/implementations/CodeGenSubAgent.d.ts +2 -0
  2. package/dist/agents/implementations/CodeGenSubAgent.d.ts.map +1 -1
  3. package/dist/agents/implementations/CodeGenSubAgent.js +344 -24
  4. package/dist/agents/implementations/CodeGenSubAgent.js.map +1 -1
  5. package/dist/agents/implementations/DocsSubAgent.js +1 -1
  6. package/dist/agents/implementations/DocsSubAgent.js.map +1 -1
  7. package/dist/agents/implementations/EnhancementAgent.d.ts.map +1 -1
  8. package/dist/agents/implementations/EnhancementAgent.js +31 -44
  9. package/dist/agents/implementations/EnhancementAgent.js.map +1 -1
  10. package/dist/agents/implementations/QASubAgent.js +1 -1
  11. package/dist/agents/orchestrator/SubAgentOrchestrator.js +1 -1
  12. package/dist/agents/orchestrator/SubAgentOrchestrator.js.map +1 -1
  13. package/dist/cli.js +38 -2
  14. package/dist/cli.js.map +1 -1
  15. package/dist/commands/auth.d.ts +8 -1
  16. package/dist/commands/auth.d.ts.map +1 -1
  17. package/dist/commands/auth.js +63 -22
  18. package/dist/commands/auth.js.map +1 -1
  19. package/dist/commands/core.d.ts +12 -0
  20. package/dist/commands/core.d.ts.map +1 -0
  21. package/dist/commands/core.js +133 -0
  22. package/dist/commands/core.js.map +1 -0
  23. package/dist/commands/enhance.d.ts +1 -1
  24. package/dist/commands/enhance.d.ts.map +1 -1
  25. package/dist/commands/enhance.js +54 -59
  26. package/dist/commands/enhance.js.map +1 -1
  27. package/dist/commands/generate-components.d.ts +15 -0
  28. package/dist/commands/generate-components.d.ts.map +1 -1
  29. package/dist/commands/generate-components.js +289 -53
  30. package/dist/commands/generate-components.js.map +1 -1
  31. package/dist/commands/generate.d.ts +4 -0
  32. package/dist/commands/generate.d.ts.map +1 -1
  33. package/dist/commands/generate.js +239 -31
  34. package/dist/commands/generate.js.map +1 -1
  35. package/dist/commands/init.js +1 -1
  36. package/dist/commands/init.js.map +1 -1
  37. package/dist/commands/list.d.ts.map +1 -1
  38. package/dist/commands/list.js +25 -9
  39. package/dist/commands/list.js.map +1 -1
  40. package/dist/config/ai-providers.json +25 -0
  41. package/dist/utils/apiKeyManager.d.ts +1 -1
  42. package/dist/utils/apiKeyManager.js +1 -1
  43. package/dist/utils/errorHandler.d.ts +4 -0
  44. package/dist/utils/errorHandler.d.ts.map +1 -1
  45. package/dist/utils/errorHandler.js +4 -0
  46. package/dist/utils/errorHandler.js.map +1 -1
  47. package/dist/utils/hybridAIClient.d.ts +1 -0
  48. package/dist/utils/hybridAIClient.d.ts.map +1 -1
  49. package/dist/utils/hybridAIClient.js +13 -0
  50. package/dist/utils/hybridAIClient.js.map +1 -1
  51. package/dist/utils/xaiClient.d.ts +19 -0
  52. package/dist/utils/xaiClient.d.ts.map +1 -0
  53. package/dist/utils/xaiClient.js +108 -0
  54. package/dist/utils/xaiClient.js.map +1 -0
  55. package/package.json +8 -2
@@ -40,40 +40,10 @@ exports.GenerateComponentsCommand = void 0;
40
40
  const fileSystem_1 = require("../utils/fileSystem");
41
41
  const spinner_1 = require("../utils/spinner");
42
42
  const chalk_1 = __importDefault(require("chalk"));
43
+ const prompts_1 = __importDefault(require("prompts"));
43
44
  const fs = __importStar(require("fs-extra"));
44
45
  const path = __importStar(require("path"));
45
46
  const child_process_1 = require("child_process");
46
- // Code Generation Sub-Agent
47
- class CodeGenSubAgent {
48
- constructor() {
49
- this.name = "CodeGenSubAgent";
50
- }
51
- async run({ component, group, options }) {
52
- // Use the existing generateComponentCode logic
53
- return new GenerateComponentsCommand().generateComponentCode(component, group, options);
54
- }
55
- }
56
- // QA Sub-Agent (stub for demonstration)
57
- class QASubAgent {
58
- constructor() {
59
- this.name = "QASubAgent";
60
- }
61
- async run({ code, component }) {
62
- // Placeholder: In real implementation, run static analysis, lint, or type checks
63
- // For now, always return true (pass)
64
- return true;
65
- }
66
- }
67
- // Docs Writer Sub-Agent (stub for demonstration)
68
- class DocsSubAgent {
69
- constructor() {
70
- this.name = "DocsSubAgent";
71
- }
72
- async run({ component, group }) {
73
- // Placeholder: Generate markdown or JSDoc for the component
74
- return `# ${component.name}\n\n${component.description}\n`;
75
- }
76
- }
77
47
  // --- Orchestration in GenerateComponentsCommand ---
78
48
  class GenerateComponentsCommand {
79
49
  constructor() {
@@ -117,6 +87,8 @@ class GenerateComponentsCommand {
117
87
  async execute(target, options) {
118
88
  const spinner = new spinner_1.EnhancedSpinner("Initializing component generation...");
119
89
  try {
90
+ // System reminder: high-level plan
91
+ console.log(chalk_1.default.gray("\n[mycontext] Plan: plan → generate → QA → docs → preview (→ checks)\n"));
120
92
  // Check authentication unless local mode is enabled
121
93
  let userInfo = null;
122
94
  if (!options.local) {
@@ -146,6 +118,36 @@ class GenerateComponentsCommand {
146
118
  // Determine if we're generating a specific group or all components
147
119
  const isAll = target === "all" || options.all;
148
120
  const groupName = isAll ? undefined : target;
121
+ // Core-first flow: generate a single BrandComp then exit
122
+ if (isAll && options.coreFirst) {
123
+ await this.generateCoreBrandComp(options, spinner);
124
+ // Update preview registry and ensure /preview route
125
+ if (options.updatePreview !== false) {
126
+ const componentsDir = options.output || path.join("components", ".mycontext");
127
+ await this.updatePreviewRegistry(componentsDir);
128
+ await this.ensurePreviewRoute();
129
+ }
130
+ // Guidance for refinement step
131
+ console.log(chalk_1.default.blue("\n🧩 Core-first step complete: edit 'components/.mycontext/core/BrandComp.tsx' until you're happy."));
132
+ console.log(chalk_1.default.gray(" You can also run: mycontext enhance components/.mycontext/core/BrandComp.tsx --prompt 'Tweak spacing/colors'\n"));
133
+ // If non-interactive, stop here
134
+ if (options.yes) {
135
+ return;
136
+ }
137
+ // Ask whether to proceed with remaining components now
138
+ const answer = await (0, prompts_1.default)({
139
+ type: "toggle",
140
+ name: "proceed",
141
+ message: "Proceed to generate the remaining components now? (You can rerun later)",
142
+ initial: false,
143
+ active: "yes",
144
+ inactive: "no",
145
+ });
146
+ if (answer?.proceed) {
147
+ await this.generateAllComponents(options, spinner, userInfo.userId);
148
+ }
149
+ return;
150
+ }
149
151
  if (isAll) {
150
152
  await this.generateAllComponents(options, spinner, userInfo.userId);
151
153
  }
@@ -285,6 +287,7 @@ class GenerateComponentsCommand {
285
287
  let generatedGroups = 0;
286
288
  for (const group of groups) {
287
289
  spinner.updateText(`Generating ${group.name} components...`);
290
+ console.log(chalk_1.default.gray(`\n[mycontext] Reminder: generate → QA → docs for group '${group.name}'`));
288
291
  const groupDir = path.join(componentsDir, this.toKebabCase(group.name));
289
292
  await this.fs.ensureDir(groupDir);
290
293
  const components = group.components || [];
@@ -306,6 +309,8 @@ class GenerateComponentsCommand {
306
309
  await this.updatePreviewRegistry(componentsDir);
307
310
  await this.ensurePreviewRoute();
308
311
  }
312
+ // Post-generation: scan actual imports and ensure missing shadcn primitives are installed
313
+ await this.scanAndInstallShadcnFromComponents(componentsDir, spinner);
309
314
  spinner.success({
310
315
  text: `Generated ${totalComponents} components across ${generatedGroups} groups!`,
311
316
  });
@@ -322,6 +327,21 @@ class GenerateComponentsCommand {
322
327
  });
323
328
  // Post-run hints
324
329
  this.printNextStepsAfterComponents(options);
330
+ // Optionally open preview in browser
331
+ if (options.openPreview !== false) {
332
+ try {
333
+ const url = "http://localhost:3000/preview";
334
+ console.log(chalk_1.default.blue(`\n🌐 Opening preview: ${url}`));
335
+ // best-effort open using the OS default opener
336
+ const opener = process.platform === "darwin"
337
+ ? "open"
338
+ : process.platform === "win32"
339
+ ? "start"
340
+ : "xdg-open";
341
+ (0, child_process_1.execSync)(`${opener} ${url}`, { stdio: "ignore" });
342
+ }
343
+ catch { }
344
+ }
325
345
  }
326
346
  async generateComponentGroup(groupName, options, spinner, userId) {
327
347
  spinner.updateText(`Generating ${groupName} components...`);
@@ -370,6 +390,8 @@ class GenerateComponentsCommand {
370
390
  await this.updatePreviewRegistry(compBaseDir);
371
391
  await this.ensurePreviewRoute();
372
392
  }
393
+ // Post-generation: scan actual imports and ensure missing shadcn primitives are installed
394
+ await this.scanAndInstallShadcnFromComponents(compBaseDir, spinner);
373
395
  spinner.success({
374
396
  text: `Generated ${components.length} components in ${group.name}!`,
375
397
  });
@@ -380,6 +402,204 @@ class GenerateComponentsCommand {
380
402
  });
381
403
  console.log(chalk_1.default.gray(` • index.ts`));
382
404
  console.log(chalk_1.default.gray(` • page.tsx`));
405
+ // Optionally open preview in browser
406
+ if (options.openPreview !== false) {
407
+ try {
408
+ const url = "http://localhost:3000/preview";
409
+ console.log(chalk_1.default.blue(`\n🌐 Opening preview: ${url}`));
410
+ const opener = process.platform === "darwin"
411
+ ? "open"
412
+ : process.platform === "win32"
413
+ ? "start"
414
+ : "xdg-open";
415
+ (0, child_process_1.execSync)(`${opener} ${url}`, { stdio: "ignore" });
416
+ }
417
+ catch { }
418
+ }
419
+ }
420
+ /**
421
+ * Generate a single core BrandComp using PRD/types/brand context to act as the design anchor.
422
+ */
423
+ async generateCoreBrandComp(options, spinner) {
424
+ spinner.updateText("Generating core BrandComp...");
425
+ const componentsDir = options.output || path.join("components", ".mycontext");
426
+ const groupDir = path.join(componentsDir, "core");
427
+ await this.fs.ensureDir(groupDir);
428
+ // Ensure shadcn initialized
429
+ await this.ensureShadcnComponentsInstalled([
430
+ {
431
+ name: "Core",
432
+ components: [
433
+ {
434
+ name: "BrandComp",
435
+ type: "layout",
436
+ description: "Core brand canvas",
437
+ tags: ["layout", "canvas"],
438
+ },
439
+ ],
440
+ },
441
+ ], spinner);
442
+ // Best-effort brand token application
443
+ await this.applyBrandTokens();
444
+ const brandComp = {
445
+ name: "BrandComp",
446
+ type: "layout",
447
+ description: "A core brand canvas showcasing typography, primary/secondary colors, interactive states, and spacing. Acts as a reference for other components.",
448
+ userStories: [
449
+ "As a designer, I can see brand colors and typography applied consistently.",
450
+ "As a developer, I can reference spacing, radius, and interactive states.",
451
+ ],
452
+ actionFunctions: [],
453
+ dependencies: ["react"],
454
+ tags: ["brand", "layout", "canvas"],
455
+ };
456
+ // Try sub-agent generation first
457
+ try {
458
+ const { orchestrator } = await Promise.resolve().then(() => __importStar(require("../agents/orchestrator/SubAgentOrchestrator")));
459
+ const codeResult = (await orchestrator.executeAgent("CodeGenSubAgent", {
460
+ component: brandComp,
461
+ group: { name: "Core" },
462
+ options: {
463
+ ...options,
464
+ context: {
465
+ prd: this.contextArtifacts.prd,
466
+ types: this.contextArtifacts.types,
467
+ },
468
+ },
469
+ }));
470
+ await this.fs.writeFile(path.join(groupDir, `BrandComp.tsx`), codeResult.code);
471
+ }
472
+ catch {
473
+ const code = this.generateComponentCode(brandComp, { name: "Core" }, {
474
+ ...options,
475
+ context: {
476
+ prd: this.contextArtifacts.prd,
477
+ types: this.contextArtifacts.types,
478
+ },
479
+ });
480
+ await this.fs.writeFile(path.join(groupDir, `BrandComp.tsx`), code);
481
+ }
482
+ // Group index and preview
483
+ await this.generateGroupIndex({
484
+ name: "Core",
485
+ description: "Core brand canvas",
486
+ components: [brandComp],
487
+ }, groupDir);
488
+ await this.generatePreviewPage({
489
+ name: "Core",
490
+ description: "Core brand canvas",
491
+ components: [brandComp],
492
+ }, groupDir);
493
+ spinner.success({ text: "Generated core BrandComp." });
494
+ }
495
+ /**
496
+ * Scan generated TSX files for imports from '@/components/ui/*' and ensure those shadcn primitives are installed.
497
+ */
498
+ async scanAndInstallShadcnFromComponents(componentsBaseDir, spinner) {
499
+ try {
500
+ const projectRoot = process.cwd();
501
+ const pkgJsonPath = path.join(projectRoot, "package.json");
502
+ if (!(await fs.pathExists(pkgJsonPath)))
503
+ return;
504
+ const needed = new Set();
505
+ const walk = async (dir) => {
506
+ const entries = await fs.readdir(dir);
507
+ for (const entry of entries) {
508
+ const full = path.join(dir, entry);
509
+ const stat = await fs.stat(full);
510
+ if (stat.isDirectory())
511
+ await walk(full);
512
+ else if (entry.endsWith(".tsx")) {
513
+ const src = await fs.readFile(full, "utf8");
514
+ const re = /from\s+["']@\/components\/ui\/([^"']+)["']/g;
515
+ let m;
516
+ while ((m = re.exec(src))) {
517
+ const mod = m[1];
518
+ if (mod)
519
+ needed.add(mod);
520
+ }
521
+ }
522
+ }
523
+ };
524
+ await walk(componentsBaseDir);
525
+ if (needed.size === 0)
526
+ return;
527
+ // Filter out already-present ui files
528
+ const uiDir = path.join(projectRoot, "components", "ui");
529
+ const missing = [];
530
+ for (const name of needed) {
531
+ const p = path.join(uiDir, `${name}.tsx`);
532
+ if (!(await fs.pathExists(p)))
533
+ missing.push(name);
534
+ }
535
+ if (missing.length === 0)
536
+ return;
537
+ spinner.updateText(`Installing missing shadcn primitives from imports (${missing.length})...`);
538
+ const pm = await this.detectPackageManager(projectRoot);
539
+ try {
540
+ if (pm === "pnpm") {
541
+ (0, child_process_1.execSync)(`pnpm dlx shadcn@latest add ${missing.join(" ")}`.trim(), {
542
+ cwd: projectRoot,
543
+ stdio: "inherit",
544
+ });
545
+ }
546
+ else {
547
+ (0, child_process_1.execSync)(`npx shadcn@latest add ${missing.join(" ")}`.trim(), {
548
+ cwd: projectRoot,
549
+ stdio: "inherit",
550
+ });
551
+ }
552
+ }
553
+ catch {
554
+ console.log(chalk_1.default.yellow(" ⚠️ shadcn add (post-scan) failed; you can add components manually."));
555
+ }
556
+ }
557
+ catch (error) {
558
+ console.log(chalk_1.default.yellow(` ⚠️ shadcn post-scan encountered an issue: ${error instanceof Error ? error.message : String(error)}`));
559
+ }
560
+ }
561
+ /**
562
+ * Apply brand tokens to globals.css (:root variables) if branding exists.
563
+ */
564
+ async applyBrandTokens() {
565
+ try {
566
+ const projectRoot = process.cwd();
567
+ const appDir = (await fs.pathExists(path.join(projectRoot, "src", "app")))
568
+ ? path.join(projectRoot, "src", "app")
569
+ : path.join(projectRoot, "app");
570
+ const globalsPath = path.join(appDir, "globals.css");
571
+ if (!(await fs.pathExists(globalsPath)))
572
+ return;
573
+ const brandPath = path.join(projectRoot, ".mycontext", "03-branding.md");
574
+ if (!(await fs.pathExists(brandPath)))
575
+ return;
576
+ const brand = await fs.readFile(brandPath, "utf8");
577
+ const pick = (label) => {
578
+ const m = brand.match(new RegExp(label + ".*?(#[0-9a-fA-F]{6})"));
579
+ return m ? m[1] : null;
580
+ };
581
+ const primary = pick("primary") || pick("Primary") || null;
582
+ const secondary = pick("secondary") || pick("Secondary") || null;
583
+ const accent = pick("accent") || pick("Accent") || null;
584
+ if (!primary && !secondary && !accent)
585
+ return;
586
+ let css = await fs.readFile(globalsPath, "utf8");
587
+ const ensureVar = (name, value) => {
588
+ const re = new RegExp(`(--${name}:\s*)([^;]+)(;)`);
589
+ if (re.test(css))
590
+ css = css.replace(re, `$1${value}$3`);
591
+ else
592
+ css = css.replace(/:root\s*\{/, (m) => `${m}\n --${name}: ${value};`);
593
+ };
594
+ if (primary)
595
+ ensureVar("primary", primary);
596
+ if (secondary)
597
+ ensureVar("secondary", secondary);
598
+ if (accent)
599
+ ensureVar("accent", accent);
600
+ await fs.writeFile(globalsPath, css);
601
+ }
602
+ catch { }
383
603
  }
384
604
  async generateComponent(component, group, groupDir, options, userId) {
385
605
  try {
@@ -441,15 +661,23 @@ class GenerateComponentsCommand {
441
661
  .replace(new RegExp(`${safeName} Default`, "g"), `${safeName}Default`);
442
662
  await this.fs.writeFile(componentPath, fixedCode);
443
663
  // Execute QA and docs in parallel
664
+ const componentWithContext = {
665
+ ...component,
666
+ _context: {
667
+ group: group?.name,
668
+ prd: this.contextArtifacts.prd,
669
+ types: this.contextArtifacts.types,
670
+ },
671
+ };
444
672
  const [qaResult, docsResult] = (await Promise.all([
445
673
  orchestrator.executeAgent("QASubAgent", {
446
674
  code: codeResult.code,
447
- component,
675
+ component: componentWithContext,
448
676
  standards: ["typescript", "react", "accessibility"],
449
677
  }),
450
678
  orchestrator.executeAgent("DocsSubAgent", {
451
679
  code: codeResult.code,
452
- component,
680
+ component: componentWithContext,
453
681
  format: "readme",
454
682
  }),
455
683
  ]));
@@ -521,6 +749,11 @@ class GenerateComponentsCommand {
521
749
  async ensureShadcnComponentsInstalled(groups, spinner) {
522
750
  try {
523
751
  const projectRoot = process.cwd();
752
+ const pkgJsonPath = path.join(projectRoot, "package.json");
753
+ if (!(await fs.pathExists(pkgJsonPath))) {
754
+ console.log(chalk_1.default.gray(" Skipping shadcn setup: no package.json in current directory. Run inside an existing Next.js project."));
755
+ return;
756
+ }
524
757
  const componentsJsonPath = path.join(projectRoot, "components.json");
525
758
  // Initialize shadcn if components.json is missing
526
759
  if (!(await fs.pathExists(componentsJsonPath))) {
@@ -557,6 +790,10 @@ class GenerateComponentsCommand {
557
790
  const names = Array.from(needed);
558
791
  spinner.updateText(`Installing shadcn components (${names.length})...`);
559
792
  try {
793
+ if (!(await fs.pathExists(pkgJsonPath))) {
794
+ console.log(chalk_1.default.gray(" Skipping 'shadcn add' because no package.json was found."));
795
+ return;
796
+ }
560
797
  if (pkgManager === "pnpm") {
561
798
  (0, child_process_1.execSync)(`pnpm dlx shadcn@latest add ${names.join(" ")}`, {
562
799
  cwd: projectRoot,
@@ -1058,7 +1295,6 @@ export default ${name};
1058
1295
  e.preventDefault();
1059
1296
  setIsSubmitting(true);
1060
1297
  try {
1061
- // TODO: Implement form submission logic
1062
1298
  onSubmit?.(formData);
1063
1299
  } catch (error) {
1064
1300
  console.error("Form submission error:", error);
@@ -1173,14 +1409,14 @@ export default ${name};
1173
1409
  case "handleLogin":
1174
1410
  return `
1175
1411
  export async function handleLogin(email: string, password: string) {
1176
- // TODO: Implement login logic
1412
+ // Implement login logic in application layer
1177
1413
  console.log("Logging in with:", { email, password });
1178
1414
  return { success: true };
1179
1415
  }`;
1180
1416
  case "handleSignup":
1181
1417
  return `
1182
1418
  export async function handleSignup(email: string, password: string, name: string) {
1183
- // TODO: Implement signup logic
1419
+ // Implement signup logic in application layer
1184
1420
  console.log("Signing up with:", { email, password, name });
1185
1421
  return { success: true };
1186
1422
  }`;
@@ -1193,14 +1429,14 @@ export function validateEmail(email: string): boolean {
1193
1429
  case "checkUsername":
1194
1430
  return `
1195
1431
  export async function checkUsername(username: string): Promise<boolean> {
1196
- // TODO: Implement username availability check
1432
+ // Implement username availability check in application layer
1197
1433
  console.log("Checking username:", username);
1198
1434
  return true;
1199
1435
  }`;
1200
1436
  default:
1201
1437
  return `
1202
1438
  export function ${func}() {
1203
- // TODO: Implement ${func} logic
1439
+ // Implement ${func} logic in application layer
1204
1440
  console.log("${func} called");
1205
1441
  }`;
1206
1442
  }
@@ -1407,14 +1643,14 @@ function groupBy<T, K extends string | number>(
1407
1643
  try {
1408
1644
  const projectRoot = process.cwd();
1409
1645
  const typesPathCandidates = [
1410
- path.join(projectRoot, '.mycontext', '02-types.ts'),
1411
- path.join(projectRoot, '.mycontext', 'types.ts'),
1412
- path.join(projectRoot, 'context', 'types.ts'),
1646
+ path.join(projectRoot, ".mycontext", "02-types.ts"),
1647
+ path.join(projectRoot, ".mycontext", "types.ts"),
1648
+ path.join(projectRoot, "context", "types.ts"),
1413
1649
  ];
1414
- let typesSource = '';
1650
+ let typesSource = "";
1415
1651
  for (const p of typesPathCandidates) {
1416
1652
  if (await fs.pathExists(p)) {
1417
- typesSource = await fs.readFile(p, 'utf8');
1653
+ typesSource = await fs.readFile(p, "utf8");
1418
1654
  break;
1419
1655
  }
1420
1656
  }
@@ -1427,7 +1663,7 @@ function groupBy<T, K extends string | number>(
1427
1663
  const body = match[2];
1428
1664
  const fields = {};
1429
1665
  body
1430
- .split('\n')
1666
+ .split("\n")
1431
1667
  .map((l) => l.trim())
1432
1668
  .filter(Boolean)
1433
1669
  .forEach((line) => {
@@ -1445,19 +1681,19 @@ function groupBy<T, K extends string | number>(
1445
1681
  const stat = await fs.stat(groupPath);
1446
1682
  if (!stat.isDirectory())
1447
1683
  continue;
1448
- const files = (await fs.readdir(groupPath)).filter((f) => f.endsWith('.tsx'));
1684
+ const files = (await fs.readdir(groupPath)).filter((f) => f.endsWith(".tsx"));
1449
1685
  for (const file of files) {
1450
- if (file === 'page.tsx')
1686
+ if (file === "page.tsx")
1451
1687
  continue;
1452
- const base = file.replace(/\.tsx$/, '');
1688
+ const base = file.replace(/\.tsx$/, "");
1453
1689
  const full = path.join(groupPath, file);
1454
- const src = await fs.readFile(full, 'utf8');
1690
+ const src = await fs.readFile(full, "utf8");
1455
1691
  const propsInterfaceMatch = src.match(/interface\s+(\w+)Props\s*\{([\s\S]*?)\}/);
1456
1692
  if (!propsInterfaceMatch)
1457
1693
  continue;
1458
1694
  const propsBody = propsInterfaceMatch[2];
1459
1695
  const entries = propsBody
1460
- .split('\n')
1696
+ .split("\n")
1461
1697
  .map((l) => l.trim())
1462
1698
  .filter((l) => /:\s*/.test(l));
1463
1699
  const propsObj = {};
@@ -1476,7 +1712,7 @@ function groupBy<T, K extends string | number>(
1476
1712
  }
1477
1713
  }
1478
1714
  const out = `export const previewProps: Record<string, any> = ${JSON.stringify(propsMap, null, 2)};\n`;
1479
- await fs.writeFile(path.join(componentsDir, 'preview-props.ts'), out);
1715
+ await fs.writeFile(path.join(componentsDir, "preview-props.ts"), out);
1480
1716
  }
1481
1717
  catch (error) {
1482
1718
  console.log(chalk_1.default.yellow(` ⚠️ Failed to build preview props: ${error instanceof Error ? error.message : String(error)}`));
@@ -1485,14 +1721,14 @@ function groupBy<T, K extends string | number>(
1485
1721
  generateSampleValue(typeStr, interfaces, depth) {
1486
1722
  if (depth > 2)
1487
1723
  return undefined;
1488
- const t = typeStr.replace(/\s+/g, '');
1489
- if (t.endsWith('[]')) {
1724
+ const t = typeStr.replace(/\s+/g, "");
1725
+ if (t.endsWith("[]")) {
1490
1726
  const inner = t.slice(0, -2);
1491
1727
  const v = this.generateSampleValue(inner, interfaces, depth + 1);
1492
1728
  return v === undefined ? undefined : [v];
1493
1729
  }
1494
1730
  if (/^string\b/.test(t))
1495
- return 'Sample';
1731
+ return "Sample";
1496
1732
  if (/^number\b/.test(t))
1497
1733
  return 1;
1498
1734
  if (/^boolean\b/.test(t))