inai-react-components 0.1.7 → 1.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 (68) hide show
  1. package/README.md +80 -0
  2. package/dist/commands/add.d.ts +42 -12
  3. package/dist/commands/add.d.ts.map +1 -1
  4. package/dist/commands/add.js +413 -93
  5. package/dist/commands/diff.d.ts +6 -0
  6. package/dist/commands/diff.d.ts.map +1 -1
  7. package/dist/commands/diff.js +90 -20
  8. package/dist/commands/init.d.ts +17 -5
  9. package/dist/commands/init.d.ts.map +1 -1
  10. package/dist/commands/init.js +87 -64
  11. package/dist/commands/mcp.d.ts +123 -0
  12. package/dist/commands/mcp.d.ts.map +1 -0
  13. package/dist/commands/mcp.js +289 -0
  14. package/dist/commands/migrate.d.ts +41 -0
  15. package/dist/commands/migrate.d.ts.map +1 -0
  16. package/dist/commands/migrate.js +139 -0
  17. package/dist/commands/registries.d.ts +46 -0
  18. package/dist/commands/registries.d.ts.map +1 -0
  19. package/dist/commands/registries.js +152 -0
  20. package/dist/commands/remove.d.ts +11 -0
  21. package/dist/commands/remove.d.ts.map +1 -0
  22. package/dist/commands/remove.js +171 -0
  23. package/dist/commands/schema.d.ts +16 -0
  24. package/dist/commands/schema.d.ts.map +1 -0
  25. package/dist/commands/schema.js +32 -0
  26. package/dist/commands/status.d.ts +40 -4
  27. package/dist/commands/status.d.ts.map +1 -1
  28. package/dist/commands/status.js +149 -25
  29. package/dist/commands/theme.d.ts.map +1 -1
  30. package/dist/commands/theme.js +3 -37
  31. package/dist/commands/update.d.ts +18 -1
  32. package/dist/commands/update.d.ts.map +1 -1
  33. package/dist/commands/update.js +197 -6
  34. package/dist/index.js +76 -5
  35. package/dist/schemas/registry-config.schema.json +62 -0
  36. package/dist/schemas/registry-item.schema.json +63 -0
  37. package/dist/schemas/registry.schema.json +15 -0
  38. package/dist/types/registry.d.ts +50 -0
  39. package/dist/types/registry.d.ts.map +1 -0
  40. package/dist/types/registry.js +10 -0
  41. package/dist/utils/auto-install.d.ts +11 -0
  42. package/dist/utils/auto-install.d.ts.map +1 -0
  43. package/dist/utils/auto-install.js +29 -0
  44. package/dist/utils/framework-detect.d.ts +20 -0
  45. package/dist/utils/framework-detect.d.ts.map +1 -0
  46. package/dist/utils/framework-detect.js +97 -0
  47. package/dist/utils/fuzzy-search.d.ts +16 -0
  48. package/dist/utils/fuzzy-search.d.ts.map +1 -0
  49. package/dist/utils/fuzzy-search.js +67 -0
  50. package/dist/utils/paths.d.ts +26 -0
  51. package/dist/utils/paths.d.ts.map +1 -0
  52. package/dist/utils/paths.js +35 -0
  53. package/dist/utils/registry-config.d.ts +27 -0
  54. package/dist/utils/registry-config.d.ts.map +1 -0
  55. package/dist/utils/registry-config.js +94 -0
  56. package/dist/utils/registry-resolver.d.ts +26 -0
  57. package/dist/utils/registry-resolver.d.ts.map +1 -1
  58. package/dist/utils/registry-resolver.js +134 -10
  59. package/dist/utils/snapshot.d.ts +20 -0
  60. package/dist/utils/snapshot.d.ts.map +1 -0
  61. package/dist/utils/snapshot.js +32 -0
  62. package/dist/utils/themes.d.ts +17 -0
  63. package/dist/utils/themes.d.ts.map +1 -0
  64. package/dist/utils/themes.js +49 -0
  65. package/dist/utils/tsconfig-detect.d.ts +18 -0
  66. package/dist/utils/tsconfig-detect.d.ts.map +1 -0
  67. package/dist/utils/tsconfig-detect.js +121 -0
  68. package/package.json +9 -3
@@ -1,4 +1,10 @@
1
1
  import { type RegistryComponent } from "./status.js";
2
+ /**
3
+ * Render a unified-style colored diff between two strings using a real
4
+ * LCS-based algorithm (`diffLines` from the `diff` package). Lines that
5
+ * changed are shown in red/green; unchanged lines are only shown as dim
6
+ * context within `CONTEXT_LINES` of a change.
7
+ */
2
8
  export declare function computeDiff(localContent: string, registryContent: string): string;
3
9
  export declare function findComponentInRegistry(registryPath: string, componentName: string): RegistryComponent | null;
4
10
  export declare function runDiff(componentName: string, rootDir: string): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/commands/diff.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAC;AAGrB,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CA+BjF;AAED,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,GACpB,iBAAiB,GAAG,IAAI,CAW1B;AAED,wBAAsB,OAAO,CAC3B,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAgEjB;AAED,wBAAsB,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CActE"}
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/commands/diff.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,iBAAiB,EAEvB,MAAM,aAAa,CAAC;AAMrB;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAqEjF;AAED,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,GACpB,iBAAiB,GAAG,IAAI,CAW1B;AA6BD,wBAAsB,OAAO,CAC3B,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAgEjB;AAED,wBAAsB,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CActE"}
@@ -2,33 +2,81 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import chalk from "chalk";
4
4
  import ora from "ora";
5
+ import { diffLines } from "diff";
5
6
  import { readComponentsJson, readRegistryJson, } from "./status.js";
6
7
  import { resolveRegistryDir } from "../utils/registry-resolver.js";
8
+ import { resolveLocalDir } from "../utils/paths.js";
9
+ const CONTEXT_LINES = 2;
10
+ /**
11
+ * Render a unified-style colored diff between two strings using a real
12
+ * LCS-based algorithm (`diffLines` from the `diff` package). Lines that
13
+ * changed are shown in red/green; unchanged lines are only shown as dim
14
+ * context within `CONTEXT_LINES` of a change.
15
+ */
7
16
  export function computeDiff(localContent, registryContent) {
8
- const localLines = localContent.split("\n");
9
- const registryLines = registryContent.split("\n");
17
+ // `diffLines` reports hunks: each has `value` (the text), and flags
18
+ // `added` (present only in the second arg) or `removed` (present only in
19
+ // the first arg). Neither flag means unchanged.
20
+ // We pass (registryContent, localContent) so that "added" means the
21
+ // local file added a line vs the registry (green +), and "removed" means
22
+ // the line was removed from the registry in the local file (red -).
23
+ const hunks = diffLines(registryContent, localContent);
24
+ const hasChanges = hunks.some((h) => h.added || h.removed);
25
+ if (!hasChanges) {
26
+ return chalk.green("No differences found. Component is up to date.");
27
+ }
10
28
  const output = [];
11
- const maxLen = Math.max(localLines.length, registryLines.length);
12
- let hasChanges = false;
13
- for (let i = 0; i < maxLen; i++) {
14
- const localLine = localLines[i];
15
- const registryLine = registryLines[i];
16
- if (localLine === registryLine) {
17
- output.push(chalk.dim(` ${localLine ?? ""}`));
29
+ for (let i = 0; i < hunks.length; i++) {
30
+ const hunk = hunks[i];
31
+ const lines = hunk.value.replace(/\n$/, "").split("\n");
32
+ if (hunk.added) {
33
+ for (const line of lines) {
34
+ output.push(chalk.green(`+ ${line}`));
35
+ }
36
+ }
37
+ else if (hunk.removed) {
38
+ for (const line of lines) {
39
+ output.push(chalk.red(`- ${line}`));
40
+ }
18
41
  }
19
42
  else {
20
- hasChanges = true;
21
- if (registryLine !== undefined) {
22
- output.push(chalk.red(`- ${registryLine}`));
43
+ // Unchanged hunk — keep only CONTEXT_LINES around neighboring changes.
44
+ const prevChanged = i > 0 && (hunks[i - 1].added || hunks[i - 1].removed);
45
+ const nextChanged = i < hunks.length - 1 && (hunks[i + 1].added || hunks[i + 1].removed);
46
+ if (!prevChanged && !nextChanged) {
47
+ continue;
48
+ }
49
+ if (prevChanged && nextChanged && lines.length > CONTEXT_LINES * 2) {
50
+ // Show trailing context from previous change, a separator, then
51
+ // leading context for next change.
52
+ for (let j = 0; j < CONTEXT_LINES; j++) {
53
+ output.push(chalk.dim(` ${lines[j]}`));
54
+ }
55
+ output.push(chalk.dim(" ..."));
56
+ for (let j = lines.length - CONTEXT_LINES; j < lines.length; j++) {
57
+ output.push(chalk.dim(` ${lines[j]}`));
58
+ }
23
59
  }
24
- if (localLine !== undefined) {
25
- output.push(chalk.green(`+ ${localLine}`));
60
+ else if (prevChanged) {
61
+ const end = Math.min(lines.length, CONTEXT_LINES);
62
+ for (let j = 0; j < end; j++) {
63
+ output.push(chalk.dim(` ${lines[j]}`));
64
+ }
65
+ if (lines.length > CONTEXT_LINES) {
66
+ output.push(chalk.dim(" ..."));
67
+ }
68
+ }
69
+ else if (nextChanged) {
70
+ const start = Math.max(0, lines.length - CONTEXT_LINES);
71
+ if (start > 0) {
72
+ output.push(chalk.dim(" ..."));
73
+ }
74
+ for (let j = start; j < lines.length; j++) {
75
+ output.push(chalk.dim(` ${lines[j]}`));
76
+ }
26
77
  }
27
78
  }
28
79
  }
29
- if (!hasChanges) {
30
- return chalk.green("No differences found. Component is up to date.");
31
- }
32
80
  return output.join("\n");
33
81
  }
34
82
  export function findComponentInRegistry(registryPath, componentName) {
@@ -42,6 +90,26 @@ export function findComponentInRegistry(registryPath, componentName) {
42
90
  ];
43
91
  return allItems.find((c) => c.name === componentName) ?? null;
44
92
  }
93
+ /**
94
+ * Map a registry component to the alias slot that should hold its local copy.
95
+ * Fixes the earlier bug where `diff` always assumed `aliases.components`.
96
+ */
97
+ function getLocalAliasDir(component, componentsJson) {
98
+ const type = component.type.toLowerCase();
99
+ if (type === "block") {
100
+ return resolveLocalDir(componentsJson.aliases.blocks, componentsJson);
101
+ }
102
+ if (type === "template") {
103
+ const templatesAlias = componentsJson.aliases.templates;
104
+ if (templatesAlias) {
105
+ return resolveLocalDir(templatesAlias, componentsJson);
106
+ }
107
+ const blocksDir = resolveLocalDir(componentsJson.aliases.blocks, componentsJson);
108
+ const parent = path.dirname(blocksDir);
109
+ return path.join(parent, "templates");
110
+ }
111
+ return resolveLocalDir(componentsJson.aliases.components, componentsJson);
112
+ }
45
113
  export async function runDiff(componentName, rootDir) {
46
114
  const componentsJson = readComponentsJson(rootDir);
47
115
  if (!componentsJson) {
@@ -57,11 +125,14 @@ export async function runDiff(componentName, rootDir) {
57
125
  return chalk.yellow(`Component "${componentName}" has no files in the registry.`);
58
126
  }
59
127
  const results = [];
128
+ const localComponentDir = getLocalAliasDir(registryComponent, componentsJson);
129
+ const isMultiFile = registryComponent.type === "block" || registryComponent.type === "template";
60
130
  for (const filePath of registryComponent.files) {
61
131
  const registryFilePath = path.join(registryDir, filePath);
62
- const localComponentDir = componentsJson.aliases.components.replace(/^@\//, "src/");
63
132
  const fileName = path.basename(filePath);
64
- const localFilePath = path.join(rootDir, localComponentDir, fileName);
133
+ const localFilePath = isMultiFile
134
+ ? path.join(rootDir, localComponentDir, componentName, fileName)
135
+ : path.join(rootDir, localComponentDir, fileName);
65
136
  results.push(chalk.bold(`\nDiff for ${fileName}:`));
66
137
  results.push(chalk.dim("─".repeat(60)));
67
138
  if (!fs.existsSync(registryFilePath)) {
@@ -71,7 +142,6 @@ export async function runDiff(componentName, rootDir) {
71
142
  const registryContent = fs.readFileSync(registryFilePath, "utf-8");
72
143
  if (!fs.existsSync(localFilePath)) {
73
144
  results.push(chalk.yellow(`Local file not found at ${localComponentDir}/${fileName}. Component may not be installed.`));
74
- // Show what registry has as all additions
75
145
  const lines = registryContent.split("\n");
76
146
  for (const line of lines) {
77
147
  results.push(chalk.green(`+ ${line}`));
@@ -1,5 +1,6 @@
1
- declare const AVAILABLE_THEMES: readonly ["inai", "monday", "linear", "notion", "vercel", "anthropic", "shadcn-default", "shadcn-blue", "shadcn-green", "shadcn-orange", "shadcn-red", "shadcn-rose", "shadcn-violet", "shadcn-yellow", "shadcn-amber", "shadcn-lime", "shadcn-emerald", "shadcn-teal", "shadcn-cyan", "shadcn-sky", "shadcn-indigo", "shadcn-purple", "shadcn-fuchsia", "shadcn-pink"];
2
- type Theme = (typeof AVAILABLE_THEMES)[number];
1
+ import { type Framework } from "../utils/framework-detect.js";
2
+ import { type ProjectLayout } from "../utils/tsconfig-detect.js";
3
+ type Theme = string;
3
4
  declare const FONT_PRESETS: readonly [{
4
5
  readonly name: "outfit";
5
6
  readonly label: "Outfit";
@@ -221,17 +222,21 @@ export interface InitConfig {
221
222
  fontBody: FontPreset;
222
223
  fontHeading: FontPreset;
223
224
  radius: number;
224
- importAlias: string;
225
- utilsAlias: string;
226
225
  tanstackRouter: boolean;
227
226
  tanstackQuery: boolean;
228
227
  tanstackForm: boolean;
229
228
  tanstackTable: boolean;
229
+ framework?: Framework;
230
+ cssEntryPoint?: string;
231
+ /** Detected project layout — drives file destinations in `runInit`. */
232
+ layout?: ProjectLayout;
230
233
  }
231
234
  export interface ComponentsJson {
232
235
  $schema: string;
233
236
  registrySource?: string;
234
237
  style: string;
238
+ framework?: Framework;
239
+ layout?: ProjectLayout;
235
240
  tailwind: {
236
241
  config: string;
237
242
  css: string;
@@ -254,7 +259,7 @@ export interface ComponentsJson {
254
259
  table: boolean;
255
260
  };
256
261
  }
257
- export declare function promptInitConfig(registryDir?: string): Promise<InitConfig | null>;
262
+ export declare function promptInitConfig(registryDir?: string, framework?: Framework, layout?: ProjectLayout): Promise<InitConfig | null>;
258
263
  export declare function buildComponentsJson(config: InitConfig, repoUrl?: string): ComponentsJson;
259
264
  export declare function getCnTemplate(): string;
260
265
  export declare function getLocalTailwindCssTemplate(theme: Theme, fontBody: FontPreset, fontHeading: FontPreset, radius: number): string;
@@ -266,6 +271,13 @@ export declare function getLegacyTailwindCssTemplate(theme: Theme, fontBody: Fon
266
271
  * `data-theme` attribute on the HTML element.
267
272
  */
268
273
  export declare function normalizeThemeCss(css: string, theme: string): string;
274
+ /**
275
+ * Copies the i18n base files (context, types, defaults) from the registry
276
+ * to the project's <sourceRoot>/lib/. Required because ~75 components import
277
+ * `useUIMessages` from `./lib/i18n-context.js` — without these files, every
278
+ * subsequent `add` of an i18n-aware component would produce a broken import.
279
+ */
280
+ export declare function copyI18nFiles(registryDir: string | undefined, targetDir: string, sourceRoot: string): string[];
269
281
  export declare function runInit(config: InitConfig, targetDir: string, repoUrl?: string): Promise<{
270
282
  success: boolean;
271
283
  filesCreated: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAOA,QAAA,MAAM,gBAAgB,yWAyBZ,CAAC;AACX,KAAK,KAAK,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/C,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4DR,CAAC;AACX,KAAK,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAUxD,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,UAAU,CAAC;IACrB,WAAW,EAAE,UAAU,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,KAAK,EAAE,KAAK,CAAC;IACb,IAAI,EAAE;QACJ,IAAI,EAAE,UAAU,CAAC;QACjB,OAAO,EAAE,UAAU,CAAC;KACrB,CAAC;IACF,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE;QACR,MAAM,EAAE,OAAO,CAAC;QAChB,KAAK,EAAE,OAAO,CAAC;QACf,IAAI,EAAE,OAAO,CAAC;QACd,KAAK,EAAE,OAAO,CAAC;KAChB,CAAC;CACH;AAgBD,wBAAsB,gBAAgB,CACpC,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA8F5B;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,UAAU,EAClB,OAAO,CAAC,EAAE,MAAM,GACf,cAAc,CAkChB;AAED,wBAAgB,aAAa,IAAI,MAAM,CAQtC;AAOD,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAa/H;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAahI;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAoBpE;AA6ED,wBAAsB,OAAO,CAC3B,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA4CvD;AAED,wBAAsB,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0DjE"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,6BAA6B,CAAC;AAGrC,KAAK,KAAK,GAAG,MAAM,CAAC;AAEpB,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4DR,CAAC;AACX,KAAK,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAUxD,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,UAAU,CAAC;IACrB,WAAW,EAAE,UAAU,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,uEAAuE;IACvE,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,KAAK,EAAE,KAAK,CAAC;IACb,IAAI,EAAE;QACJ,IAAI,EAAE,UAAU,CAAC;QACjB,OAAO,EAAE,UAAU,CAAC;KACrB,CAAC;IACF,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE;QACR,MAAM,EAAE,OAAO,CAAC;QAChB,KAAK,EAAE,OAAO,CAAC;QACf,IAAI,EAAE,OAAO,CAAC;QACd,KAAK,EAAE,OAAO,CAAC;KAChB,CAAC;CACH;AAgBD,wBAAsB,gBAAgB,CACpC,WAAW,CAAC,EAAE,MAAM,EACpB,SAAS,CAAC,EAAE,SAAS,EACrB,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA0F5B;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,UAAU,EAClB,OAAO,CAAC,EAAE,MAAM,GACf,cAAc,CAwChB;AAED,wBAAgB,aAAa,IAAI,MAAM,CAQtC;AAOD,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAc/H;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAahI;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAoBpE;AA0FD;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CAeV;AAED,wBAAsB,OAAO,CAC3B,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAqEvD;AAED,wBAAsB,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0EjE"}
@@ -4,32 +4,10 @@ import chalk from "chalk";
4
4
  import ora from "ora";
5
5
  import prompts from "prompts";
6
6
  import { cloneRegistry, getCacheDir } from "../utils/registry-resolver.js";
7
- const AVAILABLE_THEMES = [
8
- "inai",
9
- "monday",
10
- "linear",
11
- "notion",
12
- "vercel",
13
- "anthropic",
14
- "shadcn-default",
15
- "shadcn-blue",
16
- "shadcn-green",
17
- "shadcn-orange",
18
- "shadcn-red",
19
- "shadcn-rose",
20
- "shadcn-violet",
21
- "shadcn-yellow",
22
- "shadcn-amber",
23
- "shadcn-lime",
24
- "shadcn-emerald",
25
- "shadcn-teal",
26
- "shadcn-cyan",
27
- "shadcn-sky",
28
- "shadcn-indigo",
29
- "shadcn-purple",
30
- "shadcn-fuchsia",
31
- "shadcn-pink",
32
- ];
7
+ import { THEME_NAMES } from "../utils/themes.js";
8
+ import { detectFramework, frameworkLabel, getCssEntryPoint, } from "../utils/framework-detect.js";
9
+ import { detectProjectLayout, } from "../utils/tsconfig-detect.js";
10
+ const AVAILABLE_THEMES = THEME_NAMES;
33
11
  const FONT_PRESETS = [
34
12
  // Sans-serif — geometric & modern
35
13
  { name: "outfit", label: "Outfit", family: "'Outfit', system-ui, sans-serif" },
@@ -111,20 +89,24 @@ function discoverThemes(registryDir) {
111
89
  }
112
90
  return [...AVAILABLE_THEMES];
113
91
  }
114
- export async function promptInitConfig(registryDir) {
92
+ export async function promptInitConfig(registryDir, framework, layout) {
115
93
  const themes = discoverThemes(registryDir);
94
+ const sourceRoot = layout?.sourceRoot ?? "src";
95
+ const defaultCssEntry = framework
96
+ ? getCssEntryPoint(framework, sourceRoot)
97
+ : `${sourceRoot}/index.css`;
116
98
  const response = await prompts([
117
99
  {
118
100
  type: "text",
119
101
  name: "componentPath",
120
102
  message: "Where would you like to install components?",
121
- initial: "src/components/ui",
103
+ initial: `${sourceRoot}/components/ui`,
122
104
  },
123
105
  {
124
106
  type: "text",
125
107
  name: "blockPath",
126
108
  message: "Where would you like to install blocks?",
127
- initial: "src/components/blocks",
109
+ initial: `${sourceRoot}/components/blocks`,
128
110
  },
129
111
  {
130
112
  type: "select",
@@ -154,18 +136,6 @@ export async function promptInitConfig(registryDir) {
154
136
  choices: RADIUS_OPTIONS.map((r) => ({ title: r.label, value: r.value })),
155
137
  initial: 2,
156
138
  },
157
- {
158
- type: "text",
159
- name: "importAlias",
160
- message: "Configure the import alias for components:",
161
- initial: "@/components/ui",
162
- },
163
- {
164
- type: "text",
165
- name: "utilsAlias",
166
- message: "Configure the import alias for utils:",
167
- initial: "@/lib/utils",
168
- },
169
139
  {
170
140
  type: "confirm",
171
141
  name: "tanstackRouter",
@@ -198,22 +168,31 @@ export async function promptInitConfig(registryDir) {
198
168
  if (!response.componentPath) {
199
169
  return null;
200
170
  }
201
- return response;
171
+ const config = response;
172
+ config.framework = framework;
173
+ config.cssEntryPoint = defaultCssEntry;
174
+ config.layout = layout;
175
+ return config;
202
176
  }
203
177
  export function buildComponentsJson(config, repoUrl) {
178
+ const layout = config.layout ?? {
179
+ sourceRoot: "src",
180
+ aliasPrefix: "@/",
181
+ };
182
+ const utilsAlias = `${layout.aliasPrefix}lib/utils`;
204
183
  const json = {
205
184
  $schema: "https://inai-ui.dev/schema.json",
206
185
  style: "default",
186
+ framework: config.framework,
187
+ layout,
207
188
  tailwind: {
208
189
  config: "tailwind.config.ts",
209
- css: "src/index.css",
190
+ css: config.cssEntryPoint ?? `${layout.sourceRoot}/index.css`,
210
191
  },
211
192
  aliases: {
212
- components: config.importAlias,
213
- blocks: config.blockPath.startsWith("src/")
214
- ? `@/${config.blockPath.slice(4)}`
215
- : config.blockPath,
216
- utils: config.utilsAlias,
193
+ components: config.componentPath,
194
+ blocks: config.blockPath,
195
+ utils: utilsAlias,
217
196
  },
218
197
  theme: config.theme,
219
198
  font: {
@@ -248,7 +227,8 @@ function getFontFamily(font) {
248
227
  }
249
228
  export function getLocalTailwindCssTemplate(theme, fontBody, fontHeading, radius) {
250
229
  return `@import "tailwindcss";
251
- @import "./styles/tokens/index.css";
230
+ @import "./styles/tokens/primitives/colors.css";
231
+ @import "./styles/tokens/base.css";
252
232
  @import "./styles/tokens/themes/${theme}.css";
253
233
  @import "./styles/tokens/presets/typography.css";
254
234
  @import "./styles/tokens/presets/animations.css";
@@ -310,19 +290,30 @@ function copyDirRecursive(src, dest) {
310
290
  }
311
291
  return copied;
312
292
  }
313
- function copyTokensToProject(registryDir, targetDir, theme) {
293
+ function copyTokensToProject(registryDir, targetDir, theme, sourceRoot) {
314
294
  const tokensSrc = path.join(registryDir, "packages", "tokens", "src");
315
- const tokensDest = path.join(targetDir, "src", "styles", "tokens");
295
+ const tokensDest = path.join(targetDir, sourceRoot, "styles", "tokens");
296
+ const tokensRelBase = `${sourceRoot}/styles/tokens`;
316
297
  const copied = [];
317
298
  if (!fs.existsSync(tokensSrc))
318
299
  return copied;
319
300
  fs.mkdirSync(tokensDest, { recursive: true });
320
301
  // Copy base files
321
- for (const file of ["base.css", "index.css"]) {
302
+ for (const file of ["base.css"]) {
322
303
  const src = path.join(tokensSrc, file);
323
304
  if (fs.existsSync(src)) {
324
305
  fs.copyFileSync(src, path.join(tokensDest, file));
325
- copied.push(`src/styles/tokens/${file}`);
306
+ copied.push(`${tokensRelBase}/${file}`);
307
+ }
308
+ }
309
+ // Copy primitives (color scales referenced by all themes)
310
+ const primitivesSrc = path.join(tokensSrc, "primitives");
311
+ const primitivesDest = path.join(tokensDest, "primitives");
312
+ if (fs.existsSync(primitivesSrc)) {
313
+ const primitiveCopied = copyDirRecursive(primitivesSrc, primitivesDest);
314
+ for (const file of primitiveCopied) {
315
+ const rel = path.relative(targetDir, file);
316
+ copied.push(rel);
326
317
  }
327
318
  }
328
319
  // Copy selected theme (normalized so it applies without data-theme attribute)
@@ -336,7 +327,7 @@ function copyTokensToProject(registryDir, targetDir, theme) {
336
327
  const rawCss = fs.readFileSync(themeSrc, "utf-8");
337
328
  const normalizedCss = normalizeThemeCss(rawCss, theme);
338
329
  fs.writeFileSync(path.join(themesDest, themeFile), normalizedCss);
339
- copied.push(`src/styles/tokens/themes/${themeFile}`);
330
+ copied.push(`${tokensRelBase}/themes/${themeFile}`);
340
331
  }
341
332
  }
342
333
  // Copy presets
@@ -348,14 +339,38 @@ function copyTokensToProject(registryDir, targetDir, theme) {
348
339
  const src = path.join(presetsSrc, file);
349
340
  if (fs.existsSync(src)) {
350
341
  fs.copyFileSync(src, path.join(presetsDest, file));
351
- copied.push(`src/styles/tokens/presets/${file}`);
342
+ copied.push(`${tokensRelBase}/presets/${file}`);
352
343
  }
353
344
  }
354
345
  }
355
346
  return copied;
356
347
  }
348
+ /**
349
+ * Copies the i18n base files (context, types, defaults) from the registry
350
+ * to the project's <sourceRoot>/lib/. Required because ~75 components import
351
+ * `useUIMessages` from `./lib/i18n-context.js` — without these files, every
352
+ * subsequent `add` of an i18n-aware component would produce a broken import.
353
+ */
354
+ export function copyI18nFiles(registryDir, targetDir, sourceRoot) {
355
+ if (!registryDir)
356
+ return [];
357
+ const files = ["i18n-context.tsx", "i18n-types.ts", "i18n-defaults.ts"];
358
+ const srcBase = path.join(registryDir, "packages", "ui", "src", "lib");
359
+ const destBase = path.join(targetDir, sourceRoot, "lib");
360
+ fs.mkdirSync(destBase, { recursive: true });
361
+ const copied = [];
362
+ for (const file of files) {
363
+ const src = path.join(srcBase, file);
364
+ if (!fs.existsSync(src))
365
+ continue;
366
+ fs.copyFileSync(src, path.join(destBase, file));
367
+ copied.push(`${sourceRoot}/lib/${file}`);
368
+ }
369
+ return copied;
370
+ }
357
371
  export async function runInit(config, targetDir, repoUrl) {
358
372
  const filesCreated = [];
373
+ const sourceRoot = config.layout?.sourceRoot ?? "src";
359
374
  // 1. Create components.json
360
375
  const componentsJsonPath = path.join(targetDir, "components.json");
361
376
  const componentsJson = buildComponentsJson(config, repoUrl);
@@ -366,32 +381,40 @@ export async function runInit(config, targetDir, repoUrl) {
366
381
  fs.mkdirSync(componentDir, { recursive: true });
367
382
  const blockDir = path.join(targetDir, config.blockPath);
368
383
  fs.mkdirSync(blockDir, { recursive: true });
369
- // 3. Create cn.ts utility
370
- const utilsDir = path.join(targetDir, "src", "lib");
384
+ // 3. Create cn.ts utility under the detected source root
385
+ const utilsDir = path.join(targetDir, sourceRoot, "lib");
371
386
  fs.mkdirSync(utilsDir, { recursive: true });
372
387
  const cnPath = path.join(utilsDir, "cn.ts");
373
388
  fs.writeFileSync(cnPath, getCnTemplate());
374
- filesCreated.push("src/lib/cn.ts");
389
+ filesCreated.push(`${sourceRoot}/lib/cn.ts`);
375
390
  // 4. Copy tokens and create CSS
376
- const cssDir = path.join(targetDir, "src");
377
- fs.mkdirSync(cssDir, { recursive: true });
378
- const cssPath = path.join(cssDir, "index.css");
391
+ const cssRelPath = config.cssEntryPoint ?? `${sourceRoot}/index.css`;
392
+ const cssPath = path.join(targetDir, cssRelPath);
393
+ fs.mkdirSync(path.dirname(cssPath), { recursive: true });
379
394
  if (repoUrl) {
380
395
  // Remote mode: copy tokens from cached registry
381
396
  const registryDir = getCacheDir();
382
- const tokenFiles = copyTokensToProject(registryDir, targetDir, config.theme);
397
+ const tokenFiles = copyTokensToProject(registryDir, targetDir, config.theme, sourceRoot);
383
398
  filesCreated.push(...tokenFiles);
399
+ // Copy i18n base files so components importing useUIMessages resolve
400
+ const i18nFiles = copyI18nFiles(registryDir, targetDir, sourceRoot);
401
+ filesCreated.push(...i18nFiles);
384
402
  fs.writeFileSync(cssPath, getLocalTailwindCssTemplate(config.theme, config.fontBody, config.fontHeading, config.radius));
385
403
  }
386
404
  else {
387
405
  // Local mode: reference @company/tokens package
388
406
  fs.writeFileSync(cssPath, getLegacyTailwindCssTemplate(config.theme, config.fontBody, config.fontHeading, config.radius));
389
407
  }
390
- filesCreated.push("src/index.css");
408
+ filesCreated.push(cssRelPath);
391
409
  return { success: true, filesCreated };
392
410
  }
393
411
  export async function initCommand(repoUrl) {
394
412
  console.log(chalk.bold("\nInAI UI - Project Initialization\n"));
413
+ const cwd = process.cwd();
414
+ const detectedFramework = detectFramework(cwd);
415
+ const detectedLayout = detectProjectLayout(cwd);
416
+ console.log(chalk.dim(`Detected framework: ${frameworkLabel(detectedFramework)}`));
417
+ console.log(chalk.dim(`Detected layout: ${detectedLayout.sourceRoot}/ with alias ${detectedLayout.aliasPrefix}`));
395
418
  if (repoUrl) {
396
419
  const spinner = ora("Cloning component registry...").start();
397
420
  try {
@@ -407,7 +430,7 @@ export async function initCommand(repoUrl) {
407
430
  }
408
431
  }
409
432
  const registryDir = repoUrl ? getCacheDir() : undefined;
410
- const config = await promptInitConfig(registryDir);
433
+ const config = await promptInitConfig(registryDir, detectedFramework, detectedLayout);
411
434
  if (!config) {
412
435
  console.log(chalk.yellow("\nInitialization cancelled."));
413
436
  process.exit(0);
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Print the JSON config fragment that users must drop into their Claude
3
+ * Desktop or Cursor `mcpServers` block. Invoked from `inai-ui mcp init`.
4
+ */
5
+ export declare function printMcpConfig(): void;
6
+ export interface ToolTextResult {
7
+ content: Array<{
8
+ type: "text";
9
+ text: string;
10
+ }>;
11
+ isError?: boolean;
12
+ }
13
+ export declare function handleListComponents(args: {
14
+ category?: string;
15
+ } | undefined, cwd: string): Promise<ToolTextResult>;
16
+ export declare function handleViewComponent(args: {
17
+ name?: string;
18
+ } | undefined, cwd: string): Promise<ToolTextResult>;
19
+ export declare function handleAddComponent(args: {
20
+ name?: string;
21
+ force?: boolean;
22
+ } | undefined, cwd: string): Promise<ToolTextResult>;
23
+ export declare function handleDiffComponent(args: {
24
+ name?: string;
25
+ } | undefined, cwd: string): Promise<ToolTextResult>;
26
+ export declare function handleUpdateComponent(args: {
27
+ name?: string;
28
+ } | undefined, cwd: string): Promise<ToolTextResult>;
29
+ export declare function handleListThemes(): Promise<ToolTextResult>;
30
+ export declare function handleStatus(args: {
31
+ json?: boolean;
32
+ } | undefined, cwd: string): Promise<ToolTextResult>;
33
+ export declare const MCP_TOOLS: readonly [{
34
+ readonly name: "list_components";
35
+ readonly description: "List all available components, blocks and templates in the InAI UI registry.";
36
+ readonly inputSchema: {
37
+ readonly type: "object";
38
+ readonly properties: {
39
+ readonly category: {
40
+ readonly type: "string";
41
+ readonly description: "Optional type filter (e.g. 'component', 'form', 'block').";
42
+ };
43
+ };
44
+ };
45
+ }, {
46
+ readonly name: "view_component";
47
+ readonly description: "View the source code of a component from the registry.";
48
+ readonly inputSchema: {
49
+ readonly type: "object";
50
+ readonly properties: {
51
+ readonly name: {
52
+ readonly type: "string";
53
+ readonly description: "Component name";
54
+ };
55
+ };
56
+ readonly required: readonly ["name"];
57
+ };
58
+ }, {
59
+ readonly name: "add_component";
60
+ readonly description: "Install a component (and its transitive registry dependencies) into the current project.";
61
+ readonly inputSchema: {
62
+ readonly type: "object";
63
+ readonly properties: {
64
+ readonly name: {
65
+ readonly type: "string";
66
+ readonly description: "Component name";
67
+ };
68
+ readonly force: {
69
+ readonly type: "boolean";
70
+ readonly description: "Overwrite existing files without prompting.";
71
+ };
72
+ };
73
+ readonly required: readonly ["name"];
74
+ };
75
+ }, {
76
+ readonly name: "diff_component";
77
+ readonly description: "Show a unified diff between the locally-installed component and the registry version.";
78
+ readonly inputSchema: {
79
+ readonly type: "object";
80
+ readonly properties: {
81
+ readonly name: {
82
+ readonly type: "string";
83
+ readonly description: "Component name";
84
+ };
85
+ };
86
+ readonly required: readonly ["name"];
87
+ };
88
+ }, {
89
+ readonly name: "update_component";
90
+ readonly description: "Update an installed component to the latest registry version using a 3-way merge against the snapshot captured at install time. Emits conflict markers when local and registry edits overlap.";
91
+ readonly inputSchema: {
92
+ readonly type: "object";
93
+ readonly properties: {
94
+ readonly name: {
95
+ readonly type: "string";
96
+ readonly description: "Component name";
97
+ };
98
+ };
99
+ readonly required: readonly ["name"];
100
+ };
101
+ }, {
102
+ readonly name: "list_themes";
103
+ readonly description: "List the available InAI UI themes with their categories and descriptions.";
104
+ readonly inputSchema: {
105
+ readonly type: "object";
106
+ readonly properties: {};
107
+ };
108
+ }, {
109
+ readonly name: "project_status";
110
+ readonly description: "Return the InAI UI project status (HEALTHY / DRIFT / OUTDATED / MISSING per component).";
111
+ readonly inputSchema: {
112
+ readonly type: "object";
113
+ readonly properties: {
114
+ readonly json: {
115
+ readonly type: "boolean";
116
+ readonly description: "Return JSON payload (default true).";
117
+ };
118
+ };
119
+ };
120
+ }];
121
+ export declare function runMcp(cwd?: string): Promise<void>;
122
+ export declare function mcpCommand(subcommand?: "init"): Promise<void>;
123
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../src/commands/mcp.ts"],"names":[],"mappings":"AAgCA;;;GAGG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAID,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AASD,wBAAsB,oBAAoB,CACxC,IAAI,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,EACvC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,cAAc,CAAC,CAKzB;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,EACnC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,cAAc,CAAC,CA8BzB;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,EACpD,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,cAAc,CAAC,CAkBzB;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,EACnC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,cAAc,CAAC,CAmCzB;AAED,wBAAsB,qBAAqB,CACzC,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,EACnC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,cAAc,CAAC,CAgBzB;AAED,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,cAAc,CAAC,CAEhE;AAED,wBAAsB,YAAY,CAChC,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,EACpC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,cAAc,CAAC,CAGzB;AAID,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoFZ,CAAC;AAEX,wBAAsB,MAAM,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiEvE;AAED,wBAAsB,UAAU,CAC9B,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAMf"}