inventive-ui 0.0.9 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import path27 from "path";
4
+ import path26 from "path";
5
5
  import { Command } from "commander";
6
6
 
7
7
  // src/utils/ui.ts
@@ -190,7 +190,7 @@ var BANNER_COMPACT = [
190
190
  var FULL_BANNER_WIDTH = 101;
191
191
  function resolveCliVersion() {
192
192
  try {
193
- return true ? "0.0.9" : "1.0.0";
193
+ return true ? "0.0.11" : "1.0.0";
194
194
  } catch {
195
195
  return "1.0.0";
196
196
  }
@@ -373,8 +373,8 @@ function resolveApiBaseUrl() {
373
373
  );
374
374
  }
375
375
  if (parsed.pathname && parsed.pathname !== "/" && parsed.pathname !== "") {
376
- const path28 = parsed.pathname.replace(/\/+$/, "");
377
- if (path28 && !/^\/[a-zA-Z0-9._/-]+$/.test(path28)) {
376
+ const path27 = parsed.pathname.replace(/\/+$/, "");
377
+ if (path27 && !/^\/[a-zA-Z0-9._/-]+$/.test(path27)) {
378
378
  throw new CLIError(
379
379
  "IUI_API_URL path contains invalid characters.",
380
380
  "Use a simple path prefix such as /v1"
@@ -434,7 +434,7 @@ var COMPONENTS_PACKAGE = "@inventive-ui/components";
434
434
  var NPM_SCOPE = "@inventive-ui";
435
435
  var IUI_DIR = ".iui";
436
436
  var GLOBAL_CONFIG_DIR = ".iui";
437
- var PROJECT_CONFIG_FILE = "iui.config.ts";
437
+ var PROJECT_CONFIG_FILE = "theme.config.ts";
438
438
  var REQUIRED_REACT_MAJOR = 19;
439
439
  var REACT_SAFE_VERSION = "^19.0.0";
440
440
  var REQUIRED_VITE_MAJOR = 6;
@@ -596,7 +596,7 @@ var EMOJI_FAMILIES = [
596
596
  "twitter",
597
597
  "native"
598
598
  ];
599
- var DEFAULT_EMOJI_SKIN_TONE = "medium-light";
599
+ var DEFAULT_EMOJI_SKIN_TONE = "mediumLight";
600
600
  var EMOJI_FAMILY_LABELS = {
601
601
  apple: "Apple",
602
602
  google: "Google",
@@ -1428,7 +1428,7 @@ function resolveFrameworkScriptsDir(startCwd) {
1428
1428
  if (existsSync(loader)) return scriptsDir;
1429
1429
  }
1430
1430
  throw new CLIError(
1431
- `Cannot scaffold iui.config.ts: ${FRAMEWORK_PACKAGE} is not installed or is missing scripts/load-framework-theme-defaults.mjs.`
1431
+ `Cannot scaffold theme.config.ts: ${FRAMEWORK_PACKAGE} is not installed or is missing scripts/load-framework-theme-defaults.mjs.`
1432
1432
  );
1433
1433
  }
1434
1434
  function buildProjectConfigSource(cwd = process.cwd()) {
@@ -1443,42 +1443,6 @@ function buildProjectConfigSource(cwd = process.cwd()) {
1443
1443
  });
1444
1444
  }
1445
1445
 
1446
- // src/utils/security/identifiers.ts
1447
- var SLUG_RE = /^[a-z][a-z0-9-]*$/;
1448
- var JS_IDENTIFIER_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
1449
- var NPM_SCOPE_IMPORT_RE = /^@inventive-ui\/[a-z0-9][a-z0-9._-]*$/;
1450
- var NPM_COMPONENT_SUBPATH_RE = /^@inventive-ui\/components\/[A-Za-z][A-Za-z0-9-]*$/;
1451
- function assertComponentSlug(slug) {
1452
- if (!SLUG_RE.test(slug)) {
1453
- throw new CLIError(
1454
- `Invalid component slug: "${slug}"`,
1455
- "Use lowercase letters, numbers, and hyphens (e.g. button, input)."
1456
- );
1457
- }
1458
- }
1459
- function assertJsIdentifier(name, label) {
1460
- if (!JS_IDENTIFIER_RE.test(name)) {
1461
- throw new CLIError(`Invalid ${label}: "${name}"`);
1462
- }
1463
- }
1464
- function assertImportSpecifier(specifier) {
1465
- if (NPM_SCOPE_IMPORT_RE.test(specifier)) return;
1466
- if (NPM_COMPONENT_SUBPATH_RE.test(specifier)) return;
1467
- if (/^@inventive-ui\/[a-z0-9][a-z0-9-]*$/.test(specifier)) return;
1468
- throw new CLIError(`Unsafe import specifier: "${specifier}"`);
1469
- }
1470
- function escapeTsStringLiteral(value) {
1471
- return JSON.stringify(value);
1472
- }
1473
- function sanitizePackageVersionHeader(value) {
1474
- if (!value) return null;
1475
- const trimmed = value.trim();
1476
- if (!/^[0-9A-Za-z.+~^<>= -]+$/.test(trimmed) || trimmed.length > 64) {
1477
- throw new CLIError("Server returned an invalid package version header.");
1478
- }
1479
- return trimmed;
1480
- }
1481
-
1482
1446
  // src/utils/config-patch/vite-config.ts
1483
1447
  import ts from "typescript";
1484
1448
  var IUI_MANAGED_MARKER = "@iui-managed";
@@ -1969,393 +1933,40 @@ function patchProjectConfigBuildBlock(content) {
1969
1933
  // src/utils/config-patch/component-config.ts
1970
1934
  import ts2 from "typescript";
1971
1935
 
1972
- // src/utils/componentExports.ts
1973
- import path7 from "path";
1974
- import fs6 from "fs-extra";
1975
- function toRecord(value) {
1976
- if (!value || typeof value !== "object" || Array.isArray(value)) return null;
1977
- return value;
1978
- }
1979
- function toPascalCase(value) {
1980
- return value.replace(/(^|[-_\s]+)([a-zA-Z0-9])/g, (_m, _p, c) => c.toUpperCase()).replace(/[^a-zA-Z0-9]/g, "");
1981
- }
1982
- function readComponentsPackageInfo(cwd) {
1983
- const packageRoot = resolvePackageDir("@inventive-ui/components", cwd);
1984
- if (!packageRoot) return null;
1985
- const pkgPath = path7.join(packageRoot, "package.json");
1986
- if (!fs6.existsSync(pkgPath)) return null;
1987
- try {
1988
- const pkg = fs6.readJsonSync(pkgPath);
1989
- const exportsField = toRecord(pkg.exports) ?? {};
1990
- const rootExport = toRecord(exportsField["."]);
1991
- const rootTypes = resolveTypesPathFromExportEntry(rootExport) ?? (typeof pkg.types === "string" ? pkg.types : null);
1992
- return {
1993
- packageRoot,
1994
- exportsField,
1995
- rootTypesPath: rootTypes ? path7.join(packageRoot, rootTypes) : null
1996
- };
1997
- } catch {
1998
- return null;
1999
- }
2000
- }
2001
- function resolveTypesPathFromExportEntry(entry) {
2002
- if (!entry) return null;
2003
- if (typeof entry === "string") return null;
2004
- const obj = toRecord(entry);
2005
- if (!obj) return null;
2006
- if (typeof obj.types === "string") return obj.types;
2007
- for (const key of ["import", "require", "default", "node", "browser"]) {
2008
- const nested = toRecord(obj[key]);
2009
- if (!nested) continue;
2010
- if (typeof nested.types === "string") return nested.types;
2011
- }
2012
- return null;
2013
- }
2014
- function parseNamedExportClause(clause, parsed) {
2015
- const parts = clause.split(",").map((p) => p.trim()).filter(Boolean);
2016
- for (const rawPart of parts) {
2017
- let part = rawPart;
2018
- let isTypeOnly = false;
2019
- if (part.startsWith("type ")) {
2020
- isTypeOnly = true;
2021
- part = part.slice("type ".length).trim();
2022
- }
2023
- const asMatch = part.match(/^([A-Za-z_][A-Za-z0-9_]*)\s+as\s+([A-Za-z_][A-Za-z0-9_]*)$/);
2024
- const symbol = asMatch ? asMatch[2] : part;
2025
- if (!symbol) continue;
2026
- if (isTypeOnly) parsed.typeExports.add(symbol);
2027
- else parsed.valueExports.add(symbol);
2028
- }
2029
- }
2030
- function mergeParsedExports(target, source) {
2031
- for (const sym of source.valueExports) target.valueExports.add(sym);
2032
- for (const sym of source.typeExports) target.typeExports.add(sym);
2033
- }
2034
- function resolveRelativeTypesPath(fromFile, rel) {
2035
- const base = path7.dirname(fromFile);
2036
- const noExt = path7.join(base, rel);
2037
- const candidates = [`${noExt}.d.ts`, path7.join(noExt, "index.d.ts")];
2038
- for (const candidate of candidates) {
2039
- if (fs6.existsSync(candidate)) return candidate;
2040
- }
2041
- return null;
2042
- }
2043
- function parseTypeExports(typesFilePath, visited = /* @__PURE__ */ new Set()) {
2044
- const parsed = {
2045
- valueExports: /* @__PURE__ */ new Set(),
2046
- typeExports: /* @__PURE__ */ new Set()
2047
- };
2048
- const abs = path7.resolve(typesFilePath);
2049
- if (visited.has(abs)) return parsed;
2050
- visited.add(abs);
2051
- if (!fs6.existsSync(abs)) return parsed;
2052
- let text = "";
2053
- try {
2054
- text = fs6.readFileSync(abs, "utf-8");
2055
- } catch {
2056
- return parsed;
2057
- }
2058
- applyTypeExportPatterns(text, parsed);
2059
- const reexportFrom = text.matchAll(
2060
- /export\s+(?:type\s+)?(?:\{[^}]*\}|\*)\s+from\s+["'](\.[^"']+)["']/g
2061
- );
2062
- for (const m of reexportFrom) {
2063
- const refPath = resolveRelativeTypesPath(abs, m[1]);
2064
- if (refPath) mergeParsedExports(parsed, parseTypeExports(refPath, visited));
2065
- }
2066
- return parsed;
2067
- }
2068
- function parseTypeExportsLocal(typesFilePath) {
2069
- const parsed = {
2070
- valueExports: /* @__PURE__ */ new Set(),
2071
- typeExports: /* @__PURE__ */ new Set()
2072
- };
2073
- const abs = path7.resolve(typesFilePath);
2074
- if (!fs6.existsSync(abs)) return parsed;
2075
- let text = "";
2076
- try {
2077
- text = fs6.readFileSync(abs, "utf-8");
2078
- } catch {
2079
- return parsed;
2080
- }
2081
- applyTypeExportPatterns(text, parsed);
2082
- return parsed;
2083
- }
2084
- function applyTypeExportPatterns(text, parsed) {
2085
- const valueDecl = /export\s+(?:declare\s+)?(?:const|let|var|function|class)\s+([A-Za-z_][A-Za-z0-9_]*)/g;
2086
- const typeDecl = /export\s+(?:declare\s+)?(?:type|interface)\s+([A-Za-z_][A-Za-z0-9_]*)/g;
2087
- const namedClause = /export\s+(?!type\s*\{)\{([^}]+)\}/g;
2088
- const typeNamedClause = /export\s+type\s*\{([^}]+)\}/g;
2089
- for (const m of text.matchAll(valueDecl)) {
2090
- parsed.valueExports.add(m[1]);
2091
- }
2092
- for (const m of text.matchAll(typeDecl)) {
2093
- parsed.typeExports.add(m[1]);
2094
- }
2095
- for (const m of text.matchAll(namedClause)) {
2096
- parseNamedExportClause(m[1], parsed);
2097
- }
2098
- for (const m of text.matchAll(typeNamedClause)) {
2099
- parseNamedExportClause(m[1], parsed);
2100
- }
2101
- }
2102
- function pickComponentName(item, parsed) {
2103
- const expected = [toPascalCase(item.dirName), toPascalCase(item.name)];
2104
- for (const name of expected) {
2105
- if (parsed.valueExports.has(name)) return name;
2106
- }
2107
- const lowered = new Set(expected.map((n) => n.toLowerCase()));
2108
- for (const exp of parsed.valueExports) {
2109
- if (lowered.has(exp.toLowerCase())) return exp;
2110
- }
2111
- return null;
2112
- }
2113
- function pickPropsName(componentName, parsed) {
2114
- const direct = `${componentName}Props`;
2115
- if (parsed.typeExports.has(direct) || parsed.valueExports.has(direct)) return direct;
2116
- for (const sym of parsed.typeExports) {
2117
- if (sym.toLowerCase() === direct.toLowerCase()) return sym;
2118
- }
2119
- for (const sym of parsed.valueExports) {
2120
- if (sym.toLowerCase() === direct.toLowerCase()) return sym;
2121
- }
2122
- return null;
2123
- }
2124
- function pickDefaultExportComponent(item, typesIndexPath) {
2125
- const expected = [toPascalCase(item.dirName), toPascalCase(item.name)];
2126
- for (const name of expected) {
2127
- const mainTypesPath = findMainComponentTypesPath(typesIndexPath, name);
2128
- if (!mainTypesPath) continue;
2129
- const mainText = readTypesFileText(mainTypesPath);
2130
- const defaultExportMatch = mainText.match(/export\s+default\s+([A-Za-z_][A-Za-z0-9_]*)/);
2131
- if (!defaultExportMatch) continue;
2132
- const symbol = defaultExportMatch[1];
2133
- if (expected.some((candidate) => candidate.toLowerCase() === symbol.toLowerCase())) {
2134
- return symbol;
2135
- }
2136
- }
2137
- return null;
2138
- }
2139
- function readTypesFileText(typesFilePath) {
2140
- try {
2141
- return fs6.readFileSync(typesFilePath, "utf-8");
2142
- } catch {
2143
- return "";
2144
- }
2145
- }
2146
- function findMainComponentTypesPath(typesIndexPath, componentName) {
2147
- const dir = path7.dirname(typesIndexPath);
2148
- const indexText = readTypesFileText(typesIndexPath);
2149
- const fromMatches = indexText.matchAll(/from\s+["']\.\/([^"']+)["']/g);
2150
- for (const match of fromMatches) {
2151
- const candidate = path7.join(dir, `${match[1]}.d.ts`);
2152
- if (fs6.existsSync(candidate)) return candidate;
2153
- }
2154
- const byName = path7.join(dir, `${componentName}.d.ts`);
2155
- return fs6.existsSync(byName) ? byName : null;
2156
- }
2157
- function isNonCallableCompoundExport(typesText, symbolName) {
2158
- const objectDecl = new RegExp(
2159
- `(?:declare\\s+const|const)\\s+${symbolName}\\s*:\\s*\\{`
2160
- );
2161
- return objectDecl.test(typesText);
2162
- }
2163
- function pickCompoundRenderMember(typesText) {
2164
- if (/\bText\s*:\s*React\./.test(typesText)) return "Text";
2165
- const memberMatch = typesText.match(
2166
- /^\s+([A-Za-z_][A-Za-z0-9_]*)\s*:\s*React\.(?:ForwardRefExoticComponent|NamedExoticComponent|FC)/m
2167
- );
2168
- return memberMatch?.[1] ?? "Text";
2169
- }
2170
- function resolveLazyAccess(typesIndexPath, componentName) {
2171
- const indexText = readTypesFileText(typesIndexPath);
2172
- const mainTypesPath = findMainComponentTypesPath(typesIndexPath, componentName);
2173
- const mainText = mainTypesPath ? readTypesFileText(mainTypesPath) : "";
2174
- const defaultAsMatch = indexText.match(
2175
- new RegExp(`export\\s*\\{[^}]*\\bdefault\\s+as\\s+${componentName}\\b[^}]*\\}`)
2176
- );
2177
- const namedExportMatch = indexText.match(
2178
- new RegExp(`export\\s*\\{[^}]*\\b${componentName}\\b[^}]*\\}`)
2179
- );
2180
- const defaultExportMatch = mainText.match(/export\s+default\s+([A-Za-z_][A-Za-z0-9_]*)/);
2181
- const defaultSymbol = defaultExportMatch?.[1];
2182
- const compoundSymbol = defaultSymbol && isNonCallableCompoundExport(mainText, defaultSymbol) ? defaultSymbol : isNonCallableCompoundExport(mainText, componentName) ? componentName : null;
2183
- if (compoundSymbol) {
2184
- const member = pickCompoundRenderMember(mainText);
2185
- if (defaultAsMatch || namedExportMatch) {
2186
- return `.${componentName}.${member}`;
2187
- }
2188
- return `.default.${member}`;
2189
- }
2190
- if (defaultAsMatch || namedExportMatch) return `.${componentName}`;
2191
- if (defaultSymbol && defaultSymbol === componentName) {
2192
- return `.default`;
2193
- }
2194
- return `.${componentName}`;
2195
- }
2196
- function subpathExposesLazyBinding(typesIndexPath, componentName) {
2197
- const indexText = readTypesFileText(typesIndexPath);
2198
- if (new RegExp(`export\\s*\\{[^}]*\\bdefault\\s+as\\s+${componentName}\\b[^}]*\\}`).test(
2199
- indexText
2200
- )) {
2201
- return true;
2202
- }
2203
- if (new RegExp(`export\\s*\\{[^}]*\\b${componentName}\\b[^}]*\\}`).test(indexText)) {
2204
- return true;
2205
- }
2206
- if (/export\s+default\b/.test(indexText)) return true;
2207
- return pickComponentName(
2208
- { name: componentName, dirName: componentName },
2209
- parseTypeExportsLocal(typesIndexPath)
2210
- ) !== null;
2211
- }
2212
- function resolveLazyImport(pkgInfo, importSpecifier, typesFilePath, componentName) {
2213
- let lazyImportSpecifier = importSpecifier;
2214
- let lazyAccess = resolveLazyAccess(typesFilePath, componentName);
2215
- if (importSpecifier !== "@inventive-ui/components" && !subpathExposesLazyBinding(typesFilePath, componentName) && pkgInfo.rootTypesPath) {
2216
- lazyImportSpecifier = "@inventive-ui/components";
2217
- lazyAccess = `.${componentName}`;
2218
- }
2219
- return { lazyImportSpecifier, lazyAccess };
2220
- }
2221
- function describeExpected(item) {
2222
- return `${toPascalCase(item.dirName)} / ${toPascalCase(item.name)}`;
2223
- }
2224
- function resolveFromTypesFile(item, importSpecifier, typesFilePath, pkgInfo) {
2225
- const parsed = parseTypeExports(typesFilePath);
2226
- const indexParsed = parseTypeExportsLocal(typesFilePath);
2227
- const componentName = pickComponentName(item, parsed) ?? pickDefaultExportComponent(item, typesFilePath);
2228
- if (!componentName) {
2229
- return {
2230
- ok: false,
2231
- reason: `No matching component export in ${importSpecifier}. Expected ${describeExpected(item)}.`
2232
- };
1936
+ // src/utils/security/identifiers.ts
1937
+ var SLUG_RE = /^[a-z][a-z0-9-]*$/;
1938
+ var JS_IDENTIFIER_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
1939
+ var NPM_SCOPE_IMPORT_RE = /^@inventive-ui\/[a-z0-9][a-z0-9._-]*$/;
1940
+ var NPM_COMPONENT_SUBPATH_RE = /^@inventive-ui\/components\/[A-Za-z][A-Za-z0-9-]*$/;
1941
+ function assertComponentSlug(slug) {
1942
+ if (!SLUG_RE.test(slug)) {
1943
+ throw new CLIError(
1944
+ `Invalid component slug: "${slug}"`,
1945
+ "Use lowercase letters, numbers, and hyphens (e.g. button, input)."
1946
+ );
2233
1947
  }
2234
- const propsName = pickPropsName(componentName, indexParsed) ?? pickPropsName(componentName, parsed) ?? (() => {
2235
- const typesPath = path7.join(path7.dirname(typesFilePath), "types.d.ts");
2236
- if (!fs6.existsSync(typesPath)) return null;
2237
- return pickPropsName(componentName, parseTypeExports(typesPath));
2238
- })();
2239
- const lazyImport = resolveLazyImport(
2240
- pkgInfo,
2241
- importSpecifier,
2242
- typesFilePath,
2243
- componentName
2244
- );
2245
- return {
2246
- ok: true,
2247
- importSpecifier,
2248
- lazyImportSpecifier: lazyImport.lazyImportSpecifier,
2249
- componentName,
2250
- propsName: propsName ?? void 0,
2251
- lazyAccess: lazyImport.lazyAccess
2252
- };
2253
1948
  }
2254
- function exportCandidatesForItem(item) {
2255
- const candidates = [
2256
- `./${item.name}`,
2257
- `./${item.name.toLowerCase()}`,
2258
- `./${item.dirName}`,
2259
- `./${item.dirName.toLowerCase()}`
2260
- ];
2261
- return [...new Set(candidates)];
2262
- }
2263
- function componentFolderCandidates(item) {
2264
- return [
2265
- .../* @__PURE__ */ new Set([
2266
- item.dirName,
2267
- item.name,
2268
- toPascalCase(item.dirName),
2269
- toPascalCase(item.name)
2270
- ])
2271
- ];
2272
- }
2273
- function resolveWildcardTypesPath(pkgInfo, segment) {
2274
- const wildcardEntry = pkgInfo.exportsField["./*"];
2275
- if (!wildcardEntry) return null;
2276
- const typesRel = resolveTypesPathFromExportEntry(wildcardEntry);
2277
- if (!typesRel || !typesRel.includes("*")) return null;
2278
- const resolvedRel = typesRel.replace(/\*/g, segment);
2279
- const fullPath = path7.join(pkgInfo.packageRoot, resolvedRel);
2280
- return fs6.existsSync(fullPath) ? fullPath : null;
2281
- }
2282
- function resolveTypesPathForExportCandidate(pkgInfo, candidate) {
2283
- const entry = pkgInfo.exportsField[candidate];
2284
- if (entry) {
2285
- const typesRel = resolveTypesPathFromExportEntry(entry);
2286
- return typesRel ? path7.join(pkgInfo.packageRoot, typesRel) : null;
2287
- }
2288
- const segment = candidate.replace(/^\.\//, "");
2289
- return resolveWildcardTypesPath(pkgInfo, segment);
2290
- }
2291
- function resolveFromComponentFolders(item, pkgInfo) {
2292
- for (const folder of componentFolderCandidates(item)) {
2293
- const typesPath = resolveWildcardTypesPath(pkgInfo, folder) ?? (() => {
2294
- const directPath = path7.join(
2295
- pkgInfo.packageRoot,
2296
- "dist",
2297
- "components",
2298
- folder,
2299
- "index.d.ts"
2300
- );
2301
- return fs6.existsSync(directPath) ? directPath : null;
2302
- })();
2303
- if (!typesPath) continue;
2304
- const importSpecifier = `@inventive-ui/components/${folder}`;
2305
- try {
2306
- assertImportSpecifier(importSpecifier);
2307
- } catch {
2308
- continue;
2309
- }
2310
- const resolved = resolveFromTypesFile(item, importSpecifier, typesPath, pkgInfo);
2311
- if (resolved.ok) return resolved;
1949
+ function assertJsIdentifier(name, label) {
1950
+ if (!JS_IDENTIFIER_RE.test(name)) {
1951
+ throw new CLIError(`Invalid ${label}: "${name}"`);
2312
1952
  }
2313
- return null;
2314
1953
  }
2315
- function componentBuildExists(item, pkgInfo) {
2316
- return componentFolderCandidates(item).some(
2317
- (folder) => fs6.existsSync(path7.join(pkgInfo.packageRoot, "dist", "components", folder))
2318
- );
1954
+ function assertImportSpecifier(specifier) {
1955
+ if (NPM_SCOPE_IMPORT_RE.test(specifier)) return;
1956
+ if (NPM_COMPONENT_SUBPATH_RE.test(specifier)) return;
1957
+ if (/^@inventive-ui\/[a-z0-9][a-z0-9-]*$/.test(specifier)) return;
1958
+ throw new CLIError(`Unsafe import specifier: "${specifier}"`);
2319
1959
  }
2320
- function buildMissingComponentReason(item) {
2321
- return `Component "${item.name}" is listed in iui-manifest.json but is missing from the published @inventive-ui/components build (expected dist/components/${item.dirName}). Run a full components build, export ${describeExpected(item)} from dist/index.d.ts, and republish.`;
1960
+ function escapeTsStringLiteral(value) {
1961
+ return JSON.stringify(value);
2322
1962
  }
2323
- function resolveComponentExport(item, cwd = process.cwd()) {
2324
- const pkgInfo = readComponentsPackageInfo(cwd);
2325
- if (!pkgInfo) {
2326
- return {
2327
- ok: false,
2328
- reason: "@inventive-ui/components is not installed in node_modules."
2329
- };
2330
- }
2331
- const fromFolders = resolveFromComponentFolders(item, pkgInfo);
2332
- if (fromFolders?.ok) return fromFolders;
2333
- for (const candidate of exportCandidatesForItem(item)) {
2334
- const typesPath = resolveTypesPathForExportCandidate(pkgInfo, candidate);
2335
- if (!typesPath) continue;
2336
- const importSpecifier = `@inventive-ui/components/${candidate.replace(/^\.\//, "")}`;
2337
- try {
2338
- assertImportSpecifier(importSpecifier);
2339
- } catch {
2340
- continue;
2341
- }
2342
- const resolved = resolveFromTypesFile(item, importSpecifier, typesPath, pkgInfo);
2343
- if (resolved.ok) return resolved;
2344
- }
2345
- if (pkgInfo.rootTypesPath) {
2346
- const fromRoot = resolveFromTypesFile(item, "@inventive-ui/components", pkgInfo.rootTypesPath, pkgInfo);
2347
- if (fromRoot.ok) return fromRoot;
2348
- }
2349
- if (!componentBuildExists(item, pkgInfo)) {
2350
- return {
2351
- ok: false,
2352
- reason: buildMissingComponentReason(item)
2353
- };
1963
+ function sanitizePackageVersionHeader(value) {
1964
+ if (!value) return null;
1965
+ const trimmed = value.trim();
1966
+ if (!/^[0-9A-Za-z.+~^<>= -]+$/.test(trimmed) || trimmed.length > 64) {
1967
+ throw new CLIError("Server returned an invalid package version header.");
2354
1968
  }
2355
- return {
2356
- ok: false,
2357
- reason: `No matching component export for "${item.name}" in @inventive-ui/components. Expected a value export named ${describeExpected(item)}.`
2358
- };
1969
+ return trimmed;
2359
1970
  }
2360
1971
 
2361
1972
  // src/utils/config-patch/component-config.ts
@@ -2376,19 +1987,6 @@ function findComponentConfigObject(sourceFile) {
2376
1987
  visit(sourceFile);
2377
1988
  return found;
2378
1989
  }
2379
- function findComponentConfigMapType(sourceFile) {
2380
- let found;
2381
- const visit = (node) => {
2382
- if (found) return;
2383
- if (ts2.isTypeAliasDeclaration(node) && ts2.isIdentifier(node.name) && node.name.text === "ComponentConfigMap" && node.type && ts2.isTypeLiteralNode(node.type)) {
2384
- found = node.type;
2385
- return;
2386
- }
2387
- ts2.forEachChild(node, visit);
2388
- };
2389
- visit(sourceFile);
2390
- return found;
2391
- }
2392
1990
  function existingComponentKeys(obj) {
2393
1991
  const keys = /* @__PURE__ */ new Set();
2394
1992
  for (const prop of obj.properties) {
@@ -2398,33 +1996,14 @@ function existingComponentKeys(obj) {
2398
1996
  }
2399
1997
  return keys;
2400
1998
  }
2401
- function formatDefaultConfig(cfg) {
2402
- return JSON.stringify(cfg, null, 6).split("\n").map((line, i) => i === 0 ? line : ` ${line}`).join("\n");
2403
- }
2404
1999
  function buildComponentEntry(item) {
2405
2000
  assertJsIdentifier(item.dirName, "component dirName");
2406
- const cfg = item.meta?.defaultConfig ?? {};
2407
- const cfgStr = formatDefaultConfig(cfg);
2408
2001
  return ` ${item.dirName}: {
2409
- default: ${cfgStr},
2002
+ default: {},
2410
2003
  },
2411
2004
 
2412
2005
  `;
2413
2006
  }
2414
- function buildTypeEntry(item, cwd) {
2415
- const resolved = resolveComponentExport(item, cwd);
2416
- if (resolved.ok && resolved.propsName) {
2417
- return ` ${item.dirName}: { default: Partial<${resolved.propsName}> };`;
2418
- }
2419
- return ` ${item.dirName}: { default: Record<string, unknown> };`;
2420
- }
2421
- function buildTypeImport(item, cwd) {
2422
- const resolved = resolveComponentExport(item, cwd);
2423
- if (resolved.ok && resolved.propsName && resolved.importSpecifier) {
2424
- return `import type { ${resolved.propsName} } from "${resolved.importSpecifier}";`;
2425
- }
2426
- return null;
2427
- }
2428
2007
  function insertBeforeClosingBrace(source, objectEnd, insertion) {
2429
2008
  let pos = objectEnd - 1;
2430
2009
  while (pos >= 0 && /\s/.test(source[pos] ?? "")) pos--;
@@ -2436,7 +2015,7 @@ function insertBeforeClosingBrace(source, objectEnd, insertion) {
2436
2015
  }
2437
2016
  return source;
2438
2017
  }
2439
- function mergeComponentConfigContent(source, manifest, cwd) {
2018
+ function mergeComponentConfigContent(source, manifest) {
2440
2019
  if (!manifest || manifest.items.length === 0) {
2441
2020
  return { content: source, changed: false };
2442
2021
  }
@@ -2452,33 +2031,78 @@ function mergeComponentConfigContent(source, manifest, cwd) {
2452
2031
  const existing = existingComponentKeys(configObject);
2453
2032
  const missing = manifest.items.filter((item) => !existing.has(item.dirName));
2454
2033
  if (missing.length === 0) return { content: source, changed: false };
2455
- let next = source;
2456
2034
  const newEntries = missing.map((item) => buildComponentEntry(item)).join("");
2457
- next = insertBeforeClosingBrace(next, configObject.getEnd(), newEntries);
2458
- const typeLiteral = findComponentConfigMapType(
2459
- ts2.createSourceFile("component.config.ts", next, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TS)
2035
+ const next = insertBeforeClosingBrace(
2036
+ source,
2037
+ configObject.getEnd(),
2038
+ newEntries
2460
2039
  );
2461
- if (typeLiteral) {
2462
- const typeLines = `${missing.map((item) => buildTypeEntry(item, cwd)).join("\n")}
2463
- `;
2464
- next = insertBeforeClosingBrace(next, typeLiteral.getEnd(), typeLines);
2465
- }
2466
- const existingImportLines = new Set(next.match(/^import\s.+;$/gm) ?? []);
2467
- const newImports = missing.map((item) => buildTypeImport(item, cwd)).filter((line) => line !== null && !existingImportLines.has(line));
2468
- if (newImports.length > 0) {
2469
- const importMatches = [...next.matchAll(/^import\s.+;$/gm)];
2470
- const lastImport = importMatches.at(-1);
2471
- if (lastImport?.index !== void 0) {
2472
- const insertAt = lastImport.index + lastImport[0].length;
2473
- next = `${next.slice(0, insertAt)}
2474
- ${[...new Set(newImports)].join("\n")}${next.slice(insertAt)}`;
2475
- } else {
2476
- next = `${[...new Set(newImports)].join("\n")}
2040
+ return { content: next, changed: true };
2041
+ }
2477
2042
 
2478
- ${next}`;
2043
+ // src/utils/config-patch/tsconfig-iui.ts
2044
+ import path7 from "path";
2045
+ import fs6 from "fs-extra";
2046
+ function isSolutionStyleTsconfig(config) {
2047
+ const refs = config.references;
2048
+ return Array.isArray(refs) && refs.length > 0;
2049
+ }
2050
+ function patchJsonInclude(filePath, extra) {
2051
+ if (!fs6.existsSync(filePath)) return false;
2052
+ const raw = fs6.readJsonSync(filePath);
2053
+ const include = Array.isArray(raw.include) ? [...raw.include.map(String)] : [];
2054
+ let changed = false;
2055
+ for (const item of extra) {
2056
+ if (!include.includes(item)) {
2057
+ include.push(item);
2058
+ changed = true;
2479
2059
  }
2480
2060
  }
2481
- return { content: next, changed: true };
2061
+ if (!changed) return false;
2062
+ atomicWriteJson(filePath, { ...raw, include });
2063
+ return true;
2064
+ }
2065
+ function resolveAppTsconfigPath(cwd, root) {
2066
+ const refs = root.references;
2067
+ if (!refs) return null;
2068
+ for (const ref of refs) {
2069
+ const p = ref.path?.replace(/^\.\//, "") ?? "";
2070
+ const base = p.replace(/\.json$/i, "");
2071
+ if (/app/i.test(base)) {
2072
+ return path7.join(cwd, p.endsWith(".json") ? p : `${p}.json`);
2073
+ }
2074
+ }
2075
+ for (const ref of refs) {
2076
+ const p = ref.path?.replace(/^\.\//, "") ?? "";
2077
+ if (!/node/i.test(p)) {
2078
+ return path7.join(cwd, p.endsWith(".json") ? p : `${p}.json`);
2079
+ }
2080
+ }
2081
+ return null;
2082
+ }
2083
+ function repairSolutionStyleRootTsconfig(cwd) {
2084
+ const rootPath = path7.join(cwd, "tsconfig.json");
2085
+ if (!fs6.existsSync(rootPath)) return false;
2086
+ const existing = fs6.readJsonSync(rootPath);
2087
+ if (!isSolutionStyleTsconfig(existing)) return false;
2088
+ const polluted = existing.compilerOptions !== void 0 || Array.isArray(existing.include) && existing.include.length > 0 || Array.isArray(existing.exclude) && existing.exclude.length > 0;
2089
+ if (!polluted) return false;
2090
+ atomicWriteJson(rootPath, {
2091
+ files: Array.isArray(existing.files) ? existing.files : [],
2092
+ references: existing.references
2093
+ });
2094
+ return true;
2095
+ }
2096
+ function patchSolutionStyleTsconfigForIui(cwd) {
2097
+ const rootPath = path7.join(cwd, "tsconfig.json");
2098
+ if (!fs6.existsSync(rootPath)) return false;
2099
+ const existing = fs6.readJsonSync(rootPath);
2100
+ if (!isSolutionStyleTsconfig(existing)) return false;
2101
+ const repairedRoot = repairSolutionStyleRootTsconfig(cwd);
2102
+ const appPath = resolveAppTsconfigPath(cwd, existing);
2103
+ const themeFile = fs6.existsSync(path7.join(cwd, "iui.config.ts")) && !fs6.existsSync(path7.join(cwd, "theme.config.ts")) ? "iui.config.ts" : "theme.config.ts";
2104
+ const patchedApp = appPath ? patchJsonInclude(appPath, [themeFile, "component.config.ts"]) : false;
2105
+ return repairedRoot || patchedApp;
2482
2106
  }
2483
2107
 
2484
2108
  // src/validation/configTierChecks.ts
@@ -2495,10 +2119,9 @@ var iuiThemeConfigSchema = z2.object({
2495
2119
  }).strict();
2496
2120
  var IuiThemeConfigSchema = iuiThemeConfigSchema.refine(
2497
2121
  (data) => !("assets" in data),
2498
- { message: "iui.config must not contain an assets key \u2014 use assets.config.json" }
2122
+ { message: "theme.config must not contain an assets key \u2014 use assets.config.json" }
2499
2123
  );
2500
2124
  var AssetsConfigSchema = z2.object({
2501
- binding: z2.enum(["lazy", "scanned"]).optional(),
2502
2125
  preload: z2.enum(["none", "configured", "scanned"]).optional(),
2503
2126
  icon: z2.object({
2504
2127
  library: z2.string().optional(),
@@ -2571,11 +2194,14 @@ function stripAssetsFromIuiConfig(content) {
2571
2194
  return next;
2572
2195
  }
2573
2196
  function checkIuiConfigTierBleed(cwd = process.cwd(), options = {}) {
2574
- const configPath = path8.join(cwd, PROJECT_CONFIG_FILE);
2197
+ const configPath = path8.join(
2198
+ cwd,
2199
+ fs7.existsSync(path8.join(cwd, PROJECT_CONFIG_FILE)) || !fs7.existsSync(path8.join(cwd, "iui.config.ts")) ? PROJECT_CONFIG_FILE : "iui.config.ts"
2200
+ );
2575
2201
  if (!fs7.existsSync(configPath)) {
2576
2202
  return {
2577
2203
  ok: false,
2578
- summary: "iui.config.ts not found",
2204
+ summary: "theme.config.ts not found",
2579
2205
  details: "Run iui init to scaffold project config."
2580
2206
  };
2581
2207
  }
@@ -2590,7 +2216,7 @@ function checkIuiConfigTierBleed(cwd = process.cwd(), options = {}) {
2590
2216
  }
2591
2217
  }
2592
2218
  if (issues.length === 0) {
2593
- return { ok: true, summary: "iui.config.ts tier boundaries are valid" };
2219
+ return { ok: true, summary: "theme.config.ts tier boundaries are valid" };
2594
2220
  }
2595
2221
  if (options.autoFix) {
2596
2222
  const fixed = stripAssetsFromIuiConfig(content);
@@ -2603,14 +2229,14 @@ function checkIuiConfigTierBleed(cwd = process.cwd(), options = {}) {
2603
2229
  if (remaining.length === 0 && /\bbuild\s*:\s*\{/.test(content)) {
2604
2230
  return {
2605
2231
  ok: true,
2606
- summary: "iui.config.ts repaired (removed assets tier bleed)"
2232
+ summary: "theme.config.ts repaired (removed assets tier bleed)"
2607
2233
  };
2608
2234
  }
2609
2235
  }
2610
2236
  }
2611
2237
  return {
2612
2238
  ok: false,
2613
- summary: "iui.config.ts violates three-config tier boundaries",
2239
+ summary: "theme.config.ts violates three-config tier boundaries",
2614
2240
  details: issues.map((i) => `- ${i}`).join("\n")
2615
2241
  };
2616
2242
  }
@@ -2877,15 +2503,6 @@ function loadAssetsConfigTemplate() {
2877
2503
  return {};
2878
2504
  }
2879
2505
  }
2880
- function loadComponentConfigPresetsTemplate() {
2881
- const templatePath = path10.join(getCliTemplatesDir(), "component.config.presets.json");
2882
- if (!fs8.existsSync(templatePath)) return {};
2883
- try {
2884
- return fs8.readJsonSync(templatePath);
2885
- } catch {
2886
- return {};
2887
- }
2888
- }
2889
2506
  function mergeAssetSlotWithTemplate(slot, templateSlot) {
2890
2507
  if (!templateSlot) return slot ?? {};
2891
2508
  const out = { ...templateSlot, ...slot ?? {} };
@@ -2913,12 +2530,6 @@ function mergeAssetSlotWithTemplate(slot, templateSlot) {
2913
2530
  function seedAssetsOutputFromTemplate(output) {
2914
2531
  const template = loadAssetsConfigTemplate();
2915
2532
  for (const [key, tplVal] of Object.entries(template)) {
2916
- if (key === "binding") {
2917
- if (output.binding === void 0 && tplVal !== void 0) {
2918
- output.binding = tplVal;
2919
- }
2920
- continue;
2921
- }
2922
2533
  if (typeof tplVal === "object" && tplVal !== null && !Array.isArray(tplVal)) {
2923
2534
  output[key] = mergeAssetSlotWithTemplate(
2924
2535
  output[key],
@@ -2926,13 +2537,6 @@ function seedAssetsOutputFromTemplate(output) {
2926
2537
  );
2927
2538
  }
2928
2539
  }
2929
- if (output.binding === "scanned") {
2930
- output.preload = output.preload ?? "scanned";
2931
- const icon = output.icon;
2932
- if (icon && typeof icon === "object" && !Array.isArray(icon)) {
2933
- icon.preload = icon.preload ?? "scanned";
2934
- }
2935
- }
2936
2540
  }
2937
2541
  function assetsConfigPath(cwd) {
2938
2542
  return path10.join(resolveIuiProjectRoot(cwd ?? process.cwd()), ASSETS_CONFIG_FILE);
@@ -3092,9 +2696,6 @@ function writeAssetsConfig(cwd = process.cwd()) {
3092
2696
  delete output[legacyKey];
3093
2697
  }
3094
2698
  }
3095
- if (output.binding === void 0 && Object.keys(assets2).length > 0 && projectHasViteTooling(cwd)) {
3096
- output.binding = "scanned";
3097
- }
3098
2699
  seedAssetsOutputFromTemplate(output);
3099
2700
  writeJson(assetsConfigPath(cwd), output);
3100
2701
  try {
@@ -3147,12 +2748,19 @@ function registryItemsMap(manifest) {
3147
2748
  }
3148
2749
  return map;
3149
2750
  }
2751
+ function resolveProjectConfigPath(root) {
2752
+ const current = path10.join(root, PROJECT_CONFIG_FILE);
2753
+ if (fs8.existsSync(current)) return current;
2754
+ const previous = path10.join(root, "iui.config.ts");
2755
+ if (fs8.existsSync(previous)) return previous;
2756
+ return current;
2757
+ }
3150
2758
  function writeProjectConfig(cwd = process.cwd()) {
3151
2759
  const configPath = path10.join(cwd, PROJECT_CONFIG_FILE);
3152
2760
  atomicWriteFile(configPath, buildProjectConfigSource(cwd));
3153
2761
  }
3154
2762
  function ensureProjectConfigBuildBlock(cwd = process.cwd()) {
3155
- const configPath = path10.join(resolveIuiProjectRoot(cwd), PROJECT_CONFIG_FILE);
2763
+ const configPath = resolveProjectConfigPath(resolveIuiProjectRoot(cwd));
3156
2764
  if (!fs8.existsSync(configPath)) return false;
3157
2765
  const before = fs8.readFileSync(configPath, "utf-8");
3158
2766
  const result = patchProjectConfigBuildBlock(before);
@@ -3162,7 +2770,7 @@ function ensureProjectConfigBuildBlock(cwd = process.cwd()) {
3162
2770
  }
3163
2771
  function ensureProjectConfig(cwd = process.cwd()) {
3164
2772
  const root = resolveIuiProjectRoot(cwd);
3165
- const configPath = path10.join(root, PROJECT_CONFIG_FILE);
2773
+ const configPath = resolveProjectConfigPath(root);
3166
2774
  if (!fs8.existsSync(configPath)) {
3167
2775
  writeProjectConfig(root);
3168
2776
  return "scaffolded";
@@ -3232,7 +2840,24 @@ function writeTsConfigNode(cwd = process.cwd()) {
3232
2840
  };
3233
2841
  atomicWriteJson(nodeTsPath, content);
3234
2842
  }
3235
- function writeTsConfig(framework, cwd = process.cwd()) {
2843
+ function ensureTsConfigForIui(framework, cwd = process.cwd()) {
2844
+ const tsconfigPath = path10.join(cwd, "tsconfig.json");
2845
+ let existing = {};
2846
+ if (fs8.existsSync(tsconfigPath)) {
2847
+ try {
2848
+ existing = fs8.readJsonSync(tsconfigPath);
2849
+ } catch {
2850
+ existing = {};
2851
+ }
2852
+ }
2853
+ if (framework === "vite" && isSolutionStyleTsconfig(existing)) {
2854
+ patchSolutionStyleTsconfigForIui(cwd);
2855
+ writeTsConfigNode(cwd);
2856
+ return;
2857
+ }
2858
+ writeFlatProjectTsConfig(framework, cwd);
2859
+ }
2860
+ function writeFlatProjectTsConfig(framework, cwd = process.cwd()) {
3236
2861
  const tsconfigPath = path10.join(cwd, "tsconfig.json");
3237
2862
  let existing = {};
3238
2863
  if (fs8.existsSync(tsconfigPath)) {
@@ -3275,7 +2900,8 @@ function writeTsConfig(framework, cwd = process.cwd()) {
3275
2900
  }
3276
2901
  const include = Array.isArray(existing.include) ? [...existing.include.map(String)] : [];
3277
2902
  if (!include.includes("src")) include.push("src");
3278
- const rootConfigFiles = ["iui.config.ts", "component.config.ts"];
2903
+ const themeConfigFile = fs8.existsSync(path10.join(cwd, "iui.config.ts")) && !fs8.existsSync(path10.join(cwd, PROJECT_CONFIG_FILE)) ? "iui.config.ts" : PROJECT_CONFIG_FILE;
2904
+ const rootConfigFiles = [themeConfigFile, "component.config.ts"];
3279
2905
  for (const rootFile of rootConfigFiles) {
3280
2906
  if (!include.includes(rootFile)) include.push(rootFile);
3281
2907
  }
@@ -3300,56 +2926,22 @@ function writeTsConfig(framework, cwd = process.cwd()) {
3300
2926
  };
3301
2927
  atomicWriteJson(tsconfigPath, output);
3302
2928
  }
3303
- function writeComponentConfig(manifest, cwd = process.cwd()) {
2929
+ function writeComponentConfig(_manifest, cwd = process.cwd()) {
3304
2930
  const configPath = path10.join(cwd, COMPONENT_CONFIG_FILE);
3305
- let entries = "";
3306
- const typedEntries = [];
3307
- const typeImports = [];
3308
- const presetsTemplate = loadComponentConfigPresetsTemplate();
3309
- if (manifest) {
3310
- for (const item of manifest.items) {
3311
- assertJsIdentifier(item.dirName, "component dirName");
3312
- const cfg = item.meta?.defaultConfig ?? {};
3313
- const presetBlock = presetsTemplate[item.dirName];
3314
- const cfgStr = JSON.stringify(cfg, null, 6).split("\n").map((line, i) => i === 0 ? line : ` ${line}`).join("\n");
3315
- let extraBlocks = "";
3316
- if (presetBlock?.presets) {
3317
- const presetsStr = JSON.stringify(presetBlock.presets, null, 6).split("\n").map((line, i) => i === 0 ? line : ` ${line}`).join("\n");
3318
- extraBlocks += `
3319
- presets: ${presetsStr},`;
3320
- }
3321
- entries += ` ${item.dirName}: {
3322
- default: ${cfgStr},${extraBlocks}
3323
- },
3324
-
3325
- `;
3326
- const resolved = resolveComponentExport(item, cwd);
3327
- if (resolved.ok && resolved.propsName && resolved.importSpecifier) {
3328
- typeImports.push(`import type { ${resolved.propsName} } from "${resolved.importSpecifier}";`);
3329
- typedEntries.push(` ${item.dirName}: { default: Partial<${resolved.propsName}> };`);
3330
- } else {
3331
- typedEntries.push(` ${item.dirName}: { default: Record<string, unknown> };`);
3332
- }
3333
- }
3334
- }
3335
- const imports = [...new Set(typeImports)].join("\n");
3336
- const componentConfigType = typedEntries.length > 0 ? `type ComponentConfigMap = {
3337
- ${typedEntries.join("\n")}
3338
- };` : `type ComponentConfigMap = Record<string, { default: Record<string, unknown> }>;`;
3339
2931
  const content = `// \u2500\u2500\u2500 Component Configuration \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
3340
2932
  //
3341
- // Default component presets for your Inventive UI project.
3342
- // Customize variants, appearances, and slot assignments below.
3343
- // Entries are rebuilt from the published component registry.
2933
+ // Optional per-component defaults (variant, appearance, presets, cTags).
2934
+ // Only add entries you want to override \u2014 omit components you do not customize.
2935
+ // \`iui update\` may append new registry keys; edit or remove them as needed.
3344
2936
  //
3345
2937
  // Docs: https://inventiveui.com/docs/configuration
3346
2938
 
3347
- ${imports}
3348
-
3349
- ${componentConfigType}
2939
+ import type { ComponentConfig } from "@inventive-ui/components/config";
3350
2940
 
3351
- export const componentConfig: ComponentConfigMap = {
3352
- ${entries}};
2941
+ export const componentConfig = {
2942
+ // Example:
2943
+ // Button: { default: { variant: "solid", appearance: "soft" } },
2944
+ } satisfies ComponentConfig;
3353
2945
  `;
3354
2946
  atomicWriteFile(configPath, content);
3355
2947
  }
@@ -3361,7 +2953,7 @@ function ensureComponentConfig(manifest, cwd = process.cwd(), options = {}) {
3361
2953
  return existed && options.force ? "replaced" : "scaffolded";
3362
2954
  }
3363
2955
  const before = fs8.readFileSync(configPath, "utf-8");
3364
- const result = mergeComponentConfigContent(before, manifest, cwd);
2956
+ const result = mergeComponentConfigContent(before, manifest);
3365
2957
  if (!result.changed) return "noop";
3366
2958
  atomicWriteFile(configPath, result.content);
3367
2959
  return "merged";
@@ -3773,13 +3365,13 @@ function ensureInventiveUiViteConfig(cwd = process.cwd()) {
3773
3365
  }
3774
3366
 
3775
3367
  // src/services/auth.ts
3776
- async function api(path28, opts) {
3777
- const res = await fetch(`${API_BASE_URL}${path28}`, {
3368
+ async function api(path27, opts) {
3369
+ const res = await fetch(`${API_BASE_URL}${path27}`, {
3778
3370
  ...opts,
3779
3371
  signal: opts?.signal ?? AbortSignal.timeout(API_REQUEST_TIMEOUT_MS),
3780
3372
  headers: { "Content-Type": "application/json", ...opts?.headers }
3781
3373
  });
3782
- throwIfRateLimited(res, `calling ${path28}`);
3374
+ throwIfRateLimited(res, `calling ${path27}`);
3783
3375
  if (!res.ok) {
3784
3376
  const body = await res.text().catch(() => "");
3785
3377
  throw new CLIError(`API error ${res.status}: ${body || res.statusText}`);
@@ -4031,10 +3623,12 @@ async function promptAssetSelection(installedPackages = []) {
4031
3623
  const choices = [];
4032
3624
  for (const cat of categories) {
4033
3625
  const inCategory = catalogue.filter((p) => p.category === cat);
3626
+ if (choices.length > 0) {
3627
+ choices.push(new inquirer.Separator(" "));
3628
+ }
4034
3629
  choices.push(
4035
3630
  new inquirer.Separator(
4036
- `
4037
- ${brand.bold(ASSET_CATEGORY_LABELS[cat])} ${dim(`(${inCategory.length})`)}`
3631
+ ` ${brand.bold(ASSET_CATEGORY_LABELS[cat])} ${dim(`(${inCategory.length})`)}`
4038
3632
  )
4039
3633
  );
4040
3634
  for (const pkg of inCategory) {
@@ -4046,6 +3640,8 @@ async function promptAssetSelection(installedPackages = []) {
4046
3640
  }
4047
3641
  }
4048
3642
  console.log();
3643
+ const terminalRows = process.stdout.rows ?? 0;
3644
+ const pageSize = terminalRows > 0 ? Math.max(10, Math.min(choices.length, terminalRows - 4)) : choices.length;
4049
3645
  const { selected } = await inquirer.prompt([
4050
3646
  {
4051
3647
  type: "checkbox",
@@ -4053,7 +3649,7 @@ async function promptAssetSelection(installedPackages = []) {
4053
3649
  message: chalk2.dim("Toggle packages to install"),
4054
3650
  prefix: PROMPT_PREFIX,
4055
3651
  choices,
4056
- pageSize: 20,
3652
+ pageSize,
4057
3653
  loop: false
4058
3654
  }
4059
3655
  ]);
@@ -4135,7 +3731,7 @@ async function promptChooseEmojiFamily(fallbackCurrent) {
4135
3731
  assertInteractivePrompt("emoji family choice");
4136
3732
  inputBox(
4137
3733
  "Emoji Family",
4138
- "Choose the default CDN style for emoji slots. Skin tone defaults to medium-light."
3734
+ "Choose the default CDN style for emoji slots. Skin tone defaults to medium-light (`mediumLight`)."
4139
3735
  );
4140
3736
  const { chosen } = await inquirer.prompt([
4141
3737
  {
@@ -4227,7 +3823,7 @@ async function promptText(title, hint2, placeholder, validate) {
4227
3823
  }
4228
3824
 
4229
3825
  // src/commands/init.ts
4230
- import path23 from "path";
3826
+ import path22 from "path";
4231
3827
  import ora3 from "ora";
4232
3828
 
4233
3829
  // src/services/license.ts
@@ -5194,8 +4790,8 @@ function getMajorFromVersion(version) {
5194
4790
  import ora2 from "ora";
5195
4791
 
5196
4792
  // src/services/slot-registry.ts
5197
- import fs18 from "fs-extra";
5198
- import path22 from "path";
4793
+ import fs17 from "fs-extra";
4794
+ import path21 from "path";
5199
4795
 
5200
4796
  // src/services/registry-lock.ts
5201
4797
  import fs11 from "fs";
@@ -5282,8 +4878,8 @@ async function withRegistryLock(cwd, operation) {
5282
4878
  }
5283
4879
 
5284
4880
  // src/services/slots.ts
5285
- import fs15 from "fs-extra";
5286
- import path19 from "path";
4881
+ import fs14 from "fs-extra";
4882
+ import path18 from "path";
5287
4883
 
5288
4884
  // src/utils/public-slot-contract.ts
5289
4885
  import path15 from "path";
@@ -5413,11 +5009,6 @@ function safeWriteFile(filePath, content) {
5413
5009
  atomicWriteFile(filePath, content);
5414
5010
  }
5415
5011
 
5416
- // src/services/asset-bound.ts
5417
- import fs14 from "fs-extra";
5418
- import path18 from "path";
5419
- import { pathToFileURL } from "url";
5420
-
5421
5012
  // src/services/generated-paths.ts
5422
5013
  import path17 from "path";
5423
5014
  function iuiProjectRoot2(cwd) {
@@ -5429,367 +5020,26 @@ function generatedIuiDir(cwd) {
5429
5020
  function generatedSlotsDir(cwd) {
5430
5021
  return path17.join(generatedIuiDir(cwd), "slots");
5431
5022
  }
5432
- function generatedAssetsDir(cwd) {
5433
- return path17.join(generatedIuiDir(cwd), "assets");
5434
- }
5435
-
5436
- // src/services/asset-bound.ts
5437
- var LIBRARY_TO_PKG = {
5438
- lucide: "icons-lucide",
5439
- phosphor: "icons-phosphor",
5440
- material: "icons-material",
5441
- "material-icons": "icons-material",
5442
- materialSymbols: "material-symbols",
5443
- "material-symbols": "material-symbols"
5444
- };
5445
- var PKG_LOOKUP_PREFIX = {
5446
- "icons-lucide": "icons/",
5447
- "icons-phosphor": "icons/",
5448
- "icons-material": "icons/",
5449
- "material-symbols": "icons/",
5450
- logos: "logos/",
5451
- "color-logos": "logos/",
5452
- flags: "flags/",
5453
- "file-types": "types/",
5454
- loaders: "loaders/",
5455
- illustrations: ""
5456
- };
5457
- var BOUND_SPECS = [
5458
- {
5459
- slotType: "icon",
5460
- fileName: "icons.bound.ts",
5461
- exportName: "BOUND_ICONS",
5462
- packages: /* @__PURE__ */ new Set([
5463
- "material-symbols",
5464
- "icons-lucide",
5465
- "icons-phosphor",
5466
- "icons-material"
5467
- ]),
5468
- filterByDefaultIconLibrary: true
5469
- },
5470
- {
5471
- slotType: "logo",
5472
- fileName: "logos.bound.ts",
5473
- exportName: "BOUND_LOGOS",
5474
- packages: /* @__PURE__ */ new Set(["logos"])
5475
- },
5476
- {
5477
- slotType: "color-logo",
5478
- fileName: "color-logos.bound.ts",
5479
- exportName: "BOUND_COLOR_LOGOS",
5480
- packages: /* @__PURE__ */ new Set(["color-logos"])
5481
- },
5482
- {
5483
- slotType: "flag",
5484
- fileName: "flags.bound.ts",
5485
- exportName: "BOUND_FLAGS",
5486
- packages: /* @__PURE__ */ new Set(["flags"])
5487
- },
5488
- {
5489
- slotType: "file-type",
5490
- fileName: "file-types.bound.ts",
5491
- exportName: "BOUND_FILE_TYPES",
5492
- packages: /* @__PURE__ */ new Set(["file-types"])
5493
- },
5494
- {
5495
- slotType: "loader",
5496
- fileName: "loaders.bound.ts",
5497
- exportName: "BOUND_LOADERS",
5498
- packages: /* @__PURE__ */ new Set(["loaders"])
5499
- },
5500
- {
5501
- slotType: "illustration",
5502
- fileName: "illustrations.bound.ts",
5503
- exportName: "BOUND_ILLUSTRATIONS",
5504
- packages: /* @__PURE__ */ new Set(["illustrations"])
5505
- }
5506
- ];
5507
- function isAssetPackageInstalled(cwd, pkgId) {
5508
- return resolvePackageDir(`@inventive-ui/${pkgId}`, cwd) !== null;
5509
- }
5510
- var DEFAULT_SCAN = {
5511
- scanDirs: ["src", ".storybook", "stories", ".iui"],
5512
- include: [
5513
- "**/*.stories.*",
5514
- "**/*.mdx",
5515
- "**/src/**/*.tsx",
5516
- "**/src/**/*.ts",
5517
- "**/src/**/*.jsx",
5518
- "**/src/**/*.js",
5519
- "**/.storybook/**/*.tsx",
5520
- "**/.storybook/**/*.ts",
5521
- "**/.storybook/**/*.jsx",
5522
- "**/.storybook/**/*.js"
5523
- ],
5524
- exclude: ["**/*.test.*", "**/*.spec.*"]
5525
- };
5526
- function resolveFrameworkModule(cwd, relativePath) {
5527
- const searchRoots = /* @__PURE__ */ new Set();
5528
- for (const candidate of [
5529
- resolveDependencyInstallRoot(cwd),
5530
- path18.resolve(cwd),
5531
- iuiProjectRoot2(cwd)
5532
- ]) {
5533
- searchRoots.add(path18.resolve(candidate));
5534
- }
5535
- for (const start of searchRoots) {
5536
- const frameworkDir = resolvePackageDir("@inventive-ui/framework", start);
5537
- if (!frameworkDir) continue;
5538
- const installed = path18.join(frameworkDir, relativePath);
5539
- if (fs14.existsSync(installed)) return installed;
5540
- }
5541
- const root = iuiProjectRoot2(cwd);
5542
- for (const candidate of [
5543
- path18.join(root, "..", "Framework", relativePath),
5544
- path18.join(root, "..", "..", "Framework", relativePath)
5545
- ]) {
5546
- if (fs14.existsSync(candidate)) return candidate;
5547
- }
5548
- return null;
5549
- }
5550
- async function loadScanUtils(cwd) {
5551
- const scanPath = resolveFrameworkModule(
5552
- cwd,
5553
- "integrations/vite/scan-used-slot-assets.mjs"
5554
- );
5555
- const resolvePath = resolveFrameworkModule(
5556
- cwd,
5557
- "integrations/shared/resolve-scanned-icon-name.mjs"
5558
- );
5559
- if (!scanPath || !resolvePath) {
5560
- const installRoot = resolveDependencyInstallRoot(cwd);
5561
- const frameworkDir = resolvePackageDir("@inventive-ui/framework", installRoot);
5562
- const hint2 = frameworkDir && !scanPath ? "Update @inventive-ui/framework to the latest version (iui update) \u2014 scan utilities require a current Framework release." : "Install @inventive-ui/framework and run iui doctor again.";
5563
- throw new CLIError("Could not load Framework scan utilities.", hint2);
5564
- }
5565
- const scanMod = await import(pathToFileURL(scanPath).href);
5566
- const resolveMod = await import(pathToFileURL(resolvePath).href);
5567
- return { ...scanMod, ...resolveMod };
5568
- }
5569
- function lookupKeyToGlyphKey(pkg, lookupKey) {
5570
- let subpath = lookupKey.replace(/^\.\//, "").replace(/\.js$/, "");
5571
- if (pkg === "illustrations") {
5572
- return subpath;
5573
- }
5574
- const prefix = PKG_LOOKUP_PREFIX[pkg];
5575
- if (prefix && subpath.startsWith(prefix)) {
5576
- subpath = subpath.slice(prefix.length);
5577
- }
5578
- return subpath;
5579
- }
5580
- function glyphToIdentifier(name, used) {
5581
- let base = name.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
5582
- if (!base || !/^[A-Za-z_$]/.test(base)) {
5583
- base = `Glyph${base}`;
5584
- }
5585
- let id = base;
5586
- let suffix = 2;
5587
- while (used.has(id)) {
5588
- id = `${base}${suffix++}`;
5589
- }
5590
- used.add(id);
5591
- return id;
5592
- }
5593
- function resolveIconPkg(library) {
5594
- return LIBRARY_TO_PKG[library] ?? library;
5595
- }
5596
- function buildBoundFileContent(exportName, entries) {
5597
- const lines = [
5598
- "// Managed by iui. Do not edit manually.",
5599
- '// Static glyph bindings for scanned assets (`binding: "scanned"`).',
5600
- "",
5601
- 'import type { ComponentType } from "react";'
5602
- ];
5603
- for (const entry of entries) {
5604
- lines.push(`import ${entry.identifier} from "${entry.moduleId}";`);
5605
- }
5606
- lines.push("");
5607
- lines.push(
5608
- `export const ${exportName}: Record<string, ComponentType<Record<string, unknown>>> = {`
5609
- );
5610
- for (const entry of entries) {
5611
- lines.push(` ${JSON.stringify(entry.key)}: ${entry.identifier},`);
5612
- }
5613
- lines.push("};");
5614
- lines.push("");
5615
- return lines.join("\n");
5616
- }
5617
- function cleanupAssetBoundFiles(cwd) {
5618
- const assetsDir = generatedAssetsDir(cwd);
5619
- if (!fs14.existsSync(assetsDir)) return;
5620
- for (const file of fs14.readdirSync(assetsDir)) {
5621
- if (file.endsWith(".bound.ts") || file === "register-bound.ts") {
5622
- fs14.removeSync(path18.join(assetsDir, file));
5623
- }
5624
- }
5625
- const remaining = fs14.readdirSync(assetsDir);
5626
- if (remaining.length === 0) {
5627
- fs14.removeSync(assetsDir);
5628
- }
5629
- }
5630
- function hasAssetBoundRegistration(cwd) {
5631
- return fs14.existsSync(path18.join(generatedAssetsDir(cwd), "register-bound.ts"));
5632
- }
5633
- async function writeAssetBoundFiles(cwd = process.cwd()) {
5634
- const root = iuiProjectRoot2(cwd);
5635
- const scanUtils = await loadScanUtils(cwd);
5636
- const activeSpecs = BOUND_SPECS.filter(
5637
- (spec) => scanUtils.isScannedAssetBindingEnabled(root, spec.slotType)
5638
- );
5639
- if (activeSpecs.length === 0) {
5640
- cleanupAssetBoundFiles(root);
5641
- return;
5642
- }
5643
- const registry = scanUtils.scanUsedSlotAssets(root, DEFAULT_SCAN);
5644
- const defaultIconLibrary = scanUtils.readDefaultIconLibraryFromConfig(root);
5645
- const defaultIconPkg = resolveIconPkg(defaultIconLibrary);
5646
- const assetsDir = generatedAssetsDir(root);
5647
- fs14.ensureDirSync(assetsDir);
5648
- const generatedFiles = /* @__PURE__ */ new Set();
5649
- const registrationSpecs = [];
5650
- for (const spec of activeSpecs) {
5651
- const entries = [];
5652
- const usedIdentifiers = /* @__PURE__ */ new Set();
5653
- for (const [pkg, keys] of registry.entries()) {
5654
- if (!spec.packages.has(pkg)) continue;
5655
- if ("filterByDefaultIconLibrary" in spec && spec.filterByDefaultIconLibrary && pkg !== defaultIconPkg) {
5656
- continue;
5657
- }
5658
- if (!isAssetPackageInstalled(cwd, pkg)) continue;
5659
- for (const lookupKey of keys) {
5660
- const key = lookupKeyToGlyphKey(pkg, lookupKey);
5661
- const moduleId = scanUtils.lookupKeyToModuleId(pkg, lookupKey);
5662
- const identifier = glyphToIdentifier(key, usedIdentifiers);
5663
- if (entries.some((entry) => entry.key === key)) continue;
5664
- entries.push({ key, moduleId, identifier });
5665
- }
5666
- }
5667
- entries.sort((a, b) => a.key.localeCompare(b.key));
5668
- if (entries.length === 0) {
5669
- continue;
5670
- }
5671
- const content = buildBoundFileContent(spec.exportName, entries);
5672
- const outPath = resolveWithinRoot(
5673
- root,
5674
- ".iui",
5675
- "generated",
5676
- "assets",
5677
- spec.fileName
5678
- );
5679
- safeWriteFile(outPath, content);
5680
- generatedFiles.add(spec.fileName);
5681
- registrationSpecs.push({
5682
- slotType: spec.slotType,
5683
- exportName: spec.exportName,
5684
- fileName: spec.fileName
5685
- });
5686
- }
5687
- const existing = fs14.existsSync(assetsDir) ? fs14.readdirSync(assetsDir).filter((f) => f.endsWith(".bound.ts")) : [];
5688
- for (const file of existing) {
5689
- if (!generatedFiles.has(file)) {
5690
- fs14.removeSync(path18.join(assetsDir, file));
5691
- }
5692
- }
5693
- if (registrationSpecs.length === 0) {
5694
- cleanupAssetBoundFiles(root);
5695
- return;
5696
- }
5697
- const registerLines = [
5698
- "// Managed by iui. Do not edit manually.",
5699
- "",
5700
- 'import { registerBoundAssetComponents } from "@inventive-ui/framework/slots";'
5701
- ];
5702
- for (const spec of registrationSpecs) {
5703
- registerLines.push(
5704
- `import { ${spec.exportName} } from "./${spec.fileName.replace(/\.ts$/, "")}";`
5705
- );
5706
- }
5707
- registerLines.push("");
5708
- for (const spec of registrationSpecs) {
5709
- registerLines.push(
5710
- `registerBoundAssetComponents(${JSON.stringify(spec.slotType)}, ${spec.exportName});`
5711
- );
5712
- }
5713
- registerLines.push("");
5714
- safeWriteFile(
5715
- resolveWithinRoot(root, ".iui", "generated", "assets", "register-bound.ts"),
5716
- registerLines.join("\n")
5717
- );
5718
- }
5719
- function assetModuleCandidates(pkgRoot, moduleId) {
5720
- const pkgName = moduleId.split("/").slice(0, 2).join("/");
5721
- const subpath = moduleId.slice(pkgName.length + 1);
5722
- const pkgId = pkgName.replace("@inventive-ui/", "");
5723
- if (!subpath || subpath.includes("..")) return [];
5724
- if (pkgId === "loaders") {
5725
- return [path18.join(pkgRoot, "dist", "loaders", `${subpath}.js`)];
5726
- }
5727
- if (pkgId === "illustrations") {
5728
- const [family, scene] = subpath.split("/");
5729
- if (family && scene) {
5730
- return [path18.join(pkgRoot, "dist", family, `${scene}.js`)];
5731
- }
5732
- return [path18.join(pkgRoot, "dist", `${subpath}.js`)];
5733
- }
5734
- const prefix = PKG_LOOKUP_PREFIX[pkgId];
5735
- if (prefix) {
5736
- const dir = prefix.replace(/\/$/, "");
5737
- return [
5738
- path18.join(pkgRoot, "dist", dir, `${subpath}.js`),
5739
- path18.join(pkgRoot, "dist", `${subpath}.js`),
5740
- path18.join(pkgRoot, "dist", subpath, "index.js")
5741
- ];
5742
- }
5743
- return [
5744
- path18.join(pkgRoot, "dist", `${subpath}.js`),
5745
- path18.join(pkgRoot, "dist", subpath, "index.js")
5746
- ];
5747
- }
5748
- function validateGeneratedAssetBoundImports(cwd = process.cwd()) {
5749
- const assetsDir = generatedAssetsDir(cwd);
5750
- if (!fs14.existsSync(assetsDir)) return [];
5751
- const issues = [];
5752
- const boundFiles = fs14.readdirSync(assetsDir).filter((file) => file.endsWith(".bound.ts"));
5753
- for (const file of boundFiles) {
5754
- const content = fs14.readFileSync(path18.join(assetsDir, file), "utf8");
5755
- const importRe = /from\s+["'](@inventive-ui\/[^"']+)["']/g;
5756
- let match;
5757
- while ((match = importRe.exec(content)) !== null) {
5758
- const moduleId = match[1];
5759
- const pkgName = moduleId.split("/").slice(0, 2).join("/");
5760
- const pkgRoot = resolvePackageDir(pkgName, cwd);
5761
- if (!pkgRoot) {
5762
- issues.push(`${file}: missing asset package ${pkgName}`);
5763
- continue;
5764
- }
5765
- const candidates = assetModuleCandidates(pkgRoot, moduleId);
5766
- if (!candidates.some((candidate) => fs14.existsSync(candidate))) {
5767
- issues.push(`${file}: missing asset module ${moduleId}`);
5768
- }
5769
- }
5770
- }
5771
- return issues;
5772
- }
5773
5023
 
5774
5024
  // src/services/slots.ts
5775
5025
  var SLOT_GROUP_CORE_FILE = "slot-core.generated.tsx";
5776
5026
  var SLOT_GROUP_OPTIONAL_FILE = "slot-optional.generated.tsx";
5777
5027
  function bridgeSlotFilePath(cwd) {
5778
- return path19.join(cwd, "src", "iui", "slot.tsx");
5028
+ return path18.join(cwd, "src", "iui", "slot.tsx");
5779
5029
  }
5780
5030
  function cleanupLegacySourceSlotFiles(cwd) {
5781
- const legacySlotsDir = path19.join(cwd, "src", "iui", "slots");
5782
- if (!fs15.existsSync(legacySlotsDir)) return;
5031
+ const legacySlotsDir = path18.join(cwd, "src", "iui", "slots");
5032
+ if (!fs14.existsSync(legacySlotsDir)) return;
5783
5033
  try {
5784
- const files = fs15.readdirSync(legacySlotsDir);
5034
+ const files = fs14.readdirSync(legacySlotsDir);
5785
5035
  for (const file of files) {
5786
5036
  if (file.endsWith(".slot.tsx")) {
5787
- fs15.removeSync(path19.join(legacySlotsDir, file));
5037
+ fs14.removeSync(path18.join(legacySlotsDir, file));
5788
5038
  }
5789
5039
  }
5790
- const remaining = fs15.readdirSync(legacySlotsDir);
5040
+ const remaining = fs14.readdirSync(legacySlotsDir);
5791
5041
  if (remaining.length === 0) {
5792
- fs15.removeSync(legacySlotsDir);
5042
+ fs14.removeSync(legacySlotsDir);
5793
5043
  }
5794
5044
  } catch {
5795
5045
  }
@@ -5853,18 +5103,18 @@ function writeComponentSlotFiles(cwd = process.cwd()) {
5853
5103
  const generationIssues = [];
5854
5104
  cleanupLegacySourceSlotFiles(cwd);
5855
5105
  if (Object.keys(components).length === 0) {
5856
- if (fs15.existsSync(slotsDir)) {
5857
- const existingSlots2 = fs15.readdirSync(slotsDir).filter((f) => f.endsWith(".slot.tsx"));
5106
+ if (fs14.existsSync(slotsDir)) {
5107
+ const existingSlots2 = fs14.readdirSync(slotsDir).filter((f) => f.endsWith(".slot.tsx"));
5858
5108
  for (const file of existingSlots2) {
5859
5109
  try {
5860
- fs15.removeSync(path19.join(slotsDir, file));
5110
+ fs14.removeSync(path18.join(slotsDir, file));
5861
5111
  } catch {
5862
5112
  }
5863
5113
  }
5864
5114
  }
5865
5115
  return;
5866
5116
  }
5867
- fs15.ensureDirSync(slotsDir);
5117
+ fs14.ensureDirSync(slotsDir);
5868
5118
  if (!pkgManifest) return;
5869
5119
  const itemsLookup = registryItemsMap(pkgManifest);
5870
5120
  const installedItems = Object.entries(components).map(([slug]) => itemsLookup[slug]).filter((item) => Boolean(item));
@@ -5905,7 +5155,7 @@ function writeComponentSlotFiles(cwd = process.cwd()) {
5905
5155
  for (const group of renderedGroups) {
5906
5156
  const outPath = resolveWithinRoot(root, ".iui", "generated", "slots", group.fileName);
5907
5157
  if (group.emitters.length === 0) {
5908
- if (fs15.existsSync(outPath)) fs15.removeSync(outPath);
5158
+ if (fs14.existsSync(outPath)) fs14.removeSync(outPath);
5909
5159
  continue;
5910
5160
  }
5911
5161
  safeWriteFile(
@@ -5915,19 +5165,19 @@ function writeComponentSlotFiles(cwd = process.cwd()) {
5915
5165
  })
5916
5166
  );
5917
5167
  }
5918
- const existingSlots = fs15.existsSync(slotsDir) ? fs15.readdirSync(slotsDir).filter((f) => f.endsWith(".slot.tsx") || f.endsWith(".generated.tsx")) : [];
5168
+ const existingSlots = fs14.existsSync(slotsDir) ? fs14.readdirSync(slotsDir).filter((f) => f.endsWith(".slot.tsx") || f.endsWith(".generated.tsx")) : [];
5919
5169
  for (const file of existingSlots) {
5920
5170
  if (file === SLOT_GROUP_CORE_FILE || file === SLOT_GROUP_OPTIONAL_FILE) continue;
5921
5171
  if (file.endsWith(".slot.tsx")) {
5922
5172
  try {
5923
- fs15.removeSync(path19.join(slotsDir, file));
5173
+ fs14.removeSync(path18.join(slotsDir, file));
5924
5174
  } catch {
5925
5175
  }
5926
5176
  continue;
5927
5177
  }
5928
5178
  if (file.endsWith(".generated.tsx")) {
5929
5179
  try {
5930
- fs15.removeSync(path19.join(slotsDir, file));
5180
+ fs14.removeSync(path18.join(slotsDir, file));
5931
5181
  } catch {
5932
5182
  }
5933
5183
  }
@@ -6031,24 +5281,18 @@ function writeSlotHelperFile(cwd = process.cwd()) {
6031
5281
  }
6032
5282
  const typesArray = Array.from(slotTypes).sort();
6033
5283
  const slotImports = [];
6034
- const coreSlotsPath = path19.join(generatedSlotsDir(cwd), SLOT_GROUP_CORE_FILE);
6035
- const optionalSlotsPath = path19.join(generatedSlotsDir(cwd), SLOT_GROUP_OPTIONAL_FILE);
6036
- if (fs15.existsSync(coreSlotsPath)) slotImports.push(`import "./slots/${SLOT_GROUP_CORE_FILE.replace(/\.tsx$/, "")}";`);
6037
- if (fs15.existsSync(optionalSlotsPath)) slotImports.push(`import "./slots/${SLOT_GROUP_OPTIONAL_FILE.replace(/\.tsx$/, "")}";`);
5284
+ const coreSlotsPath = path18.join(generatedSlotsDir(cwd), SLOT_GROUP_CORE_FILE);
5285
+ const optionalSlotsPath = path18.join(generatedSlotsDir(cwd), SLOT_GROUP_OPTIONAL_FILE);
5286
+ if (fs14.existsSync(coreSlotsPath)) slotImports.push(`import "./slots/${SLOT_GROUP_CORE_FILE.replace(/\.tsx$/, "")}";`);
5287
+ if (fs14.existsSync(optionalSlotsPath)) slotImports.push(`import "./slots/${SLOT_GROUP_OPTIONAL_FILE.replace(/\.tsx$/, "")}";`);
6038
5288
  const componentSlotImports = slotImports.join("\n");
6039
- const includeAssetBindings = hasAssetBoundRegistration(cwd);
6040
5289
  const outDir = generatedIuiDir(cwd);
6041
- fs15.ensureDirSync(outDir);
6042
- const outPath = path19.join(outDir, "slot.generated.tsx");
5290
+ fs14.ensureDirSync(outDir);
5291
+ const outPath = path18.join(outDir, "slot.generated.tsx");
6043
5292
  const sections = [
6044
5293
  `// Managed by iui. Do not edit manually.`,
6045
5294
  `// Rebuilt automatically when the CLI validates the project.`
6046
5295
  ];
6047
- if (includeAssetBindings) {
6048
- sections.push("");
6049
- sections.push("// Scanned asset bindings (static glyph imports)");
6050
- sections.push(`import "./assets/register-bound";`);
6051
- }
6052
5296
  if (componentSlotImports) {
6053
5297
  sections.push("");
6054
5298
  sections.push("// Component slot registrations");
@@ -6074,11 +5318,11 @@ ${typesArray.map((t) => ` | "${t}"`).join("\n")};` : `export type IUISlotType =
6074
5318
  }
6075
5319
  function writeSlotBridge(packageDir, iuiRoot2) {
6076
5320
  const bridgePath = bridgeSlotFilePath(packageDir);
6077
- const generatedFile = path19.join(iuiRoot2, ".iui", "generated", "slot.generated.tsx");
6078
- const importBase = relativeImportPath(path19.dirname(bridgePath), generatedFile);
6079
- fs15.ensureDirSync(path19.dirname(bridgePath));
6080
- if (fs15.existsSync(bridgePath)) {
6081
- const existing = fs15.readFileSync(bridgePath, "utf-8");
5321
+ const generatedFile = path18.join(iuiRoot2, ".iui", "generated", "slot.generated.tsx");
5322
+ const importBase = relativeImportPath(path18.dirname(bridgePath), generatedFile);
5323
+ fs14.ensureDirSync(path18.dirname(bridgePath));
5324
+ if (fs14.existsSync(bridgePath)) {
5325
+ const existing = fs14.readFileSync(bridgePath, "utf-8");
6082
5326
  if (existing.length > 0 && !/@iui-managed/.test(existing)) {
6083
5327
  return;
6084
5328
  }
@@ -6095,18 +5339,18 @@ export type { IUISlotType } from "${importBase}";
6095
5339
  }
6096
5340
 
6097
5341
  // src/services/workspace-bootstrap.ts
6098
- import path21 from "path";
6099
- import fs17 from "fs-extra";
5342
+ import path20 from "path";
5343
+ import fs16 from "fs-extra";
6100
5344
 
6101
5345
  // src/services/bootstrap.ts
6102
- import fs16 from "fs-extra";
6103
- import path20 from "path";
5346
+ import fs15 from "fs-extra";
5347
+ import path19 from "path";
6104
5348
  var BOOTSTRAP_GENERATED_FILE = "bootstrap.generated.tsx";
6105
5349
  function bridgeBootstrapFilePath(cwd) {
6106
- return path20.join(cwd, "src", "iui", "bootstrap.ts");
5350
+ return path19.join(cwd, "src", "iui", "bootstrap.ts");
6107
5351
  }
6108
5352
  function bootstrapGeneratedPath(cwd = process.cwd()) {
6109
- return path20.join(generatedIuiDir(cwd), BOOTSTRAP_GENERATED_FILE);
5353
+ return path19.join(generatedIuiDir(cwd), BOOTSTRAP_GENERATED_FILE);
6110
5354
  }
6111
5355
  function resolveProjectConfigPaths(cwd) {
6112
5356
  const meta = readProjectMeta(cwd);
@@ -6121,8 +5365,8 @@ function resolveProjectConfigPaths(cwd) {
6121
5365
  };
6122
5366
  }
6123
5367
  function configImportFromGenerated(cwd, configRel) {
6124
- const generatedDir = path20.dirname(bootstrapGeneratedPath(cwd));
6125
- const abs = path20.resolve(cwd, configRel.replace(/^\.\//, ""));
5368
+ const generatedDir = path19.dirname(bootstrapGeneratedPath(cwd));
5369
+ const abs = path19.resolve(cwd, configRel.replace(/^\.\//, ""));
6126
5370
  return relativeImportPath(generatedDir, abs);
6127
5371
  }
6128
5372
  function expectedBootstrapImportPaths(cwd) {
@@ -6135,13 +5379,13 @@ function expectedBootstrapImportPaths(cwd) {
6135
5379
  }
6136
5380
  function writeBootstrapGenerated(cwd = process.cwd()) {
6137
5381
  const outPath = bootstrapGeneratedPath(cwd);
6138
- fs16.ensureDirSync(path20.dirname(outPath));
5382
+ fs15.ensureDirSync(path19.dirname(outPath));
6139
5383
  const imports = expectedBootstrapImportPaths(cwd);
6140
5384
  const content = `// @iui-managed
6141
5385
 
6142
5386
  // Generated by iui CLI \u2014 do not edit manually.
6143
5387
 
6144
- // Connects iui.config.ts + assets.config.json + component.config.ts for standard bootstrap.
5388
+ // Connects theme.config.ts + assets.config.json + component.config.ts for standard bootstrap.
6145
5389
 
6146
5390
 
6147
5391
 
@@ -6161,7 +5405,7 @@ import {
6161
5405
 
6162
5406
  } from "@inventive-ui/framework";
6163
5407
 
6164
- import { initConfig as initSlotsConfig } from "@inventive-ui/framework/slots";
5408
+ import { initConfig as initAssetsConfig } from "@inventive-ui/framework/assets";
6165
5409
 
6166
5410
  import type { IUIAssetsConfig } from "@inventive-ui/framework/config";
6167
5411
 
@@ -6197,7 +5441,7 @@ registerBootstrapState({
6197
5441
 
6198
5442
  initFramework(frameworkConfig);
6199
5443
 
6200
- initSlotsConfig(frameworkConfig);
5444
+ initAssetsConfig(frameworkConfig);
6201
5445
 
6202
5446
 
6203
5447
 
@@ -6209,10 +5453,10 @@ export { projectComponentConfig as componentConfig };
6209
5453
  function writeBootstrapBridge(packageDir, iuiRoot2) {
6210
5454
  const bridgePath = bridgeBootstrapFilePath(packageDir);
6211
5455
  const generatedFile = bootstrapGeneratedPath(iuiRoot2);
6212
- const importBase = relativeImportPath(path20.dirname(bridgePath), generatedFile);
6213
- fs16.ensureDirSync(path20.dirname(bridgePath));
6214
- if (fs16.existsSync(bridgePath)) {
6215
- const existing = fs16.readFileSync(bridgePath, "utf-8");
5456
+ const importBase = relativeImportPath(path19.dirname(bridgePath), generatedFile);
5457
+ fs15.ensureDirSync(path19.dirname(bridgePath));
5458
+ if (fs15.existsSync(bridgePath)) {
5459
+ const existing = fs15.readFileSync(bridgePath, "utf-8");
6216
5460
  if (existing.length > 0 && !/@iui-managed/.test(existing)) {
6217
5461
  return;
6218
5462
  }
@@ -6237,13 +5481,13 @@ function writeProjectBootstrapArtifacts(packageDir, iuiRoot2) {
6237
5481
 
6238
5482
  // src/services/workspace-bootstrap.ts
6239
5483
  function workspaceManifestPath(iuiRoot2) {
6240
- return path21.join(iuiRoot2, IUI_DIR, "workspace.json");
5484
+ return path20.join(iuiRoot2, IUI_DIR, "workspace.json");
6241
5485
  }
6242
5486
  function readWorkspaceManifest(iuiRoot2) {
6243
5487
  const p = workspaceManifestPath(iuiRoot2);
6244
- if (!fs17.existsSync(p)) return null;
5488
+ if (!fs16.existsSync(p)) return null;
6245
5489
  try {
6246
- const raw = fs17.readJsonSync(p);
5490
+ const raw = fs16.readJsonSync(p);
6247
5491
  if (!Array.isArray(raw.packages)) return null;
6248
5492
  return {
6249
5493
  iuiRoot: raw.iuiRoot ?? iuiRoot2,
@@ -6255,40 +5499,40 @@ function readWorkspaceManifest(iuiRoot2) {
6255
5499
  }
6256
5500
  }
6257
5501
  function writeWorkspaceManifest(iuiRoot2, packageDirs) {
6258
- const unique = [...new Set(packageDirs.map((dir) => path21.resolve(dir)))];
5502
+ const unique = [...new Set(packageDirs.map((dir) => path20.resolve(dir)))];
6259
5503
  atomicWriteJson(workspaceManifestPath(iuiRoot2), {
6260
- packages: unique.map((dir) => path21.relative(iuiRoot2, dir) || "."),
5504
+ packages: unique.map((dir) => path20.relative(iuiRoot2, dir) || "."),
6261
5505
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
6262
5506
  });
6263
5507
  }
6264
5508
  function resolveRegisteredPackageDirs(iuiRoot2) {
6265
- const resolvedRoot = path21.resolve(iuiRoot2);
5509
+ const resolvedRoot = path20.resolve(iuiRoot2);
6266
5510
  const manifest = readWorkspaceManifest(resolvedRoot);
6267
5511
  if (!manifest) return [resolvedRoot];
6268
5512
  const dirs = manifest.packages.map(
6269
- (rel) => path21.resolve(resolvedRoot, rel === "." ? "" : rel)
5513
+ (rel) => path20.resolve(resolvedRoot, rel === "." ? "" : rel)
6270
5514
  );
6271
- if (!dirs.some((dir) => path21.resolve(dir) === resolvedRoot)) {
5515
+ if (!dirs.some((dir) => path20.resolve(dir) === resolvedRoot)) {
6272
5516
  dirs.unshift(resolvedRoot);
6273
5517
  }
6274
5518
  return dirs;
6275
5519
  }
6276
5520
  function registerWorkspacePackage(iuiRoot2, packageDir) {
6277
- const resolvedRoot = path21.resolve(iuiRoot2);
6278
- const resolvedPackage = path21.resolve(packageDir);
5521
+ const resolvedRoot = path20.resolve(iuiRoot2);
5522
+ const resolvedPackage = path20.resolve(packageDir);
6279
5523
  const existing = resolveRegisteredPackageDirs(resolvedRoot);
6280
- if (!existing.some((dir) => path21.resolve(dir) === resolvedPackage)) {
5524
+ if (!existing.some((dir) => path20.resolve(dir) === resolvedPackage)) {
6281
5525
  existing.push(resolvedPackage);
6282
5526
  }
6283
5527
  writeWorkspaceManifest(resolvedRoot, existing);
6284
5528
  }
6285
5529
  function registerAllWorkspacePackages(iuiRoot2) {
6286
- const resolvedRoot = path21.resolve(iuiRoot2);
5530
+ const resolvedRoot = path20.resolve(iuiRoot2);
6287
5531
  const workspaceRoot = findWorkspaceRoot(resolvedRoot);
6288
5532
  const targets = /* @__PURE__ */ new Set([resolvedRoot]);
6289
5533
  if (workspaceRoot) {
6290
5534
  for (const pkgDir of listWorkspacePackageDirs(workspaceRoot)) {
6291
- targets.add(path21.resolve(pkgDir));
5535
+ targets.add(path20.resolve(pkgDir));
6292
5536
  }
6293
5537
  }
6294
5538
  const dirs = [...targets];
@@ -6299,7 +5543,7 @@ function bootstrapRegisteredPackages(iuiRoot2) {
6299
5543
  const resolvedRoot = resolveIuiProjectRoot(iuiRoot2);
6300
5544
  const bootstrapped = [];
6301
5545
  for (const packageDir of resolveRegisteredPackageDirs(resolvedRoot)) {
6302
- if (!fs17.existsSync(path21.join(packageDir, "package.json"))) continue;
5546
+ if (!fs16.existsSync(path20.join(packageDir, "package.json"))) continue;
6303
5547
  ensureProjectNpmrc(packageDir);
6304
5548
  writeSlotBridge(packageDir, resolvedRoot);
6305
5549
  writeProjectBootstrapArtifacts(packageDir, resolvedRoot);
@@ -6308,9 +5552,9 @@ function bootstrapRegisteredPackages(iuiRoot2) {
6308
5552
  return bootstrapped;
6309
5553
  }
6310
5554
  async function bootstrapWorkspacePackage(packageDir, iuiRoot2) {
6311
- const resolvedPackage = path21.resolve(packageDir);
5555
+ const resolvedPackage = path20.resolve(packageDir);
6312
5556
  const resolvedIuiRoot = resolveIuiProjectRoot(iuiRoot2);
6313
- if (!fs17.existsSync(path21.join(resolvedPackage, "package.json"))) {
5557
+ if (!fs16.existsSync(path20.join(resolvedPackage, "package.json"))) {
6314
5558
  throw new CLIError(
6315
5559
  `No package.json found in ${resolvedPackage}.`,
6316
5560
  "Run iui init from a workspace app directory that contains package.json."
@@ -6346,17 +5590,17 @@ function checksumFor(components, slots) {
6346
5590
  return sha256(JSON.stringify({ components, slots }));
6347
5591
  }
6348
5592
  function backupCorruptFile(filePath) {
6349
- if (!fs18.existsSync(filePath)) return;
5593
+ if (!fs17.existsSync(filePath)) return;
6350
5594
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
6351
5595
  try {
6352
- fs18.moveSync(filePath, `${filePath}.corrupt-${stamp}`, { overwrite: false });
5596
+ fs17.moveSync(filePath, `${filePath}.corrupt-${stamp}`, { overwrite: false });
6353
5597
  } catch {
6354
5598
  }
6355
5599
  }
6356
5600
  function readJsonObject(filePath, fallback, issues, label) {
6357
- if (!fs18.existsSync(filePath)) return fallback;
5601
+ if (!fs17.existsSync(filePath)) return fallback;
6358
5602
  try {
6359
- const value = fs18.readJsonSync(filePath);
5603
+ const value = fs17.readJsonSync(filePath);
6360
5604
  if (value && typeof value === "object" && !Array.isArray(value)) {
6361
5605
  return value;
6362
5606
  }
@@ -6368,9 +5612,9 @@ function readJsonObject(filePath, fallback, issues, label) {
6368
5612
  }
6369
5613
  function readState(cwd, issues) {
6370
5614
  const filePath = statePath(cwd);
6371
- if (!fs18.existsSync(filePath)) return null;
5615
+ if (!fs17.existsSync(filePath)) return null;
6372
5616
  try {
6373
- const raw = fs18.readJsonSync(filePath);
5617
+ const raw = fs17.readJsonSync(filePath);
6374
5618
  if (raw.schemaVersion !== STATE_SCHEMA_VERSION) {
6375
5619
  issues.push("registration state schema was upgraded");
6376
5620
  return null;
@@ -6474,7 +5718,7 @@ async function ensureSlotRegistry(options = {}) {
6474
5718
  }
6475
5719
  const iuiRoot2 = resolveIuiProjectRoot(cwd);
6476
5720
  return withRegistryLock(iuiRoot2, async () => {
6477
- const iuiPath = path22.join(iuiRoot2, IUI_DIR);
5721
+ const iuiPath = path21.join(iuiRoot2, IUI_DIR);
6478
5722
  const issues = [];
6479
5723
  cleanupTempFiles(iuiPath);
6480
5724
  const registry = ensureInstalledManifest(
@@ -6528,9 +5772,7 @@ async function ensureSlotRegistry(options = {}) {
6528
5772
  if (driftDetected) {
6529
5773
  issues.push("slot manifests drifted");
6530
5774
  }
6531
- const generationIssues = validateGeneratedSlotImports(iuiRoot2);
6532
- const assetBoundIssues = validateGeneratedAssetBoundImports(iuiRoot2);
6533
- const integrityIssues = [...generationIssues, ...assetBoundIssues];
5775
+ const integrityIssues = validateGeneratedSlotImports(iuiRoot2);
6534
5776
  if (shouldSkipWritesFastPath({
6535
5777
  mode,
6536
5778
  previousState,
@@ -6584,7 +5826,6 @@ async function ensureSlotRegistry(options = {}) {
6584
5826
  writeComponentSlotFiles(iuiRoot2);
6585
5827
  writeAssetsConfig(iuiRoot2);
6586
5828
  ensureProjectConfig(iuiRoot2);
6587
- await writeAssetBoundFiles(iuiRoot2);
6588
5829
  writeSlotHelperFile(iuiRoot2);
6589
5830
  if (projectHasViteTooling(cwd)) {
6590
5831
  ensureInventiveUiViteConfig(cwd);
@@ -6769,7 +6010,7 @@ async function initCommand(opts) {
6769
6010
  try {
6770
6011
  heading("Initialize Project");
6771
6012
  const existingIuiRoot = findIuiProjectRoot(invocationCwd);
6772
- if (existingIuiRoot && path23.resolve(existingIuiRoot) !== path23.resolve(invocationCwd)) {
6013
+ if (existingIuiRoot && path22.resolve(existingIuiRoot) !== path22.resolve(invocationCwd)) {
6773
6014
  await bootstrapWorkspacePackage(invocationCwd, existingIuiRoot);
6774
6015
  return;
6775
6016
  }
@@ -6788,10 +6029,10 @@ async function initCommand(opts) {
6788
6029
  return;
6789
6030
  }
6790
6031
  const originalCwd = process.cwd();
6791
- if (path23.resolve(initRoot) !== path23.resolve(originalCwd)) {
6032
+ if (path22.resolve(initRoot) !== path22.resolve(originalCwd)) {
6792
6033
  process.chdir(initRoot);
6793
6034
  hint(
6794
- `Monorepo --workspace: initializing at ${path23.relative(invocationCwd, initRoot) || initRoot}`
6035
+ `Monorepo --workspace: initializing at ${path22.relative(invocationCwd, initRoot) || initRoot}`
6795
6036
  );
6796
6037
  } else if (!sharedWorkspace && findIuiProjectRoot(initRoot) === null) {
6797
6038
  hint("Initializing this package only \u2014 other monorepo apps are untouched.");
@@ -6852,7 +6093,7 @@ async function initCommand(opts) {
6852
6093
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
6853
6094
  initScope: sharedWorkspace ? "workspace" : "package",
6854
6095
  configs: {
6855
- theme: "./iui.config.ts",
6096
+ theme: "./theme.config.ts",
6856
6097
  assets: "./assets.config.json",
6857
6098
  components: "./component.config.ts"
6858
6099
  }
@@ -6913,17 +6154,17 @@ async function initCommand(opts) {
6913
6154
  step("Generating config files\u2026");
6914
6155
  writeAssetsConfig(initRoot);
6915
6156
  ensureProjectConfig(initRoot);
6916
- writeTsConfig(framework.framework, initRoot);
6157
+ ensureTsConfigForIui(framework.framework, initRoot);
6917
6158
  if (framework.framework === "vite") {
6918
6159
  ensureInventiveUiViteConfig(initRoot);
6919
- ok("Config files ready (iui.config.ts, tsconfig.json, tsconfig.node.json, vite.config.ts)");
6160
+ ok("Config files ready (theme.config.ts, tsconfig.json, tsconfig.node.json, vite.config.ts)");
6920
6161
  } else {
6921
6162
  if (removeStaleIuiViteConfig(initRoot)) {
6922
6163
  hint("Removed vite.config.ts (React-only preset \u2014 no Vite tooling required).");
6923
6164
  }
6924
- ok("Config files ready (iui.config.ts, tsconfig.json)");
6165
+ ok("Config files ready (theme.config.ts, tsconfig.json)");
6925
6166
  }
6926
- step("Generating component.config.ts\u2026");
6167
+ step("Scaffolding component.config.ts\u2026");
6927
6168
  const fetchedRegistry = await fetchComponentRegistry(auth.token);
6928
6169
  if (!fetchedRegistry.registry && fetchedRegistry.apiFailure) {
6929
6170
  warn(`Component registry API: ${fetchedRegistry.apiFailure}`);
@@ -7674,17 +6915,17 @@ async function deployTokenRevokeCommand(tokenId) {
7674
6915
  }
7675
6916
 
7676
6917
  // src/commands/setup.ts
7677
- import path26 from "path";
7678
- import fs20 from "fs-extra";
6918
+ import path25 from "path";
6919
+ import fs19 from "fs-extra";
7679
6920
  import ora6 from "ora";
7680
6921
 
7681
6922
  // src/commands/doctor.ts
7682
- import path25 from "path";
6923
+ import path24 from "path";
7683
6924
 
7684
6925
  // src/services/health.ts
7685
6926
  import { execFileSync as execFileSync2 } from "child_process";
7686
- import path24 from "path";
7687
- import fs19 from "fs-extra";
6927
+ import path23 from "path";
6928
+ import fs18 from "fs-extra";
7688
6929
  function installDevTypeScript(cwd) {
7689
6930
  const pm = detectPackageManager(cwd);
7690
6931
  try {
@@ -7727,8 +6968,8 @@ function checkGeneratedSlotValidity(cwd = process.cwd()) {
7727
6968
  };
7728
6969
  }
7729
6970
  function checkComponentConfigValidity(cwd = process.cwd(), options = {}) {
7730
- const configPath = path24.join(cwd, COMPONENT_CONFIG_FILE);
7731
- if (!fs19.existsSync(configPath)) {
6971
+ const configPath = path23.join(cwd, COMPONENT_CONFIG_FILE);
6972
+ if (!fs18.existsSync(configPath)) {
7732
6973
  return {
7733
6974
  ok: false,
7734
6975
  summary: "component.config.ts not found",
@@ -7736,8 +6977,8 @@ function checkComponentConfigValidity(cwd = process.cwd(), options = {}) {
7736
6977
  };
7737
6978
  }
7738
6979
  const tsPkgDir = resolvePackageDir("typescript", cwd);
7739
- const tscPath = tsPkgDir ? path24.join(tsPkgDir, "bin", "tsc") : path24.join(cwd, "node_modules", "typescript", "bin", "tsc");
7740
- if (!fs19.existsSync(tscPath)) {
6980
+ const tscPath = tsPkgDir ? path23.join(tsPkgDir, "bin", "tsc") : path23.join(cwd, "node_modules", "typescript", "bin", "tsc");
6981
+ if (!fs18.existsSync(tscPath)) {
7741
6982
  if (!options.autoFix) {
7742
6983
  return {
7743
6984
  ok: false,
@@ -7805,33 +7046,36 @@ ${stderr}`.trim() };
7805
7046
  function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
7806
7047
  const warnings = [];
7807
7048
  const hints = [];
7808
- const configPath = path24.join(cwd, PROJECT_CONFIG_FILE);
7809
- if (fs19.existsSync(configPath)) {
7810
- const configContent = fs19.readFileSync(configPath, "utf-8");
7049
+ const configPath = path23.join(
7050
+ cwd,
7051
+ fs18.existsSync(path23.join(cwd, PROJECT_CONFIG_FILE)) || !fs18.existsSync(path23.join(cwd, "iui.config.ts")) ? PROJECT_CONFIG_FILE : "iui.config.ts"
7052
+ );
7053
+ if (fs18.existsSync(configPath)) {
7054
+ const configContent = fs18.readFileSync(configPath, "utf-8");
7811
7055
  if (/packageSafelist\s*:\s*false/.test(configContent)) {
7812
7056
  warnings.push(
7813
- "Deprecated iui.config build.packageSafelist \u2014 remove it; Framework always merges IUI package compile contracts"
7057
+ "Deprecated theme.config build.packageSafelist \u2014 remove it; Framework always merges IUI package compile contracts"
7814
7058
  );
7815
7059
  }
7816
7060
  if (/includeShadeMatrix\s*:/.test(configContent)) {
7817
7061
  warnings.push(
7818
- "Deprecated compiler flags in iui.config build.* \u2014 remove them; compile policy is Framework-internal"
7062
+ "Deprecated compiler flags in theme.config build.* \u2014 remove them; compile policy is Framework-internal"
7819
7063
  );
7820
7064
  hints.push("Use theme + optional scan.dirs only. See Framework docs/01-compile-first-guide.md");
7821
7065
  }
7822
7066
  if (/scanPackages\s*:/.test(configContent) || /scan\.packages\s*:/.test(configContent)) {
7823
7067
  warnings.push(
7824
- "Deprecated scanPackages in iui.config \u2014 IUI packages are discovered from package.json dependencies"
7068
+ "Deprecated scanPackages in theme.config \u2014 IUI packages are discovered from package.json dependencies"
7825
7069
  );
7826
7070
  }
7827
7071
  }
7828
7072
  if (projectHasViteTooling(cwd)) {
7829
7073
  const viteCandidates = ["vite.config.ts", "vite.config.mjs", "vite.config.js"];
7830
- const vitePath = viteCandidates.map((name) => path24.join(cwd, name)).find((p) => fs19.existsSync(p));
7074
+ const vitePath = viteCandidates.map((name) => path23.join(cwd, name)).find((p) => fs18.existsSync(p));
7831
7075
  if (!vitePath) {
7832
7076
  warnings.push("Vite tooling detected but no vite.config.* found");
7833
7077
  } else {
7834
- const viteContent = fs19.readFileSync(vitePath, "utf-8");
7078
+ const viteContent = fs18.readFileSync(vitePath, "utf-8");
7835
7079
  if (!/inventiveUiVite\s*\(/.test(viteContent)) {
7836
7080
  warnings.push("vite.config is missing inventiveUiVite() \u2014 compile-first CSS will not generate");
7837
7081
  hints.push("Wire plugins: [...inventiveUiVite({ root: import.meta.dirname }), react()]");
@@ -7845,11 +7089,11 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
7845
7089
  "webpack.config.mjs",
7846
7090
  "webpack.config.ts"
7847
7091
  ];
7848
- const webpackPath = webpackCandidates.map((name) => path24.join(cwd, name)).find((p) => fs19.existsSync(p));
7092
+ const webpackPath = webpackCandidates.map((name) => path23.join(cwd, name)).find((p) => fs18.existsSync(p));
7849
7093
  if (!webpackPath) {
7850
7094
  warnings.push("Webpack tooling detected but no webpack.config.* found");
7851
7095
  } else {
7852
- const webpackContent = fs19.readFileSync(webpackPath, "utf-8");
7096
+ const webpackContent = fs18.readFileSync(webpackPath, "utf-8");
7853
7097
  if (!/inventiveUiWebpack\s*\(/.test(webpackContent)) {
7854
7098
  warnings.push("webpack.config is missing inventiveUiWebpack() \u2014 compile-first CSS will not generate");
7855
7099
  hints.push('Wire plugins: [...inventiveUiWebpack()] from "@inventive-ui/framework/webpack"');
@@ -7859,11 +7103,11 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
7859
7103
  }
7860
7104
  if (projectHasNextTooling(cwd)) {
7861
7105
  const nextCandidates = ["next.config.ts", "next.config.mjs", "next.config.js", "next.config.cjs"];
7862
- const nextPath = nextCandidates.map((name) => path24.join(cwd, name)).find((p) => fs19.existsSync(p));
7106
+ const nextPath = nextCandidates.map((name) => path23.join(cwd, name)).find((p) => fs18.existsSync(p));
7863
7107
  if (!nextPath) {
7864
7108
  warnings.push("Next.js detected but no next.config.* found");
7865
7109
  } else {
7866
- const nextContent = fs19.readFileSync(nextPath, "utf-8");
7110
+ const nextContent = fs18.readFileSync(nextPath, "utf-8");
7867
7111
  if (!/withIUI\s*\(/.test(nextContent)) {
7868
7112
  warnings.push("next.config is missing withIUI() \u2014 compile-first CSS will not generate");
7869
7113
  hints.push('Wrap config: export default withIUI({ ... }) from "@inventive-ui/framework/next"');
@@ -7876,18 +7120,18 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
7876
7120
  "src/app/layout.jsx",
7877
7121
  "app/providers.tsx",
7878
7122
  "src/app/providers.tsx"
7879
- ].map((rel) => path24.join(cwd, rel));
7880
- const readableLayouts = layoutCandidates.filter((file) => fs19.existsSync(file));
7123
+ ].map((rel) => path23.join(cwd, rel));
7124
+ const readableLayouts = layoutCandidates.filter((file) => fs18.existsSync(file));
7881
7125
  const hasRegistry = readableLayouts.some((file) => {
7882
7126
  try {
7883
- return /\bIUIRegistry\b/.test(fs19.readFileSync(file, "utf-8"));
7127
+ return /\bIUIRegistry\b/.test(fs18.readFileSync(file, "utf-8"));
7884
7128
  } catch {
7885
7129
  return false;
7886
7130
  }
7887
7131
  });
7888
7132
  const hasBootstrapImport = readableLayouts.some((file) => {
7889
7133
  try {
7890
- const content = fs19.readFileSync(file, "utf-8");
7134
+ const content = fs18.readFileSync(file, "utf-8");
7891
7135
  return /next\/bootstrap/.test(content) || /["']iui-bootstrap["']/.test(content) || /iui\/bootstrap/.test(content);
7892
7136
  } catch {
7893
7137
  return false;
@@ -7895,7 +7139,7 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
7895
7139
  });
7896
7140
  const hasProvider = readableLayouts.some((file) => {
7897
7141
  try {
7898
- return /\bIUIProvider\b/.test(fs19.readFileSync(file, "utf-8"));
7142
+ return /\bIUIProvider\b/.test(fs18.readFileSync(file, "utf-8"));
7899
7143
  } catch {
7900
7144
  return false;
7901
7145
  }
@@ -7926,14 +7170,14 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
7926
7170
  "src/app/providers.tsx",
7927
7171
  "app/layout.tsx",
7928
7172
  "src/app/layout.tsx"
7929
- ].map((rel) => path24.join(cwd, rel));
7173
+ ].map((rel) => path23.join(cwd, rel));
7930
7174
  for (const file of entryCandidates) {
7931
- if (!fs19.existsSync(file)) continue;
7175
+ if (!fs18.existsSync(file)) continue;
7932
7176
  try {
7933
- const content = fs19.readFileSync(file, "utf-8");
7177
+ const content = fs18.readFileSync(file, "utf-8");
7934
7178
  if (/from\s+['"][^'"]*\.generated['"]/.test(content) || /import\s+['"][^'"]*\.generated['"]/.test(content)) {
7935
7179
  warnings.push(
7936
- `Do not import .generated style-map files into the browser (${path24.relative(cwd, file)})`
7180
+ `Do not import .generated style-map files into the browser (${path23.relative(cwd, file)})`
7937
7181
  );
7938
7182
  hints.push(
7939
7183
  "Keep style maps on the scanner path (default src + .iui/generated, or override build.scanDirs) \u2014 see Framework compile-first docs"
@@ -7953,9 +7197,9 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
7953
7197
  hints.push(
7954
7198
  "Compile-first: avoid dynamic utility templates like `p-${n}` \u2014 use static strings, style maps, or safelist (ESLint: customPlugin/no-dynamic-utility-class)"
7955
7199
  );
7956
- const giPath = path24.join(cwd, ".gitignore");
7957
- if (fs19.existsSync(giPath)) {
7958
- const gi = fs19.readFileSync(giPath, "utf-8");
7200
+ const giPath = path23.join(cwd, ".gitignore");
7201
+ if (fs18.existsSync(giPath)) {
7202
+ const gi = fs18.readFileSync(giPath, "utf-8");
7959
7203
  if (!gi.includes(".iui/cache/")) {
7960
7204
  warnings.push(".gitignore missing IUI cache directory (.iui/cache/)");
7961
7205
  hints.push("Run iui init or append .iui/cache/ from the IUI docs");
@@ -7966,11 +7210,11 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
7966
7210
  function checkMetadataPortability(cwd = process.cwd()) {
7967
7211
  const warnings = [];
7968
7212
  const hints = [];
7969
- const iuiPath = path24.join(cwd, IUI_DIR);
7970
- const projectPath = path24.join(iuiPath, "project.json");
7971
- if (fs19.existsSync(projectPath)) {
7213
+ const iuiPath = path23.join(cwd, IUI_DIR);
7214
+ const projectPath = path23.join(iuiPath, "project.json");
7215
+ if (fs18.existsSync(projectPath)) {
7972
7216
  try {
7973
- const meta = fs19.readJsonSync(projectPath);
7217
+ const meta = fs18.readJsonSync(projectPath);
7974
7218
  const repoUrl = meta.repoUrl ?? "";
7975
7219
  if (/^[A-Za-z]:[\\/]/.test(repoUrl) || repoUrl.startsWith("/") && !repoUrl.startsWith("//") || repoUrl.startsWith("file:")) {
7976
7220
  warnings.push("project.json repoUrl is a local filesystem path \u2014 use a git remote URL");
@@ -7979,15 +7223,15 @@ function checkMetadataPortability(cwd = process.cwd()) {
7979
7223
  } catch {
7980
7224
  }
7981
7225
  }
7982
- const workspacePath = path24.join(iuiPath, "workspace.json");
7983
- if (fs19.existsSync(workspacePath)) {
7226
+ const workspacePath = path23.join(iuiPath, "workspace.json");
7227
+ if (fs18.existsSync(workspacePath)) {
7984
7228
  try {
7985
- const ws = fs19.readJsonSync(workspacePath);
7229
+ const ws = fs18.readJsonSync(workspacePath);
7986
7230
  if (ws.iuiRoot) {
7987
7231
  warnings.push("workspace.json contains deprecated iuiRoot \u2014 remove it (root is implicit)");
7988
7232
  }
7989
7233
  for (const pkg of ws.packages ?? []) {
7990
- if (/^[A-Za-z]:[\\/]/.test(pkg) || path24.isAbsolute(pkg)) {
7234
+ if (/^[A-Za-z]:[\\/]/.test(pkg) || path23.isAbsolute(pkg)) {
7991
7235
  warnings.push(`workspace.json packages entry is absolute: ${pkg}`);
7992
7236
  hints.push("packages should be relative paths from the IUI root");
7993
7237
  }
@@ -7996,9 +7240,9 @@ function checkMetadataPortability(cwd = process.cwd()) {
7996
7240
  }
7997
7241
  }
7998
7242
  const scanCachePath = iuiCacheFile(cwd, "scan");
7999
- if (fs19.existsSync(scanCachePath)) {
7243
+ if (fs18.existsSync(scanCachePath)) {
8000
7244
  try {
8001
- const cache = fs19.readJsonSync(scanCachePath);
7245
+ const cache = fs18.readJsonSync(scanCachePath);
8002
7246
  const absoluteKeys = Object.keys(cache.files ?? {}).filter(
8003
7247
  (key) => /^[A-Za-z]:[\\/]/.test(key) || key.startsWith("/") && !key.startsWith("//")
8004
7248
  );
@@ -8015,38 +7259,70 @@ function checkMetadataPortability(cwd = process.cwd()) {
8015
7259
  }
8016
7260
  return { warnings, hints };
8017
7261
  }
8018
- function checkAssetBoundBindings(cwd = process.cwd()) {
8019
- const assetsPath = path24.join(cwd, ASSETS_CONFIG_FILE);
8020
- if (!fs19.existsSync(assetsPath)) {
8021
- return { ok: true, summary: "Asset binding check skipped (no assets.config.json)" };
7262
+ var ICON_LIBRARY_PACKAGES = {
7263
+ "material-symbols": "material-symbols",
7264
+ materialSymbols: "material-symbols",
7265
+ "material-icons": "icons-material",
7266
+ lucide: "icons-lucide",
7267
+ phosphor: "icons-phosphor"
7268
+ };
7269
+ function checkAssetPipeline(cwd = process.cwd()) {
7270
+ const assetsPath = path23.join(cwd, ASSETS_CONFIG_FILE);
7271
+ if (!fs18.existsSync(assetsPath)) {
7272
+ return { ok: true, summary: "Asset check skipped (no assets.config.json)" };
8022
7273
  }
8023
7274
  let assets2;
8024
7275
  try {
8025
- assets2 = fs19.readJsonSync(assetsPath);
7276
+ assets2 = fs18.readJsonSync(assetsPath);
8026
7277
  } catch {
8027
7278
  return { ok: false, summary: "assets.config.json is not valid JSON" };
8028
7279
  }
8029
- if (assets2.binding !== "scanned") {
8030
- return { ok: true, summary: "Asset slots use lazy binding (default)" };
7280
+ const packagesDir = path23.join(cwd, "node_modules", "@inventive-ui");
7281
+ const frameworkPkg = path23.join(packagesDir, "framework", "package.json");
7282
+ if (fs18.existsSync(frameworkPkg)) {
7283
+ const framework = fs18.readJsonSync(frameworkPkg);
7284
+ if (!framework.exports?.["./assets"]) {
7285
+ return {
7286
+ ok: false,
7287
+ summary: "Installed @inventive-ui/framework has no asset pipeline",
7288
+ details: "Update it: iui update"
7289
+ };
7290
+ }
7291
+ }
7292
+ const library = assets2.icon?.library;
7293
+ const pkg = library ? ICON_LIBRARY_PACKAGES[library] : void 0;
7294
+ if (!pkg) return { ok: true, summary: "Asset config valid" };
7295
+ const iconsDir = path23.join(packagesDir, pkg, "dist", "icons");
7296
+ if (!fs18.existsSync(iconsDir)) {
7297
+ return {
7298
+ ok: false,
7299
+ summary: `Icon library "${library}" is configured but @inventive-ui/${pkg} is not installed`,
7300
+ details: `Install it: iui install assets @inventive-ui/${pkg}`
7301
+ };
8031
7302
  }
8032
- const registerBound = path24.join(generatedAssetsDir(cwd), "register-bound.ts");
8033
- if (!fs19.existsSync(registerBound)) {
7303
+ const glyphs = [
7304
+ ...Object.entries(assets2.icon?.globalIcons ?? {}).map(([alias, glyph]) => [`@${alias}`, glyph]),
7305
+ ["placeholder", assets2.icon?.placeholder?.name],
7306
+ ["fallback", assets2.icon?.fallback]
7307
+ ].filter((entry) => typeof entry[1] === "string" && entry[1].length > 0);
7308
+ const missing = glyphs.filter(([, glyph]) => !fs18.existsSync(path23.join(iconsDir, `${glyph}.js`)));
7309
+ if (missing.length > 0) {
8034
7310
  return {
8035
7311
  ok: false,
8036
- summary: 'binding is "scanned" but .iui/generated/assets/register-bound.ts is missing',
8037
- details: "Run any iui command to refresh the slot registry, or reinstall asset packages."
7312
+ summary: `${missing.length} icon alias${missing.length === 1 ? "" : "es"} point at glyphs "${library}" does not have`,
7313
+ details: missing.slice(0, 8).map(([name, glyph]) => `${name} \u2192 ${glyph}`).join(", ")
8038
7314
  };
8039
7315
  }
8040
- return { ok: true, summary: "Scanned asset bindings present" };
7316
+ return { ok: true, summary: `Asset config valid (${glyphs.length} icon names checked in ${library})` };
8041
7317
  }
8042
7318
  function checkBootstrapSync(cwd = process.cwd(), options = {}) {
8043
7319
  const iuiRoot2 = resolveIuiProjectRoot(cwd);
8044
7320
  const generatedPath = bootstrapGeneratedPath(iuiRoot2);
8045
- const bridgePath = path24.join(cwd, "src", "iui", "bootstrap.ts");
8046
- if (!fs19.existsSync(generatedPath)) {
7321
+ const bridgePath = path23.join(cwd, "src", "iui", "bootstrap.ts");
7322
+ if (!fs18.existsSync(generatedPath)) {
8047
7323
  if (options.autoFix) {
8048
7324
  writeProjectBootstrapArtifacts(cwd, iuiRoot2);
8049
- if (fs19.existsSync(generatedPath)) {
7325
+ if (fs18.existsSync(generatedPath)) {
8050
7326
  return { ok: true, summary: "Generated bootstrap artifacts repaired" };
8051
7327
  }
8052
7328
  }
@@ -8056,10 +7332,10 @@ function checkBootstrapSync(cwd = process.cwd(), options = {}) {
8056
7332
  details: "Expected .iui/generated/bootstrap.generated.tsx \u2014 run iui doctor --fix."
8057
7333
  };
8058
7334
  }
8059
- if (!fs19.existsSync(bridgePath)) {
7335
+ if (!fs18.existsSync(bridgePath)) {
8060
7336
  if (options.autoFix) {
8061
7337
  writeProjectBootstrapArtifacts(cwd, iuiRoot2);
8062
- if (fs19.existsSync(bridgePath)) {
7338
+ if (fs18.existsSync(bridgePath)) {
8063
7339
  return { ok: true, summary: "Bootstrap bridge repaired" };
8064
7340
  }
8065
7341
  }
@@ -8072,8 +7348,8 @@ function checkBootstrapSync(cwd = process.cwd(), options = {}) {
8072
7348
  const configs = resolveProjectConfigPaths(iuiRoot2);
8073
7349
  const missing = [];
8074
7350
  for (const [key, rel] of Object.entries(configs)) {
8075
- const abs = path24.resolve(iuiRoot2, rel.replace(/^\.\//, ""));
8076
- if (!fs19.existsSync(abs)) missing.push(`${key}: ${rel}`);
7351
+ const abs = path23.resolve(iuiRoot2, rel.replace(/^\.\//, ""));
7352
+ if (!fs18.existsSync(abs)) missing.push(`${key}: ${rel}`);
8077
7353
  }
8078
7354
  if (missing.length > 0) {
8079
7355
  return {
@@ -8083,7 +7359,7 @@ function checkBootstrapSync(cwd = process.cwd(), options = {}) {
8083
7359
  };
8084
7360
  }
8085
7361
  const expected = expectedBootstrapImportPaths(iuiRoot2);
8086
- const generated = fs19.readFileSync(generatedPath, "utf8");
7362
+ const generated = fs18.readFileSync(generatedPath, "utf8");
8087
7363
  const stale = [];
8088
7364
  for (const [key, importPath] of Object.entries(expected)) {
8089
7365
  if (!generated.includes(`"${importPath}"`)) {
@@ -8093,7 +7369,7 @@ function checkBootstrapSync(cwd = process.cwd(), options = {}) {
8093
7369
  if (stale.length > 0) {
8094
7370
  if (options.autoFix) {
8095
7371
  writeProjectBootstrapArtifacts(cwd, iuiRoot2);
8096
- const refreshed = fs19.readFileSync(bootstrapGeneratedPath(iuiRoot2), "utf8");
7372
+ const refreshed = fs18.readFileSync(bootstrapGeneratedPath(iuiRoot2), "utf8");
8097
7373
  const stillStale = Object.entries(expected).filter(
8098
7374
  ([, importPath]) => !refreshed.includes(`"${importPath}"`)
8099
7375
  );
@@ -8111,7 +7387,7 @@ function checkBootstrapSync(cwd = process.cwd(), options = {}) {
8111
7387
  }
8112
7388
 
8113
7389
  // src/commands/doctor.ts
8114
- function runConfigTierDiagnostics(targetCwd, opts, counters, options = {}) {
7390
+ async function runConfigTierDiagnostics(targetCwd, opts, counters, options = {}) {
8115
7391
  const pass = (label) => {
8116
7392
  checkPass(label);
8117
7393
  counters.passed++;
@@ -8129,10 +7405,13 @@ function runConfigTierDiagnostics(targetCwd, opts, counters, options = {}) {
8129
7405
  if (opts?.fix === true && includePackageJson) {
8130
7406
  ensureProjectConfig(targetCwd);
8131
7407
  ensureGitignoreHasIuiBuildCache(targetCwd);
8132
- if (projectHasViteTooling(targetCwd)) {
7408
+ const vite = projectHasViteTooling(targetCwd);
7409
+ ensureTsConfigForIui(vite ? "vite" : "react", targetCwd);
7410
+ if (vite) {
8133
7411
  ensureInventiveUiViteConfig(targetCwd);
8134
7412
  }
8135
7413
  ensureComponentConfig(readComponentPackageManifest(targetCwd), targetCwd);
7414
+ await ensureSlotRegistry({ cwd: targetCwd, quiet: true, mode: "repair" });
8136
7415
  }
8137
7416
  if (includeSlotCheck && isInsideProject(targetCwd) && getInstalledPackageVersion(COMPONENTS_PACKAGE, targetCwd)) {
8138
7417
  const slotValidity = checkGeneratedSlotValidity(targetCwd);
@@ -8216,12 +7495,12 @@ function runConfigTierDiagnostics(targetCwd, opts, counters, options = {}) {
8216
7495
  hint(hint2);
8217
7496
  }
8218
7497
  }
8219
- const assetBound = checkAssetBoundBindings(targetCwd);
8220
- if (assetBound.ok) {
8221
- pass(assetBound.summary);
7498
+ const assetPipeline = checkAssetPipeline(targetCwd);
7499
+ if (assetPipeline.ok) {
7500
+ pass(assetPipeline.summary);
8222
7501
  } else {
8223
- warn(assetBound.summary);
8224
- if (assetBound.details) hint(assetBound.details);
7502
+ warn(assetPipeline.summary);
7503
+ if (assetPipeline.details) hint(assetPipeline.details);
8225
7504
  }
8226
7505
  }
8227
7506
  async function runPackageDiagnostics(targetCwd, opts, counters) {
@@ -8234,7 +7513,7 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
8234
7513
  counters.failed++;
8235
7514
  };
8236
7515
  if (opts?.configOnly) {
8237
- runConfigTierDiagnostics(targetCwd, opts, counters, {
7516
+ await runConfigTierDiagnostics(targetCwd, opts, counters, {
8238
7517
  includePackageJson: true,
8239
7518
  includeSlotCheck: true
8240
7519
  });
@@ -8244,10 +7523,13 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
8244
7523
  else fail2("package.json missing");
8245
7524
  if (opts?.fix === true) {
8246
7525
  ensureProjectConfig(targetCwd);
8247
- if (projectHasViteTooling(targetCwd)) {
7526
+ const vite2 = projectHasViteTooling(targetCwd);
7527
+ ensureTsConfigForIui(vite2 ? "vite" : "react", targetCwd);
7528
+ if (vite2) {
8248
7529
  ensureInventiveUiViteConfig(targetCwd);
8249
7530
  }
8250
7531
  ensureComponentConfig(readComponentPackageManifest(targetCwd), targetCwd);
7532
+ await ensureSlotRegistry({ cwd: targetCwd, quiet: true, mode: "repair" });
8251
7533
  }
8252
7534
  if (isInsideProject(targetCwd)) {
8253
7535
  pass("Inventive UI project initialized");
@@ -8366,7 +7648,7 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
8366
7648
  hint("Fix: run iui doctor --fix to regenerate bootstrap artifacts");
8367
7649
  }
8368
7650
  }
8369
- runConfigTierDiagnostics(targetCwd, opts, counters, {
7651
+ await runConfigTierDiagnostics(targetCwd, opts, counters, {
8370
7652
  includePackageJson: false,
8371
7653
  includeSlotCheck: false
8372
7654
  });
@@ -8374,7 +7656,7 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
8374
7656
  async function doctorCommand(opts) {
8375
7657
  try {
8376
7658
  const invocationCwd = process.cwd();
8377
- const targets = opts?.cwd ? [path25.resolve(opts.cwd)] : resolveSetupDoctorTargets(invocationCwd);
7659
+ const targets = opts?.cwd ? [path24.resolve(opts.cwd)] : resolveSetupDoctorTargets(invocationCwd);
8378
7660
  const installRoot = resolveDependencyInstallRoot(invocationCwd);
8379
7661
  const multiPackage = targets.length > 1;
8380
7662
  heading("Diagnostics");
@@ -8417,7 +7699,7 @@ async function doctorCommand(opts) {
8417
7699
  for (const targetCwd of targets) {
8418
7700
  if (multiPackage) {
8419
7701
  newline();
8420
- const label = path25.relative(installRoot, targetCwd) || path25.basename(targetCwd);
7702
+ const label = path24.relative(installRoot, targetCwd) || path24.basename(targetCwd);
8421
7703
  kv("Package", label);
8422
7704
  }
8423
7705
  await runPackageDiagnostics(targetCwd, opts, counters);
@@ -8445,9 +7727,9 @@ async function doctorCommand(opts) {
8445
7727
 
8446
7728
  // src/commands/setup.ts
8447
7729
  function detectDevScript(cwd) {
8448
- const pkgPath = path26.join(cwd, "package.json");
7730
+ const pkgPath = path25.join(cwd, "package.json");
8449
7731
  try {
8450
- const pkg = fs20.readJsonSync(pkgPath);
7732
+ const pkg = fs19.readJsonSync(pkgPath);
8451
7733
  if (pkg.scripts?.dev) return "npm run dev";
8452
7734
  if (pkg.scripts?.start) return "npm run start";
8453
7735
  } catch {
@@ -8456,8 +7738,8 @@ function detectDevScript(cwd) {
8456
7738
  return null;
8457
7739
  }
8458
7740
  function relativePackageLabel(installRoot, packageDir) {
8459
- const rel = path26.relative(installRoot, packageDir);
8460
- return rel && rel !== "." ? rel : path26.basename(packageDir);
7741
+ const rel = path25.relative(installRoot, packageDir);
7742
+ return rel && rel !== "." ? rel : path25.basename(packageDir);
8461
7743
  }
8462
7744
  async function setupCommand(opts) {
8463
7745
  try {
@@ -8466,7 +7748,7 @@ async function setupCommand(opts) {
8466
7748
  const installRoot = resolveDependencyInstallRoot(cwd);
8467
7749
  const workspaceRoot = findWorkspaceRoot(cwd);
8468
7750
  const inMonorepo = workspaceRoot !== null;
8469
- const installFromChild = inMonorepo && path26.resolve(installRoot) !== path26.resolve(cwd);
7751
+ const installFromChild = inMonorepo && path25.resolve(installRoot) !== path25.resolve(cwd);
8470
7752
  if (!hasPackageJson(cwd) && !hasPackageJson(installRoot)) {
8471
7753
  throw new CLIError(
8472
7754
  "No package.json found in the current directory.",
@@ -8500,7 +7782,7 @@ async function setupCommand(opts) {
8500
7782
  for (const w of warnings) warn(w);
8501
7783
  kv("Package manager", `${pm} (${source})`);
8502
7784
  if (installFromChild) {
8503
- const rel = path26.relative(cwd, installRoot) || ".";
7785
+ const rel = path25.relative(cwd, installRoot) || ".";
8504
7786
  kv("Install directory", rel === ".." || rel.includes("..") ? installRoot : rel);
8505
7787
  }
8506
7788
  const installCmd2 = syncInstallCommand(pm);
@@ -8514,7 +7796,7 @@ async function setupCommand(opts) {
8514
7796
  } catch (err) {
8515
7797
  installSpinner.fail("Dependency install failed");
8516
7798
  const detail = formatExecSyncError(err);
8517
- const manual = path26.resolve(installRoot) === path26.resolve(cwd) ? installCmd2 : `cd ${JSON.stringify(installRoot)} && ${installCmd2}`;
7799
+ const manual = path25.resolve(installRoot) === path25.resolve(cwd) ? installCmd2 : `cd ${JSON.stringify(installRoot)} && ${installCmd2}`;
8518
7800
  throw new CLIError(
8519
7801
  detail ? `Could not install project dependencies.
8520
7802
  ${detail}` : "Could not install project dependencies.",
@@ -8672,7 +7954,7 @@ async function updateCommand(opts = {}) {
8672
7954
  const auth = await ensureAuthSession();
8673
7955
  await ensureLicenseSession();
8674
7956
  const inProject = isInsideProject();
8675
- const currentCliVersion = true ? "0.0.9" : "unknown";
7957
+ const currentCliVersion = true ? "0.0.11" : "unknown";
8676
7958
  const latestCliVersion = await fetchLatestCliVersion(auth.token);
8677
7959
  const cliUpdateAvailable = latestCliVersion !== null && isVersionGreater(latestCliVersion, currentCliVersion);
8678
7960
  if (latestCliVersion && cliUpdateAvailable) {
@@ -8954,7 +8236,7 @@ var AUTH_EXEMPT_COMMANDS = /* @__PURE__ */ new Set([
8954
8236
  "doctor",
8955
8237
  "list"
8956
8238
  ]);
8957
- program.name("iui").description("The official CLI for the Inventive UI Design System").version(true ? "0.0.9" : "1.0.0").option("-C, --cwd <dir>", "Run as if started in the given directory").option("-q, --quiet", "Minimal output (also respects IUI_QUIET=1)").option("--no-color", "Disable ANSI colors");
8239
+ program.name("iui").description("The official CLI for the Inventive UI Design System").version(true ? "0.0.11" : "1.0.0").option("-C, --cwd <dir>", "Run as if started in the given directory").option("-q, --quiet", "Minimal output (also respects IUI_QUIET=1)").option("--no-color", "Disable ANSI colors");
8958
8240
  program.command("login").description("Authenticate with GitHub and link your license").option("-f, --force", "Force re-authentication and register this device").option("--bootstrap", "After login, run optional setup prompts").action((opts) => loginCommand(opts));
8959
8241
  program.command("logout").description("Remove stored credentials").action(logoutCommand);
8960
8242
  program.command("whoami").description("Show authenticated identity and license details").action(whoamiCommand);
@@ -9037,7 +8319,7 @@ program.command("update").description("Check for and apply framework, component,
9037
8319
  var assets = program.command("assets").description("Manage asset packages (icons, illustrations, logos, etc.)");
9038
8320
  assets.command("remove <package>").description("Remove an installed asset package").action((pkg) => assetsRemoveCommand(pkg));
9039
8321
  assets.command("list").description("Show all available and installed asset packages").action(assetsListCommand);
9040
- program.command("doctor").description("Run project health diagnostics (read-only by default)").option("--fix", "Apply safe config patches (iui.config, vite.config, component.config)").option("--config-only", "Validate project config tiers only (no auth/registry)").action((opts) => doctorCommand(opts));
8322
+ program.command("doctor").description("Run project health diagnostics (read-only by default)").option("--fix", "Apply safe config patches (theme.config, vite.config, component.config)").option("--config-only", "Validate project config tiers only (no auth/registry)").action((opts) => doctorCommand(opts));
9041
8323
  if (shouldShowBanner()) {
9042
8324
  printBanner();
9043
8325
  }
@@ -9052,7 +8334,7 @@ program.hook("preAction", async (_thisCommand, actionCommand) => {
9052
8334
  const root = topLevelCommandName(actionCommand);
9053
8335
  const globalOpts = program.opts();
9054
8336
  if (globalOpts.cwd) {
9055
- process.chdir(path27.resolve(globalOpts.cwd));
8337
+ process.chdir(path26.resolve(globalOpts.cwd));
9056
8338
  }
9057
8339
  if (isInsideProject()) {
9058
8340
  try {