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.
- package/README.md +80 -0
- package/dist/commands/add.d.ts +42 -12
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +413 -93
- package/dist/commands/diff.d.ts +6 -0
- package/dist/commands/diff.d.ts.map +1 -1
- package/dist/commands/diff.js +90 -20
- package/dist/commands/init.d.ts +17 -5
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +87 -64
- package/dist/commands/mcp.d.ts +123 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +289 -0
- package/dist/commands/migrate.d.ts +41 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +139 -0
- package/dist/commands/registries.d.ts +46 -0
- package/dist/commands/registries.d.ts.map +1 -0
- package/dist/commands/registries.js +152 -0
- package/dist/commands/remove.d.ts +11 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.js +171 -0
- package/dist/commands/schema.d.ts +16 -0
- package/dist/commands/schema.d.ts.map +1 -0
- package/dist/commands/schema.js +32 -0
- package/dist/commands/status.d.ts +40 -4
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +149 -25
- package/dist/commands/theme.d.ts.map +1 -1
- package/dist/commands/theme.js +3 -37
- package/dist/commands/update.d.ts +18 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +197 -6
- package/dist/index.js +76 -5
- package/dist/schemas/registry-config.schema.json +62 -0
- package/dist/schemas/registry-item.schema.json +63 -0
- package/dist/schemas/registry.schema.json +15 -0
- package/dist/types/registry.d.ts +50 -0
- package/dist/types/registry.d.ts.map +1 -0
- package/dist/types/registry.js +10 -0
- package/dist/utils/auto-install.d.ts +11 -0
- package/dist/utils/auto-install.d.ts.map +1 -0
- package/dist/utils/auto-install.js +29 -0
- package/dist/utils/framework-detect.d.ts +20 -0
- package/dist/utils/framework-detect.d.ts.map +1 -0
- package/dist/utils/framework-detect.js +97 -0
- package/dist/utils/fuzzy-search.d.ts +16 -0
- package/dist/utils/fuzzy-search.d.ts.map +1 -0
- package/dist/utils/fuzzy-search.js +67 -0
- package/dist/utils/paths.d.ts +26 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +35 -0
- package/dist/utils/registry-config.d.ts +27 -0
- package/dist/utils/registry-config.d.ts.map +1 -0
- package/dist/utils/registry-config.js +94 -0
- package/dist/utils/registry-resolver.d.ts +26 -0
- package/dist/utils/registry-resolver.d.ts.map +1 -1
- package/dist/utils/registry-resolver.js +134 -10
- package/dist/utils/snapshot.d.ts +20 -0
- package/dist/utils/snapshot.d.ts.map +1 -0
- package/dist/utils/snapshot.js +32 -0
- package/dist/utils/themes.d.ts +17 -0
- package/dist/utils/themes.d.ts.map +1 -0
- package/dist/utils/themes.js +49 -0
- package/dist/utils/tsconfig-detect.d.ts +18 -0
- package/dist/utils/tsconfig-detect.d.ts.map +1 -0
- package/dist/utils/tsconfig-detect.js +121 -0
- package/package.json +9 -3
package/dist/commands/diff.d.ts
CHANGED
|
@@ -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":"
|
|
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"}
|
package/dist/commands/diff.js
CHANGED
|
@@ -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
|
-
|
|
9
|
-
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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 (
|
|
25
|
-
|
|
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 =
|
|
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}`));
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
type
|
|
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,
|
|
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"}
|
package/dist/commands/init.js
CHANGED
|
@@ -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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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:
|
|
190
|
+
css: config.cssEntryPoint ?? `${layout.sourceRoot}/index.css`,
|
|
210
191
|
},
|
|
211
192
|
aliases: {
|
|
212
|
-
components: config.
|
|
213
|
-
blocks: config.blockPath
|
|
214
|
-
|
|
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/
|
|
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,
|
|
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"
|
|
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(
|
|
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(
|
|
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(
|
|
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,
|
|
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(
|
|
389
|
+
filesCreated.push(`${sourceRoot}/lib/cn.ts`);
|
|
375
390
|
// 4. Copy tokens and create CSS
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
|
|
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(
|
|
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"}
|