inventive-ui 0.0.10 → 0.0.12

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 path25 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.10" : "1.0.0";
193
+ return true ? "0.0.12" : "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 path26 = parsed.pathname.replace(/\/+$/, "");
377
+ if (path26 && !/^\/[a-zA-Z0-9._/-]+$/.test(path26)) {
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",
@@ -763,22 +763,6 @@ function writeJsonRestricted(filePath, data) {
763
763
 
764
764
  // src/utils/security/paths.ts
765
765
  import path4 from "path";
766
- function assertWithinRoot(rootDir, targetPath, label) {
767
- const root = path4.resolve(rootDir);
768
- const target = path4.resolve(targetPath);
769
- const rel = path4.relative(root, target);
770
- if (rel.startsWith("..") || path4.isAbsolute(rel)) {
771
- throw new CLIError(
772
- `Unsafe ${label} path: ${targetPath}`,
773
- `Path must stay within ${rootDir}`
774
- );
775
- }
776
- }
777
- function resolveWithinRoot(rootDir, ...segments) {
778
- const joined = path4.join(rootDir, ...segments);
779
- assertWithinRoot(rootDir, joined, "file");
780
- return joined;
781
- }
782
766
 
783
767
  // src/utils/security/process.ts
784
768
  import fs5 from "fs-extra";
@@ -1428,7 +1412,7 @@ function resolveFrameworkScriptsDir(startCwd) {
1428
1412
  if (existsSync(loader)) return scriptsDir;
1429
1413
  }
1430
1414
  throw new CLIError(
1431
- `Cannot scaffold iui.config.ts: ${FRAMEWORK_PACKAGE} is not installed or is missing scripts/load-framework-theme-defaults.mjs.`
1415
+ `Cannot scaffold theme.config.ts: ${FRAMEWORK_PACKAGE} is not installed or is missing scripts/load-framework-theme-defaults.mjs.`
1432
1416
  );
1433
1417
  }
1434
1418
  function buildProjectConfigSource(cwd = process.cwd()) {
@@ -1934,32 +1918,12 @@ function patchProjectConfigBuildBlock(content) {
1934
1918
  import ts2 from "typescript";
1935
1919
 
1936
1920
  // src/utils/security/identifiers.ts
1937
- var SLUG_RE = /^[a-z][a-z0-9-]*$/;
1938
1921
  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
- );
1947
- }
1948
- }
1949
1922
  function assertJsIdentifier(name, label) {
1950
1923
  if (!JS_IDENTIFIER_RE.test(name)) {
1951
1924
  throw new CLIError(`Invalid ${label}: "${name}"`);
1952
1925
  }
1953
1926
  }
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}"`);
1959
- }
1960
- function escapeTsStringLiteral(value) {
1961
- return JSON.stringify(value);
1962
- }
1963
1927
  function sanitizePackageVersionHeader(value) {
1964
1928
  if (!value) return null;
1965
1929
  const trimmed = value.trim();
@@ -2043,7 +2007,6 @@ function mergeComponentConfigContent(source, manifest) {
2043
2007
  // src/utils/config-patch/tsconfig-iui.ts
2044
2008
  import path7 from "path";
2045
2009
  import fs6 from "fs-extra";
2046
- var IUI_TS_ROOT_FILES = ["iui.config.ts", "component.config.ts"];
2047
2010
  function isSolutionStyleTsconfig(config) {
2048
2011
  const refs = config.references;
2049
2012
  return Array.isArray(refs) && refs.length > 0;
@@ -2101,7 +2064,8 @@ function patchSolutionStyleTsconfigForIui(cwd) {
2101
2064
  if (!isSolutionStyleTsconfig(existing)) return false;
2102
2065
  const repairedRoot = repairSolutionStyleRootTsconfig(cwd);
2103
2066
  const appPath = resolveAppTsconfigPath(cwd, existing);
2104
- const patchedApp = appPath ? patchJsonInclude(appPath, IUI_TS_ROOT_FILES) : false;
2067
+ const themeFile = fs6.existsSync(path7.join(cwd, "iui.config.ts")) && !fs6.existsSync(path7.join(cwd, "theme.config.ts")) ? "iui.config.ts" : "theme.config.ts";
2068
+ const patchedApp = appPath ? patchJsonInclude(appPath, [themeFile, "component.config.ts"]) : false;
2105
2069
  return repairedRoot || patchedApp;
2106
2070
  }
2107
2071
 
@@ -2119,10 +2083,9 @@ var iuiThemeConfigSchema = z2.object({
2119
2083
  }).strict();
2120
2084
  var IuiThemeConfigSchema = iuiThemeConfigSchema.refine(
2121
2085
  (data) => !("assets" in data),
2122
- { message: "iui.config must not contain an assets key \u2014 use assets.config.json" }
2086
+ { message: "theme.config must not contain an assets key \u2014 use assets.config.json" }
2123
2087
  );
2124
2088
  var AssetsConfigSchema = z2.object({
2125
- binding: z2.enum(["lazy", "scanned"]).optional(),
2126
2089
  preload: z2.enum(["none", "configured", "scanned"]).optional(),
2127
2090
  icon: z2.object({
2128
2091
  library: z2.string().optional(),
@@ -2195,11 +2158,14 @@ function stripAssetsFromIuiConfig(content) {
2195
2158
  return next;
2196
2159
  }
2197
2160
  function checkIuiConfigTierBleed(cwd = process.cwd(), options = {}) {
2198
- const configPath = path8.join(cwd, PROJECT_CONFIG_FILE);
2161
+ const configPath = path8.join(
2162
+ cwd,
2163
+ fs7.existsSync(path8.join(cwd, PROJECT_CONFIG_FILE)) || !fs7.existsSync(path8.join(cwd, "iui.config.ts")) ? PROJECT_CONFIG_FILE : "iui.config.ts"
2164
+ );
2199
2165
  if (!fs7.existsSync(configPath)) {
2200
2166
  return {
2201
2167
  ok: false,
2202
- summary: "iui.config.ts not found",
2168
+ summary: "theme.config.ts not found",
2203
2169
  details: "Run iui init to scaffold project config."
2204
2170
  };
2205
2171
  }
@@ -2214,7 +2180,7 @@ function checkIuiConfigTierBleed(cwd = process.cwd(), options = {}) {
2214
2180
  }
2215
2181
  }
2216
2182
  if (issues.length === 0) {
2217
- return { ok: true, summary: "iui.config.ts tier boundaries are valid" };
2183
+ return { ok: true, summary: "theme.config.ts tier boundaries are valid" };
2218
2184
  }
2219
2185
  if (options.autoFix) {
2220
2186
  const fixed = stripAssetsFromIuiConfig(content);
@@ -2227,14 +2193,14 @@ function checkIuiConfigTierBleed(cwd = process.cwd(), options = {}) {
2227
2193
  if (remaining.length === 0 && /\bbuild\s*:\s*\{/.test(content)) {
2228
2194
  return {
2229
2195
  ok: true,
2230
- summary: "iui.config.ts repaired (removed assets tier bleed)"
2196
+ summary: "theme.config.ts repaired (removed assets tier bleed)"
2231
2197
  };
2232
2198
  }
2233
2199
  }
2234
2200
  }
2235
2201
  return {
2236
2202
  ok: false,
2237
- summary: "iui.config.ts violates three-config tier boundaries",
2203
+ summary: "theme.config.ts violates three-config tier boundaries",
2238
2204
  details: issues.map((i) => `- ${i}`).join("\n")
2239
2205
  };
2240
2206
  }
@@ -2441,9 +2407,6 @@ function componentManifestPath(cwd) {
2441
2407
  function packageManifestPath(cwd) {
2442
2408
  return metaPath("packages.json", cwd);
2443
2409
  }
2444
- function slotManifestPath(cwd) {
2445
- return metaPath("slots.json", cwd);
2446
- }
2447
2410
  function readProjectJsonStrict(p, label) {
2448
2411
  if (!fs8.existsSync(p)) {
2449
2412
  throw new CLIError(`Missing ${label}.`, "Run iui init to initialize the project.");
@@ -2528,12 +2491,6 @@ function mergeAssetSlotWithTemplate(slot, templateSlot) {
2528
2491
  function seedAssetsOutputFromTemplate(output) {
2529
2492
  const template = loadAssetsConfigTemplate();
2530
2493
  for (const [key, tplVal] of Object.entries(template)) {
2531
- if (key === "binding") {
2532
- if (output.binding === void 0 && tplVal !== void 0) {
2533
- output.binding = tplVal;
2534
- }
2535
- continue;
2536
- }
2537
2494
  if (typeof tplVal === "object" && tplVal !== null && !Array.isArray(tplVal)) {
2538
2495
  output[key] = mergeAssetSlotWithTemplate(
2539
2496
  output[key],
@@ -2541,13 +2498,6 @@ function seedAssetsOutputFromTemplate(output) {
2541
2498
  );
2542
2499
  }
2543
2500
  }
2544
- if (output.binding === "scanned") {
2545
- output.preload = output.preload ?? "scanned";
2546
- const icon = output.icon;
2547
- if (icon && typeof icon === "object" && !Array.isArray(icon)) {
2548
- icon.preload = icon.preload ?? "scanned";
2549
- }
2550
- }
2551
2501
  }
2552
2502
  function assetsConfigPath(cwd) {
2553
2503
  return path10.join(resolveIuiProjectRoot(cwd ?? process.cwd()), ASSETS_CONFIG_FILE);
@@ -2707,9 +2657,6 @@ function writeAssetsConfig(cwd = process.cwd()) {
2707
2657
  delete output[legacyKey];
2708
2658
  }
2709
2659
  }
2710
- if (output.binding === void 0 && Object.keys(assets2).length > 0 && projectHasViteTooling(cwd)) {
2711
- output.binding = "scanned";
2712
- }
2713
2660
  seedAssetsOutputFromTemplate(output);
2714
2661
  writeJson(assetsConfigPath(cwd), output);
2715
2662
  try {
@@ -2718,14 +2665,6 @@ function writeAssetsConfig(cwd = process.cwd()) {
2718
2665
  } catch {
2719
2666
  }
2720
2667
  }
2721
- function readSlotManifest(cwd) {
2722
- const p = slotManifestPath(cwd);
2723
- if (!fs8.existsSync(p)) return {};
2724
- return readProjectJsonStrict(p, ".iui/slots.json");
2725
- }
2726
- function writeSlotManifest(manifest, cwd) {
2727
- writeJson(slotManifestPath(cwd), manifest);
2728
- }
2729
2668
  function readComponentPackageManifest(cwd = process.cwd()) {
2730
2669
  const pkgDir = resolvePackageDir("@inventive-ui/components", cwd);
2731
2670
  if (!pkgDir) return null;
@@ -2762,12 +2701,19 @@ function registryItemsMap(manifest) {
2762
2701
  }
2763
2702
  return map;
2764
2703
  }
2704
+ function resolveProjectConfigPath(root) {
2705
+ const current = path10.join(root, PROJECT_CONFIG_FILE);
2706
+ if (fs8.existsSync(current)) return current;
2707
+ const previous = path10.join(root, "iui.config.ts");
2708
+ if (fs8.existsSync(previous)) return previous;
2709
+ return current;
2710
+ }
2765
2711
  function writeProjectConfig(cwd = process.cwd()) {
2766
2712
  const configPath = path10.join(cwd, PROJECT_CONFIG_FILE);
2767
2713
  atomicWriteFile(configPath, buildProjectConfigSource(cwd));
2768
2714
  }
2769
2715
  function ensureProjectConfigBuildBlock(cwd = process.cwd()) {
2770
- const configPath = path10.join(resolveIuiProjectRoot(cwd), PROJECT_CONFIG_FILE);
2716
+ const configPath = resolveProjectConfigPath(resolveIuiProjectRoot(cwd));
2771
2717
  if (!fs8.existsSync(configPath)) return false;
2772
2718
  const before = fs8.readFileSync(configPath, "utf-8");
2773
2719
  const result = patchProjectConfigBuildBlock(before);
@@ -2777,7 +2723,7 @@ function ensureProjectConfigBuildBlock(cwd = process.cwd()) {
2777
2723
  }
2778
2724
  function ensureProjectConfig(cwd = process.cwd()) {
2779
2725
  const root = resolveIuiProjectRoot(cwd);
2780
- const configPath = path10.join(root, PROJECT_CONFIG_FILE);
2726
+ const configPath = resolveProjectConfigPath(root);
2781
2727
  if (!fs8.existsSync(configPath)) {
2782
2728
  writeProjectConfig(root);
2783
2729
  return "scaffolded";
@@ -2907,7 +2853,8 @@ function writeFlatProjectTsConfig(framework, cwd = process.cwd()) {
2907
2853
  }
2908
2854
  const include = Array.isArray(existing.include) ? [...existing.include.map(String)] : [];
2909
2855
  if (!include.includes("src")) include.push("src");
2910
- const rootConfigFiles = ["iui.config.ts", "component.config.ts"];
2856
+ const themeConfigFile = fs8.existsSync(path10.join(cwd, "iui.config.ts")) && !fs8.existsSync(path10.join(cwd, PROJECT_CONFIG_FILE)) ? "iui.config.ts" : PROJECT_CONFIG_FILE;
2857
+ const rootConfigFiles = [themeConfigFile, "component.config.ts"];
2911
2858
  for (const rootFile of rootConfigFiles) {
2912
2859
  if (!include.includes(rootFile)) include.push(rootFile);
2913
2860
  }
@@ -3371,13 +3318,13 @@ function ensureInventiveUiViteConfig(cwd = process.cwd()) {
3371
3318
  }
3372
3319
 
3373
3320
  // src/services/auth.ts
3374
- async function api(path28, opts) {
3375
- const res = await fetch(`${API_BASE_URL}${path28}`, {
3321
+ async function api(path26, opts) {
3322
+ const res = await fetch(`${API_BASE_URL}${path26}`, {
3376
3323
  ...opts,
3377
3324
  signal: opts?.signal ?? AbortSignal.timeout(API_REQUEST_TIMEOUT_MS),
3378
3325
  headers: { "Content-Type": "application/json", ...opts?.headers }
3379
3326
  });
3380
- throwIfRateLimited(res, `calling ${path28}`);
3327
+ throwIfRateLimited(res, `calling ${path26}`);
3381
3328
  if (!res.ok) {
3382
3329
  const body = await res.text().catch(() => "");
3383
3330
  throw new CLIError(`API error ${res.status}: ${body || res.statusText}`);
@@ -3629,10 +3576,12 @@ async function promptAssetSelection(installedPackages = []) {
3629
3576
  const choices = [];
3630
3577
  for (const cat of categories) {
3631
3578
  const inCategory = catalogue.filter((p) => p.category === cat);
3579
+ if (choices.length > 0) {
3580
+ choices.push(new inquirer.Separator(" "));
3581
+ }
3632
3582
  choices.push(
3633
3583
  new inquirer.Separator(
3634
- `
3635
- ${brand.bold(ASSET_CATEGORY_LABELS[cat])} ${dim(`(${inCategory.length})`)}`
3584
+ ` ${brand.bold(ASSET_CATEGORY_LABELS[cat])} ${dim(`(${inCategory.length})`)}`
3636
3585
  )
3637
3586
  );
3638
3587
  for (const pkg of inCategory) {
@@ -3644,6 +3593,8 @@ async function promptAssetSelection(installedPackages = []) {
3644
3593
  }
3645
3594
  }
3646
3595
  console.log();
3596
+ const terminalRows = process.stdout.rows ?? 0;
3597
+ const pageSize = terminalRows > 0 ? Math.max(10, Math.min(choices.length, terminalRows - 4)) : choices.length;
3647
3598
  const { selected } = await inquirer.prompt([
3648
3599
  {
3649
3600
  type: "checkbox",
@@ -3651,7 +3602,7 @@ async function promptAssetSelection(installedPackages = []) {
3651
3602
  message: chalk2.dim("Toggle packages to install"),
3652
3603
  prefix: PROMPT_PREFIX,
3653
3604
  choices,
3654
- pageSize: 20,
3605
+ pageSize,
3655
3606
  loop: false
3656
3607
  }
3657
3608
  ]);
@@ -3733,7 +3684,7 @@ async function promptChooseEmojiFamily(fallbackCurrent) {
3733
3684
  assertInteractivePrompt("emoji family choice");
3734
3685
  inputBox(
3735
3686
  "Emoji Family",
3736
- "Choose the default CDN style for emoji slots. Skin tone defaults to medium-light."
3687
+ "Choose the default CDN style for emoji slots. Skin tone defaults to medium-light (`mediumLight`)."
3737
3688
  );
3738
3689
  const { chosen } = await inquirer.prompt([
3739
3690
  {
@@ -3825,7 +3776,7 @@ async function promptText(title, hint2, placeholder, validate) {
3825
3776
  }
3826
3777
 
3827
3778
  // src/commands/init.ts
3828
- import path23 from "path";
3779
+ import path21 from "path";
3829
3780
  import ora3 from "ora";
3830
3781
 
3831
3782
  // src/services/license.ts
@@ -4792,8 +4743,8 @@ function getMajorFromVersion(version) {
4792
4743
  import ora2 from "ora";
4793
4744
 
4794
4745
  // src/services/slot-registry.ts
4795
- import fs18 from "fs-extra";
4796
- import path22 from "path";
4746
+ import fs16 from "fs-extra";
4747
+ import path20 from "path";
4797
4748
 
4798
4749
  // src/services/registry-lock.ts
4799
4750
  import fs11 from "fs";
@@ -4879,113 +4830,107 @@ async function withRegistryLock(cwd, operation) {
4879
4830
  }
4880
4831
  }
4881
4832
 
4882
- // src/services/slots.ts
4883
- import fs15 from "fs-extra";
4884
- import path19 from "path";
4833
+ // src/services/legacy-slot-cleanup.ts
4834
+ import fs12 from "fs-extra";
4835
+ import path16 from "path";
4885
4836
 
4886
- // src/utils/public-slot-contract.ts
4837
+ // src/services/generated-paths.ts
4887
4838
  import path15 from "path";
4888
- import fs12 from "fs-extra";
4889
- var CONTRACT_FILENAME = "public-slot-contract.json";
4890
- function loadPublicSlotContract(cwd = process.cwd()) {
4891
- const pkgRoot = resolvePackageDir("@inventive-ui/components", cwd);
4892
- if (!pkgRoot) return null;
4893
- const contractPath = path15.join(pkgRoot, CONTRACT_FILENAME);
4894
- if (!fs12.existsSync(contractPath)) return null;
4839
+ function iuiProjectRoot2(cwd) {
4840
+ return resolveIuiProjectRoot(cwd);
4841
+ }
4842
+ function generatedIuiDir(cwd) {
4843
+ return path15.join(iuiProjectRoot2(cwd), ".iui", "generated");
4844
+ }
4845
+
4846
+ // src/services/legacy-slot-cleanup.ts
4847
+ var MANAGED_MARKER = /@iui-managed|Managed by iui/;
4848
+ function isManagedFile(filePath) {
4895
4849
  try {
4896
- return fs12.readJsonSync(contractPath);
4850
+ return MANAGED_MARKER.test(fs12.readFileSync(filePath, "utf-8"));
4897
4851
  } catch {
4898
- return null;
4852
+ return false;
4899
4853
  }
4900
4854
  }
4901
- function slotRequiresPrefetch(entry) {
4902
- if (entry.prefetch === true) return true;
4903
- if (entry.prefetch === false) return false;
4904
- if (entry.bootstrap === "sync") return true;
4905
- return Array.isArray(entry.profile) && entry.profile.includes("critical");
4906
- }
4907
- function contractEntryToBootstrapPolicy(entry) {
4908
- return slotRequiresPrefetch(entry) ? "core" : "optional";
4909
- }
4910
- function validateSlotPrefetchPolicy(entry) {
4911
- const type = entry.type ?? "?";
4912
- const requires = slotRequiresPrefetch(entry);
4913
- if (requires && entry.prefetch === false) {
4914
- return `slot "${type}" is core/critical but prefetch is false`;
4915
- }
4916
- if ((entry.bootstrap === "sync" || Array.isArray(entry.profile) && entry.profile.includes("critical")) && entry.prefetch !== true) {
4917
- return `slot "${type}" must declare prefetch: true (sync/critical peer hub)`;
4918
- }
4919
- if (!requires && entry.prefetch === true) {
4920
- return `slot "${type}" declares prefetch: true but is not sync/critical`;
4855
+ function listFiles(dir, match) {
4856
+ if (!fs12.existsSync(dir)) return [];
4857
+ try {
4858
+ return fs12.readdirSync(dir).filter(match).map((file) => path16.join(dir, file));
4859
+ } catch {
4860
+ return [];
4921
4861
  }
4922
- return null;
4923
- }
4924
-
4925
- // src/utils/slot-emitters.ts
4926
- function contractEntryToEmitter(entry) {
4927
- const lazyAccess = entry.lazyAccess.startsWith(".") ? entry.lazyAccess : `.${entry.lazyAccess}`;
4928
- return {
4929
- type: entry.type,
4930
- parentSlug: entry.parent,
4931
- componentName: entry.component ?? entry.type,
4932
- propsName: entry.props,
4933
- importSpecifier: entry.import,
4934
- lazyImportSpecifier: entry.lazyImport ?? entry.import,
4935
- lazyAccess
4936
- };
4937
4862
  }
4938
- function isContractEntryInstalled(entry, installedSlugs) {
4939
- if (!entry.public) return false;
4940
- if (installedSlugs.has(entry.type)) return true;
4941
- if (installedSlugs.has(entry.parent)) return true;
4942
- return false;
4863
+ function ownedDirs(iuiRoot2, packageDirs) {
4864
+ const generated = generatedIuiDir(iuiRoot2);
4865
+ return [
4866
+ path16.join(generated, "slots"),
4867
+ path16.join(generated, "assets"),
4868
+ ...packageDirs.map((dir) => path16.join(dir, "src", "iui", "slots"))
4869
+ ];
4943
4870
  }
4944
- function collectInstalledSlotEmitters(items, installedSlugs, cwd = process.cwd()) {
4945
- const contract = loadPublicSlotContract(cwd);
4946
- if (!contract) {
4947
- return {
4948
- emitters: [],
4949
- issues: [
4950
- "@inventive-ui/components/public-slot-contract.json is missing from node_modules."
4951
- ]
4952
- };
4953
- }
4954
- const issues = [];
4955
- const emitters = [];
4956
- const registrySlugs = new Set(items.map((item) => item.name));
4957
- for (const slug of installedSlugs) {
4958
- if (!registrySlugs.has(slug)) continue;
4959
- const hasPrimary = contract.slots.some(
4960
- (entry) => entry.public && entry.type === slug
4871
+ function findStaleComponentSlotOutput(cwd, packageDirs = []) {
4872
+ const iuiRoot2 = iuiProjectRoot2(cwd);
4873
+ const generated = generatedIuiDir(iuiRoot2);
4874
+ const packages = [...new Set([iuiRoot2, ...packageDirs].map((dir) => path16.resolve(dir)))];
4875
+ const stale = [];
4876
+ stale.push(
4877
+ ...listFiles(
4878
+ path16.join(generated, "slots"),
4879
+ (file) => file.endsWith(".generated.tsx") || file.endsWith(".slot.tsx")
4880
+ )
4881
+ );
4882
+ const helper = path16.join(generated, "slot.generated.tsx");
4883
+ if (fs12.existsSync(helper) && isManagedFile(helper)) stale.push(helper);
4884
+ stale.push(
4885
+ ...listFiles(
4886
+ path16.join(generated, "assets"),
4887
+ (file) => file.endsWith(".bound.ts") || file === "register-bound.ts"
4888
+ )
4889
+ );
4890
+ const manifest = path16.join(iuiRoot2, ".iui", "slots.json");
4891
+ if (fs12.existsSync(manifest)) stale.push(manifest);
4892
+ for (const packageDir of packages) {
4893
+ const bridge = path16.join(packageDir, "src", "iui", "slot.tsx");
4894
+ if (fs12.existsSync(bridge) && isManagedFile(bridge)) stale.push(bridge);
4895
+ stale.push(
4896
+ ...listFiles(
4897
+ path16.join(packageDir, "src", "iui", "slots"),
4898
+ (file) => file.endsWith(".slot.tsx")
4899
+ )
4961
4900
  );
4962
- if (!hasPrimary) {
4963
- issues.push(`${slug}: no public slot contract entry for primary type "${slug}"`);
4964
- }
4965
4901
  }
4966
- for (const entry of contract.slots) {
4967
- if (!isContractEntryInstalled(entry, installedSlugs)) continue;
4968
- if (!entry.props || !entry.lazyAccess || !entry.import) {
4969
- issues.push(`${entry.type}: incomplete public slot contract entry`);
4970
- continue;
4902
+ return stale;
4903
+ }
4904
+ function removeStaleComponentSlotOutput(cwd, packageDirs = []) {
4905
+ const iuiRoot2 = iuiProjectRoot2(cwd);
4906
+ const removed = [];
4907
+ for (const file of findStaleComponentSlotOutput(iuiRoot2, packageDirs)) {
4908
+ try {
4909
+ fs12.removeSync(file);
4910
+ removed.push(file);
4911
+ } catch {
4971
4912
  }
4972
- emitters.push(contractEntryToEmitter(entry));
4973
4913
  }
4974
- const deduped = /* @__PURE__ */ new Map();
4975
- for (const emitter of emitters) {
4976
- if (!deduped.has(emitter.type)) {
4977
- deduped.set(emitter.type, emitter);
4914
+ for (const dir of ownedDirs(iuiRoot2, [iuiRoot2, ...packageDirs])) {
4915
+ try {
4916
+ if (fs12.existsSync(dir) && fs12.readdirSync(dir).length === 0) fs12.removeSync(dir);
4917
+ } catch {
4978
4918
  }
4979
4919
  }
4980
- return {
4981
- emitters: [...deduped.values()].sort((a, b) => a.type.localeCompare(b.type)),
4982
- issues
4983
- };
4920
+ return removed;
4984
4921
  }
4985
4922
 
4923
+ // src/services/workspace-bootstrap.ts
4924
+ import path19 from "path";
4925
+ import fs15 from "fs-extra";
4926
+
4927
+ // src/services/bootstrap.ts
4928
+ import fs14 from "fs-extra";
4929
+ import path18 from "path";
4930
+
4986
4931
  // src/utils/security/fsSafe.ts
4987
4932
  import fs13 from "fs";
4988
- import path16 from "path";
4933
+ import path17 from "path";
4989
4934
  function assertNotSymlink(filePath, label) {
4990
4935
  try {
4991
4936
  const stat = fs13.lstatSync(filePath);
@@ -4999,11 +4944,11 @@ function assertNotSymlink(filePath, label) {
4999
4944
  }
5000
4945
  }
5001
4946
  function safeWriteFile(filePath, content) {
5002
- const dir = path16.dirname(filePath);
4947
+ const dir = path17.dirname(filePath);
5003
4948
  if (fs13.existsSync(dir)) {
5004
4949
  assertNotSymlink(dir, "directory");
5005
4950
  }
5006
- const parent = path16.dirname(filePath);
4951
+ const parent = path17.dirname(filePath);
5007
4952
  fs13.mkdirSync(parent, { recursive: true });
5008
4953
  if (fs13.existsSync(filePath)) {
5009
4954
  assertNotSymlink(filePath, "file");
@@ -5011,700 +4956,13 @@ function safeWriteFile(filePath, content) {
5011
4956
  atomicWriteFile(filePath, content);
5012
4957
  }
5013
4958
 
5014
- // src/services/asset-bound.ts
5015
- import fs14 from "fs-extra";
5016
- import path18 from "path";
5017
- import { pathToFileURL } from "url";
5018
-
5019
- // src/services/generated-paths.ts
5020
- import path17 from "path";
5021
- function iuiProjectRoot2(cwd) {
5022
- return resolveIuiProjectRoot(cwd);
5023
- }
5024
- function generatedIuiDir(cwd) {
5025
- return path17.join(iuiProjectRoot2(cwd), ".iui", "generated");
5026
- }
5027
- function generatedSlotsDir(cwd) {
5028
- return path17.join(generatedIuiDir(cwd), "slots");
5029
- }
5030
- function generatedAssetsDir(cwd) {
5031
- return path17.join(generatedIuiDir(cwd), "assets");
5032
- }
5033
-
5034
- // src/services/asset-bound.ts
5035
- var LIBRARY_TO_PKG = {
5036
- lucide: "icons-lucide",
5037
- phosphor: "icons-phosphor",
5038
- material: "icons-material",
5039
- "material-icons": "icons-material",
5040
- materialSymbols: "material-symbols",
5041
- "material-symbols": "material-symbols"
5042
- };
5043
- var PKG_LOOKUP_PREFIX = {
5044
- "icons-lucide": "icons/",
5045
- "icons-phosphor": "icons/",
5046
- "icons-material": "icons/",
5047
- "material-symbols": "icons/",
5048
- logos: "logos/",
5049
- "color-logos": "logos/",
5050
- flags: "flags/",
5051
- "file-types": "types/",
5052
- loaders: "loaders/",
5053
- illustrations: ""
5054
- };
5055
- var BOUND_SPECS = [
5056
- {
5057
- slotType: "icon",
5058
- fileName: "icons.bound.ts",
5059
- exportName: "BOUND_ICONS",
5060
- packages: /* @__PURE__ */ new Set([
5061
- "material-symbols",
5062
- "icons-lucide",
5063
- "icons-phosphor",
5064
- "icons-material"
5065
- ]),
5066
- filterByDefaultIconLibrary: true
5067
- },
5068
- {
5069
- slotType: "logo",
5070
- fileName: "logos.bound.ts",
5071
- exportName: "BOUND_LOGOS",
5072
- packages: /* @__PURE__ */ new Set(["logos"])
5073
- },
5074
- {
5075
- slotType: "color-logo",
5076
- fileName: "color-logos.bound.ts",
5077
- exportName: "BOUND_COLOR_LOGOS",
5078
- packages: /* @__PURE__ */ new Set(["color-logos"])
5079
- },
5080
- {
5081
- slotType: "flag",
5082
- fileName: "flags.bound.ts",
5083
- exportName: "BOUND_FLAGS",
5084
- packages: /* @__PURE__ */ new Set(["flags"])
5085
- },
5086
- {
5087
- slotType: "file-type",
5088
- fileName: "file-types.bound.ts",
5089
- exportName: "BOUND_FILE_TYPES",
5090
- packages: /* @__PURE__ */ new Set(["file-types"])
5091
- },
5092
- {
5093
- slotType: "loader",
5094
- fileName: "loaders.bound.ts",
5095
- exportName: "BOUND_LOADERS",
5096
- packages: /* @__PURE__ */ new Set(["loaders"])
5097
- },
5098
- {
5099
- slotType: "illustration",
5100
- fileName: "illustrations.bound.ts",
5101
- exportName: "BOUND_ILLUSTRATIONS",
5102
- packages: /* @__PURE__ */ new Set(["illustrations"])
5103
- }
5104
- ];
5105
- function isAssetPackageInstalled(cwd, pkgId) {
5106
- return resolvePackageDir(`@inventive-ui/${pkgId}`, cwd) !== null;
5107
- }
5108
- var DEFAULT_SCAN = {
5109
- scanDirs: ["src", ".storybook", "stories", ".iui"],
5110
- include: [
5111
- "**/*.stories.*",
5112
- "**/*.mdx",
5113
- "**/src/**/*.tsx",
5114
- "**/src/**/*.ts",
5115
- "**/src/**/*.jsx",
5116
- "**/src/**/*.js",
5117
- "**/.storybook/**/*.tsx",
5118
- "**/.storybook/**/*.ts",
5119
- "**/.storybook/**/*.jsx",
5120
- "**/.storybook/**/*.js"
5121
- ],
5122
- exclude: ["**/*.test.*", "**/*.spec.*"]
5123
- };
5124
- function resolveFrameworkModule(cwd, relativePath) {
5125
- const searchRoots = /* @__PURE__ */ new Set();
5126
- for (const candidate of [
5127
- resolveDependencyInstallRoot(cwd),
5128
- path18.resolve(cwd),
5129
- iuiProjectRoot2(cwd)
5130
- ]) {
5131
- searchRoots.add(path18.resolve(candidate));
5132
- }
5133
- for (const start of searchRoots) {
5134
- const frameworkDir = resolvePackageDir("@inventive-ui/framework", start);
5135
- if (!frameworkDir) continue;
5136
- const installed = path18.join(frameworkDir, relativePath);
5137
- if (fs14.existsSync(installed)) return installed;
5138
- }
5139
- const root = iuiProjectRoot2(cwd);
5140
- for (const candidate of [
5141
- path18.join(root, "..", "Framework", relativePath),
5142
- path18.join(root, "..", "..", "Framework", relativePath)
5143
- ]) {
5144
- if (fs14.existsSync(candidate)) return candidate;
5145
- }
5146
- return null;
5147
- }
5148
- async function loadScanUtils(cwd) {
5149
- const scanPath = resolveFrameworkModule(
5150
- cwd,
5151
- "integrations/vite/scan-used-slot-assets.mjs"
5152
- );
5153
- const resolvePath = resolveFrameworkModule(
5154
- cwd,
5155
- "integrations/shared/resolve-scanned-icon-name.mjs"
5156
- );
5157
- if (!scanPath || !resolvePath) {
5158
- const installRoot = resolveDependencyInstallRoot(cwd);
5159
- const frameworkDir = resolvePackageDir("@inventive-ui/framework", installRoot);
5160
- 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.";
5161
- throw new CLIError("Could not load Framework scan utilities.", hint2);
5162
- }
5163
- const scanMod = await import(pathToFileURL(scanPath).href);
5164
- const resolveMod = await import(pathToFileURL(resolvePath).href);
5165
- return { ...scanMod, ...resolveMod };
5166
- }
5167
- function lookupKeyToGlyphKey(pkg, lookupKey) {
5168
- let subpath = lookupKey.replace(/^\.\//, "").replace(/\.js$/, "");
5169
- if (pkg === "illustrations") {
5170
- return subpath;
5171
- }
5172
- const prefix = PKG_LOOKUP_PREFIX[pkg];
5173
- if (prefix && subpath.startsWith(prefix)) {
5174
- subpath = subpath.slice(prefix.length);
5175
- }
5176
- return subpath;
5177
- }
5178
- function glyphToIdentifier(name, used) {
5179
- let base = name.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
5180
- if (!base || !/^[A-Za-z_$]/.test(base)) {
5181
- base = `Glyph${base}`;
5182
- }
5183
- let id = base;
5184
- let suffix = 2;
5185
- while (used.has(id)) {
5186
- id = `${base}${suffix++}`;
5187
- }
5188
- used.add(id);
5189
- return id;
5190
- }
5191
- function resolveIconPkg(library) {
5192
- return LIBRARY_TO_PKG[library] ?? library;
5193
- }
5194
- function buildBoundFileContent(exportName, entries) {
5195
- const lines = [
5196
- "// Managed by iui. Do not edit manually.",
5197
- '// Static glyph bindings for scanned assets (`binding: "scanned"`).',
5198
- "",
5199
- 'import type { ComponentType } from "react";'
5200
- ];
5201
- for (const entry of entries) {
5202
- lines.push(`import ${entry.identifier} from "${entry.moduleId}";`);
5203
- }
5204
- lines.push("");
5205
- lines.push(
5206
- `export const ${exportName}: Record<string, ComponentType<Record<string, unknown>>> = {`
5207
- );
5208
- for (const entry of entries) {
5209
- lines.push(` ${JSON.stringify(entry.key)}: ${entry.identifier},`);
5210
- }
5211
- lines.push("};");
5212
- lines.push("");
5213
- return lines.join("\n");
5214
- }
5215
- function cleanupAssetBoundFiles(cwd) {
5216
- const assetsDir = generatedAssetsDir(cwd);
5217
- if (!fs14.existsSync(assetsDir)) return;
5218
- for (const file of fs14.readdirSync(assetsDir)) {
5219
- if (file.endsWith(".bound.ts") || file === "register-bound.ts") {
5220
- fs14.removeSync(path18.join(assetsDir, file));
5221
- }
5222
- }
5223
- const remaining = fs14.readdirSync(assetsDir);
5224
- if (remaining.length === 0) {
5225
- fs14.removeSync(assetsDir);
5226
- }
5227
- }
5228
- function hasAssetBoundRegistration(cwd) {
5229
- return fs14.existsSync(path18.join(generatedAssetsDir(cwd), "register-bound.ts"));
5230
- }
5231
- async function writeAssetBoundFiles(cwd = process.cwd()) {
5232
- const root = iuiProjectRoot2(cwd);
5233
- const scanUtils = await loadScanUtils(cwd);
5234
- const activeSpecs = BOUND_SPECS.filter(
5235
- (spec) => scanUtils.isScannedAssetBindingEnabled(root, spec.slotType)
5236
- );
5237
- if (activeSpecs.length === 0) {
5238
- cleanupAssetBoundFiles(root);
5239
- return;
5240
- }
5241
- const registry = scanUtils.scanUsedSlotAssets(root, DEFAULT_SCAN);
5242
- const defaultIconLibrary = scanUtils.readDefaultIconLibraryFromConfig(root);
5243
- const defaultIconPkg = resolveIconPkg(defaultIconLibrary);
5244
- const assetsDir = generatedAssetsDir(root);
5245
- fs14.ensureDirSync(assetsDir);
5246
- const generatedFiles = /* @__PURE__ */ new Set();
5247
- const registrationSpecs = [];
5248
- for (const spec of activeSpecs) {
5249
- const entries = [];
5250
- const usedIdentifiers = /* @__PURE__ */ new Set();
5251
- for (const [pkg, keys] of registry.entries()) {
5252
- if (!spec.packages.has(pkg)) continue;
5253
- if ("filterByDefaultIconLibrary" in spec && spec.filterByDefaultIconLibrary && pkg !== defaultIconPkg) {
5254
- continue;
5255
- }
5256
- if (!isAssetPackageInstalled(cwd, pkg)) continue;
5257
- for (const lookupKey of keys) {
5258
- const key = lookupKeyToGlyphKey(pkg, lookupKey);
5259
- const moduleId = scanUtils.lookupKeyToModuleId(pkg, lookupKey);
5260
- const identifier = glyphToIdentifier(key, usedIdentifiers);
5261
- if (entries.some((entry) => entry.key === key)) continue;
5262
- entries.push({ key, moduleId, identifier });
5263
- }
5264
- }
5265
- entries.sort((a, b) => a.key.localeCompare(b.key));
5266
- if (entries.length === 0) {
5267
- continue;
5268
- }
5269
- const content = buildBoundFileContent(spec.exportName, entries);
5270
- const outPath = resolveWithinRoot(
5271
- root,
5272
- ".iui",
5273
- "generated",
5274
- "assets",
5275
- spec.fileName
5276
- );
5277
- safeWriteFile(outPath, content);
5278
- generatedFiles.add(spec.fileName);
5279
- registrationSpecs.push({
5280
- slotType: spec.slotType,
5281
- exportName: spec.exportName,
5282
- fileName: spec.fileName
5283
- });
5284
- }
5285
- const existing = fs14.existsSync(assetsDir) ? fs14.readdirSync(assetsDir).filter((f) => f.endsWith(".bound.ts")) : [];
5286
- for (const file of existing) {
5287
- if (!generatedFiles.has(file)) {
5288
- fs14.removeSync(path18.join(assetsDir, file));
5289
- }
5290
- }
5291
- if (registrationSpecs.length === 0) {
5292
- cleanupAssetBoundFiles(root);
5293
- return;
5294
- }
5295
- const registerLines = [
5296
- "// Managed by iui. Do not edit manually.",
5297
- "",
5298
- 'import { registerBoundAssetComponents } from "@inventive-ui/framework/slots";'
5299
- ];
5300
- for (const spec of registrationSpecs) {
5301
- registerLines.push(
5302
- `import { ${spec.exportName} } from "./${spec.fileName.replace(/\.ts$/, "")}";`
5303
- );
5304
- }
5305
- registerLines.push("");
5306
- for (const spec of registrationSpecs) {
5307
- registerLines.push(
5308
- `registerBoundAssetComponents(${JSON.stringify(spec.slotType)}, ${spec.exportName});`
5309
- );
5310
- }
5311
- registerLines.push("");
5312
- safeWriteFile(
5313
- resolveWithinRoot(root, ".iui", "generated", "assets", "register-bound.ts"),
5314
- registerLines.join("\n")
5315
- );
5316
- }
5317
- function assetModuleCandidates(pkgRoot, moduleId) {
5318
- const pkgName = moduleId.split("/").slice(0, 2).join("/");
5319
- const subpath = moduleId.slice(pkgName.length + 1);
5320
- const pkgId = pkgName.replace("@inventive-ui/", "");
5321
- if (!subpath || subpath.includes("..")) return [];
5322
- if (pkgId === "loaders") {
5323
- return [path18.join(pkgRoot, "dist", "loaders", `${subpath}.js`)];
5324
- }
5325
- if (pkgId === "illustrations") {
5326
- const [family, scene] = subpath.split("/");
5327
- if (family && scene) {
5328
- return [path18.join(pkgRoot, "dist", family, `${scene}.js`)];
5329
- }
5330
- return [path18.join(pkgRoot, "dist", `${subpath}.js`)];
5331
- }
5332
- const prefix = PKG_LOOKUP_PREFIX[pkgId];
5333
- if (prefix) {
5334
- const dir = prefix.replace(/\/$/, "");
5335
- return [
5336
- path18.join(pkgRoot, "dist", dir, `${subpath}.js`),
5337
- path18.join(pkgRoot, "dist", `${subpath}.js`),
5338
- path18.join(pkgRoot, "dist", subpath, "index.js")
5339
- ];
5340
- }
5341
- return [
5342
- path18.join(pkgRoot, "dist", `${subpath}.js`),
5343
- path18.join(pkgRoot, "dist", subpath, "index.js")
5344
- ];
5345
- }
5346
- function validateGeneratedAssetBoundImports(cwd = process.cwd()) {
5347
- const assetsDir = generatedAssetsDir(cwd);
5348
- if (!fs14.existsSync(assetsDir)) return [];
5349
- const issues = [];
5350
- const boundFiles = fs14.readdirSync(assetsDir).filter((file) => file.endsWith(".bound.ts"));
5351
- for (const file of boundFiles) {
5352
- const content = fs14.readFileSync(path18.join(assetsDir, file), "utf8");
5353
- const importRe = /from\s+["'](@inventive-ui\/[^"']+)["']/g;
5354
- let match;
5355
- while ((match = importRe.exec(content)) !== null) {
5356
- const moduleId = match[1];
5357
- const pkgName = moduleId.split("/").slice(0, 2).join("/");
5358
- const pkgRoot = resolvePackageDir(pkgName, cwd);
5359
- if (!pkgRoot) {
5360
- issues.push(`${file}: missing asset package ${pkgName}`);
5361
- continue;
5362
- }
5363
- const candidates = assetModuleCandidates(pkgRoot, moduleId);
5364
- if (!candidates.some((candidate) => fs14.existsSync(candidate))) {
5365
- issues.push(`${file}: missing asset module ${moduleId}`);
5366
- }
5367
- }
5368
- }
5369
- return issues;
5370
- }
5371
-
5372
- // src/services/slots.ts
5373
- var SLOT_GROUP_CORE_FILE = "slot-core.generated.tsx";
5374
- var SLOT_GROUP_OPTIONAL_FILE = "slot-optional.generated.tsx";
5375
- function bridgeSlotFilePath(cwd) {
5376
- return path19.join(cwd, "src", "iui", "slot.tsx");
5377
- }
5378
- function cleanupLegacySourceSlotFiles(cwd) {
5379
- const legacySlotsDir = path19.join(cwd, "src", "iui", "slots");
5380
- if (!fs15.existsSync(legacySlotsDir)) return;
5381
- try {
5382
- const files = fs15.readdirSync(legacySlotsDir);
5383
- for (const file of files) {
5384
- if (file.endsWith(".slot.tsx")) {
5385
- fs15.removeSync(path19.join(legacySlotsDir, file));
5386
- }
5387
- }
5388
- const remaining = fs15.readdirSync(legacySlotsDir);
5389
- if (remaining.length === 0) {
5390
- fs15.removeSync(legacySlotsDir);
5391
- }
5392
- } catch {
5393
- }
5394
- }
5395
- function loadSlotBootstrapPolicy(cwd) {
5396
- const policy = /* @__PURE__ */ new Map();
5397
- const contract = loadPublicSlotContract(cwd);
5398
- if (!contract) return policy;
5399
- for (const entry of contract.slots ?? []) {
5400
- if (!entry?.type || !entry.public) continue;
5401
- policy.set(entry.type, contractEntryToBootstrapPolicy(entry));
5402
- }
5403
- return policy;
5404
- }
5405
- function validateGeneratedSlotImports(cwd = process.cwd()) {
5406
- const components = readComponentManifest(cwd);
5407
- const pkgManifest = readComponentPackageManifest(cwd);
5408
- if (!pkgManifest) {
5409
- return ["@inventive-ui/components manifest is missing from node_modules."];
5410
- }
5411
- const itemsLookup = registryItemsMap(pkgManifest);
5412
- const installedItems = Object.keys(components).map((slug) => itemsLookup[slug]).filter((item) => Boolean(item));
5413
- const { issues } = collectInstalledSlotEmitters(
5414
- installedItems,
5415
- new Set(Object.keys(components)),
5416
- cwd
5417
- );
5418
- return issues.map((issue) => issue);
5419
- }
5420
- function renderGetComponentExpr(emitter, _slotPropsType = "unknown") {
5421
- const access = emitter.lazyAccess.replace(/^\./, "").trim();
5422
- const parts = access.split(".").filter(Boolean);
5423
- const compName = emitter.componentName;
5424
- if (parts.length === 0) {
5425
- assertJsIdentifier(compName, "component export");
5426
- return `resolveComponentExport(mod, ${JSON.stringify(compName)})`;
5427
- }
5428
- if (parts.length === 1) {
5429
- const name = parts[0] === "default" ? compName : parts[0];
5430
- assertJsIdentifier(name, "component export");
5431
- return `resolveComponentExport(mod, ${JSON.stringify(name)})`;
5432
- }
5433
- const [root, ...rest] = parts;
5434
- if (root !== "default") {
5435
- assertJsIdentifier(root, "component export");
5436
- }
5437
- for (const part of rest) {
5438
- assertJsIdentifier(part, "component export member");
5439
- }
5440
- const rootName = root === "default" ? compName : root;
5441
- if (rest.length === 1) {
5442
- return `resolveComponentExport(mod, ${JSON.stringify(rootName)}, ${JSON.stringify(rest[0])})`;
5443
- }
5444
- const rootExpr = `resolveComponentExport(mod, ${JSON.stringify(rootName)})`;
5445
- return `${rootExpr}?.${rest.join(".")}`;
5446
- }
5447
- function writeComponentSlotFiles(cwd = process.cwd()) {
5448
- const components = readComponentManifest(cwd);
5449
- const pkgManifest = readComponentPackageManifest(cwd);
5450
- const slotsDir = generatedSlotsDir(cwd);
5451
- const generationIssues = [];
5452
- cleanupLegacySourceSlotFiles(cwd);
5453
- if (Object.keys(components).length === 0) {
5454
- if (fs15.existsSync(slotsDir)) {
5455
- const existingSlots2 = fs15.readdirSync(slotsDir).filter((f) => f.endsWith(".slot.tsx"));
5456
- for (const file of existingSlots2) {
5457
- try {
5458
- fs15.removeSync(path19.join(slotsDir, file));
5459
- } catch {
5460
- }
5461
- }
5462
- }
5463
- return;
5464
- }
5465
- fs15.ensureDirSync(slotsDir);
5466
- if (!pkgManifest) return;
5467
- const itemsLookup = registryItemsMap(pkgManifest);
5468
- const installedItems = Object.entries(components).map(([slug]) => itemsLookup[slug]).filter((item) => Boolean(item));
5469
- const { emitters, issues: emitterIssues } = collectInstalledSlotEmitters(
5470
- installedItems,
5471
- new Set(Object.keys(components)),
5472
- cwd
5473
- );
5474
- generationIssues.push(...emitterIssues.map((issue) => `- ${issue}`));
5475
- const contract = loadPublicSlotContract(cwd);
5476
- if (contract) {
5477
- for (const entry of contract.slots ?? []) {
5478
- if (!entry.public) continue;
5479
- const prefetchError = validateSlotPrefetchPolicy(entry);
5480
- if (prefetchError) {
5481
- generationIssues.push(prefetchError);
5482
- }
5483
- }
5484
- }
5485
- const slotPolicy = loadSlotBootstrapPolicy(cwd);
5486
- const coreEmitters = [];
5487
- const optionalEmitters = [];
5488
- for (const emitter of emitters) {
5489
- assertComponentSlug(emitter.type);
5490
- assertJsIdentifier(emitter.componentName, "component export");
5491
- if (emitter.propsName !== "Props") assertJsIdentifier(emitter.propsName, "props type");
5492
- assertImportSpecifier(emitter.importSpecifier);
5493
- assertImportSpecifier(emitter.lazyImportSpecifier);
5494
- const policy = slotPolicy.get(emitter.type) ?? "optional";
5495
- if (policy === "core") coreEmitters.push(emitter);
5496
- else optionalEmitters.push(emitter);
5497
- }
5498
- const root = iuiProjectRoot2(cwd);
5499
- const renderedGroups = [
5500
- { fileName: SLOT_GROUP_CORE_FILE, emitters: coreEmitters },
5501
- { fileName: SLOT_GROUP_OPTIONAL_FILE, emitters: optionalEmitters }
5502
- ];
5503
- for (const group of renderedGroups) {
5504
- const outPath = resolveWithinRoot(root, ".iui", "generated", "slots", group.fileName);
5505
- if (group.emitters.length === 0) {
5506
- if (fs15.existsSync(outPath)) fs15.removeSync(outPath);
5507
- continue;
5508
- }
5509
- safeWriteFile(
5510
- outPath,
5511
- renderGroupedSlotFileContent(group.emitters, {
5512
- prefetch: group.fileName === SLOT_GROUP_CORE_FILE
5513
- })
5514
- );
5515
- }
5516
- const existingSlots = fs15.existsSync(slotsDir) ? fs15.readdirSync(slotsDir).filter((f) => f.endsWith(".slot.tsx") || f.endsWith(".generated.tsx")) : [];
5517
- for (const file of existingSlots) {
5518
- if (file === SLOT_GROUP_CORE_FILE || file === SLOT_GROUP_OPTIONAL_FILE) continue;
5519
- if (file.endsWith(".slot.tsx")) {
5520
- try {
5521
- fs15.removeSync(path19.join(slotsDir, file));
5522
- } catch {
5523
- }
5524
- continue;
5525
- }
5526
- if (file.endsWith(".generated.tsx")) {
5527
- try {
5528
- fs15.removeSync(path19.join(slotsDir, file));
5529
- } catch {
5530
- }
5531
- }
5532
- }
5533
- if (generationIssues.length > 0) {
5534
- throw new CLIError(
5535
- [
5536
- "Component public slot contract mismatch while generating slot files:",
5537
- ...generationIssues
5538
- ].join("\n"),
5539
- "Reinstall @inventive-ui/components and run iui doctor to repair the slot registry."
5540
- );
5541
- }
5542
- }
5543
- function renderGroupedSlotFileContent(emitters, options = {}) {
5544
- const needsComponentProps = emitters.some((emitter) => emitter.propsName === "Props");
5545
- const lines = [
5546
- "// Managed by iui. Do not edit manually.",
5547
- 'import React from "react";',
5548
- 'import { registerSlot, createEagerComponent, resolveComponentExport } from "@inventive-ui/framework/slots";'
5549
- ];
5550
- if (needsComponentProps) {
5551
- lines.push('import type { ComponentProps } from "react";');
5552
- }
5553
- lines.push("");
5554
- const imports = /* @__PURE__ */ new Set();
5555
- let idx = 0;
5556
- for (const emitter of emitters) {
5557
- idx += 1;
5558
- const alias = `Comp${idx}`;
5559
- if (emitter.propsName === "Props") {
5560
- imports.add(
5561
- `import type { ${emitter.componentName} as ${alias}Type } from "${emitter.importSpecifier}";`
5562
- );
5563
- } else {
5564
- imports.add(`import type { ${emitter.propsName} } from "${emitter.importSpecifier}";`);
5565
- }
5566
- }
5567
- lines.push(...[...imports].sort(), "");
5568
- idx = 0;
5569
- for (const emitter of emitters) {
5570
- idx += 1;
5571
- const alias = `Comp${idx}`;
5572
- const slotType = emitter.propsName === "Props" ? `ComponentProps<typeof ${alias}Type>` : emitter.propsName;
5573
- lines.push(`type ${alias}Slot = { type: "${emitter.type}" } & Omit<${slotType}, "type">;`);
5574
- lines.push(`type ${alias}SlotProps = Omit<${alias}Slot, "type">;`);
5575
- }
5576
- lines.push("", 'declare module "@inventive-ui/framework/slots" {', " interface SlotMap {");
5577
- idx = 0;
5578
- for (const emitter of emitters) {
5579
- idx += 1;
5580
- lines.push(` "${emitter.type}": Comp${idx}Slot;`);
5581
- }
5582
- lines.push(" }", "}", "");
5583
- idx = 0;
5584
- for (const emitter of emitters) {
5585
- idx += 1;
5586
- const alias = `Comp${idx}`;
5587
- const renderer = `${alias}Renderer`;
5588
- lines.push(`const ${renderer} = createEagerComponent<${alias}SlotProps>(`);
5589
- lines.push(` () => import(${escapeTsStringLiteral(emitter.lazyImportSpecifier)}),`);
5590
- lines.push(` (mod) => ${renderGetComponentExpr(emitter, `${alias}SlotProps`)} as React.ComponentType<${alias}SlotProps>,`);
5591
- if (options.prefetch) {
5592
- lines.push(" { prefetch: true },");
5593
- }
5594
- lines.push(");", "");
5595
- lines.push(`registerSlot(${escapeTsStringLiteral(emitter.type)}, (slot) => {`);
5596
- lines.push(" const { type, ...props } = slot;");
5597
- lines.push(` return <${renderer} {...props} />;`);
5598
- lines.push("});", "");
5599
- }
5600
- return `${lines.join("\n")}
5601
- `;
5602
- }
5603
- function writeSlotHelperFile(cwd = process.cwd()) {
5604
- const manifest = readSlotManifest(cwd);
5605
- const components = readComponentManifest(cwd);
5606
- const pkgManifest = readComponentPackageManifest(cwd);
5607
- const slotTypes = /* @__PURE__ */ new Set();
5608
- for (const record of Object.values(manifest)) {
5609
- if (record.slotType && record.slotType !== "component") {
5610
- slotTypes.add(record.slotType);
5611
- }
5612
- if (Array.isArray(record.supportedSlots)) {
5613
- for (const t of record.supportedSlots) slotTypes.add(t);
5614
- }
5615
- }
5616
- let emitterSlotTypes = [];
5617
- if (pkgManifest) {
5618
- const itemsLookup = registryItemsMap(pkgManifest);
5619
- const installedItems = Object.keys(components).map((slug) => itemsLookup[slug]).filter((item) => Boolean(item));
5620
- const { emitters } = collectInstalledSlotEmitters(
5621
- installedItems,
5622
- new Set(Object.keys(components)),
5623
- cwd
5624
- );
5625
- emitterSlotTypes = emitters.map((emitter) => emitter.type);
5626
- for (const type of emitterSlotTypes) slotTypes.add(type);
5627
- } else {
5628
- for (const slug of Object.keys(components)) slotTypes.add(slug);
5629
- }
5630
- const typesArray = Array.from(slotTypes).sort();
5631
- const slotImports = [];
5632
- const coreSlotsPath = path19.join(generatedSlotsDir(cwd), SLOT_GROUP_CORE_FILE);
5633
- const optionalSlotsPath = path19.join(generatedSlotsDir(cwd), SLOT_GROUP_OPTIONAL_FILE);
5634
- if (fs15.existsSync(coreSlotsPath)) slotImports.push(`import "./slots/${SLOT_GROUP_CORE_FILE.replace(/\.tsx$/, "")}";`);
5635
- if (fs15.existsSync(optionalSlotsPath)) slotImports.push(`import "./slots/${SLOT_GROUP_OPTIONAL_FILE.replace(/\.tsx$/, "")}";`);
5636
- const componentSlotImports = slotImports.join("\n");
5637
- const includeAssetBindings = hasAssetBoundRegistration(cwd);
5638
- const outDir = generatedIuiDir(cwd);
5639
- fs15.ensureDirSync(outDir);
5640
- const outPath = path19.join(outDir, "slot.generated.tsx");
5641
- const sections = [
5642
- `// Managed by iui. Do not edit manually.`,
5643
- `// Rebuilt automatically when the CLI validates the project.`
5644
- ];
5645
- if (includeAssetBindings) {
5646
- sections.push("");
5647
- sections.push("// Scanned asset bindings (static glyph imports)");
5648
- sections.push(`import "./assets/register-bound";`);
5649
- }
5650
- if (componentSlotImports) {
5651
- sections.push("");
5652
- sections.push("// Component slot registrations");
5653
- sections.push(componentSlotImports);
5654
- }
5655
- sections.push("");
5656
- sections.push(`// Framework slot system \u2014 flag, icon, loader, etc. registrations run as side effects`);
5657
- sections.push(`// when @inventive-ui/framework is first imported. No explicit registration needed here.`);
5658
- sections.push(`import { SlotRenderer, useSlotRenderer } from "@inventive-ui/framework/slots";`);
5659
- sections.push(`import slotManifest from "../slots.json";`);
5660
- sections.push("");
5661
- sections.push(
5662
- typesArray.length > 0 ? `export type IUISlotType =
5663
- ${typesArray.map((t) => ` | "${t}"`).join("\n")};` : `export type IUISlotType = never;`
5664
- );
5665
- sections.push("");
5666
- sections.push(`export { SlotRenderer, useSlotRenderer };`);
5667
- sections.push("");
5668
- sections.push(`export const slots = slotManifest;`);
5669
- sections.push("");
5670
- const content = sections.join("\n");
5671
- safeWriteFile(outPath, content);
5672
- }
5673
- function writeSlotBridge(packageDir, iuiRoot2) {
5674
- const bridgePath = bridgeSlotFilePath(packageDir);
5675
- const generatedFile = path19.join(iuiRoot2, ".iui", "generated", "slot.generated.tsx");
5676
- const importBase = relativeImportPath(path19.dirname(bridgePath), generatedFile);
5677
- fs15.ensureDirSync(path19.dirname(bridgePath));
5678
- if (fs15.existsSync(bridgePath)) {
5679
- const existing = fs15.readFileSync(bridgePath, "utf-8");
5680
- if (existing.length > 0 && !/@iui-managed/.test(existing)) {
5681
- return;
5682
- }
5683
- }
5684
- const bridgeContent = `// Managed by iui. Do not edit manually.
5685
- // @iui-managed
5686
- // Compatibility bridge: keep project imports stable at src/iui/slot.tsx.
5687
-
5688
- export { SlotRenderer, useSlotRenderer, slots } from "${importBase}";
5689
- export type { IUISlotType } from "${importBase}";
5690
- `;
5691
- safeWriteFile(bridgePath, bridgeContent);
5692
- cleanupLegacySourceSlotFiles(packageDir);
5693
- }
5694
-
5695
- // src/services/workspace-bootstrap.ts
5696
- import path21 from "path";
5697
- import fs17 from "fs-extra";
5698
-
5699
4959
  // src/services/bootstrap.ts
5700
- import fs16 from "fs-extra";
5701
- import path20 from "path";
5702
4960
  var BOOTSTRAP_GENERATED_FILE = "bootstrap.generated.tsx";
5703
4961
  function bridgeBootstrapFilePath(cwd) {
5704
- return path20.join(cwd, "src", "iui", "bootstrap.ts");
4962
+ return path18.join(cwd, "src", "iui", "bootstrap.ts");
5705
4963
  }
5706
4964
  function bootstrapGeneratedPath(cwd = process.cwd()) {
5707
- return path20.join(generatedIuiDir(cwd), BOOTSTRAP_GENERATED_FILE);
4965
+ return path18.join(generatedIuiDir(cwd), BOOTSTRAP_GENERATED_FILE);
5708
4966
  }
5709
4967
  function resolveProjectConfigPaths(cwd) {
5710
4968
  const meta = readProjectMeta(cwd);
@@ -5719,8 +4977,8 @@ function resolveProjectConfigPaths(cwd) {
5719
4977
  };
5720
4978
  }
5721
4979
  function configImportFromGenerated(cwd, configRel) {
5722
- const generatedDir = path20.dirname(bootstrapGeneratedPath(cwd));
5723
- const abs = path20.resolve(cwd, configRel.replace(/^\.\//, ""));
4980
+ const generatedDir = path18.dirname(bootstrapGeneratedPath(cwd));
4981
+ const abs = path18.resolve(cwd, configRel.replace(/^\.\//, ""));
5724
4982
  return relativeImportPath(generatedDir, abs);
5725
4983
  }
5726
4984
  function expectedBootstrapImportPaths(cwd) {
@@ -5733,13 +4991,13 @@ function expectedBootstrapImportPaths(cwd) {
5733
4991
  }
5734
4992
  function writeBootstrapGenerated(cwd = process.cwd()) {
5735
4993
  const outPath = bootstrapGeneratedPath(cwd);
5736
- fs16.ensureDirSync(path20.dirname(outPath));
4994
+ fs14.ensureDirSync(path18.dirname(outPath));
5737
4995
  const imports = expectedBootstrapImportPaths(cwd);
5738
4996
  const content = `// @iui-managed
5739
4997
 
5740
4998
  // Generated by iui CLI \u2014 do not edit manually.
5741
4999
 
5742
- // Connects iui.config.ts + assets.config.json + component.config.ts for standard bootstrap.
5000
+ // Connects theme.config.ts + assets.config.json + component.config.ts for standard bootstrap.
5743
5001
 
5744
5002
 
5745
5003
 
@@ -5759,16 +5017,12 @@ import {
5759
5017
 
5760
5018
  } from "@inventive-ui/framework";
5761
5019
 
5762
- import { initConfig as initSlotsConfig } from "@inventive-ui/framework/slots";
5020
+ import { initConfig as initAssetsConfig } from "@inventive-ui/framework/assets";
5763
5021
 
5764
5022
  import type { IUIAssetsConfig } from "@inventive-ui/framework/config";
5765
5023
 
5766
5024
 
5767
5025
 
5768
- import "./slot.generated";
5769
-
5770
-
5771
-
5772
5026
  const themeConfig = (theme as { default?: typeof theme }).default ?? theme;
5773
5027
 
5774
5028
 
@@ -5795,7 +5049,7 @@ registerBootstrapState({
5795
5049
 
5796
5050
  initFramework(frameworkConfig);
5797
5051
 
5798
- initSlotsConfig(frameworkConfig);
5052
+ initAssetsConfig(frameworkConfig);
5799
5053
 
5800
5054
 
5801
5055
 
@@ -5807,10 +5061,10 @@ export { projectComponentConfig as componentConfig };
5807
5061
  function writeBootstrapBridge(packageDir, iuiRoot2) {
5808
5062
  const bridgePath = bridgeBootstrapFilePath(packageDir);
5809
5063
  const generatedFile = bootstrapGeneratedPath(iuiRoot2);
5810
- const importBase = relativeImportPath(path20.dirname(bridgePath), generatedFile);
5811
- fs16.ensureDirSync(path20.dirname(bridgePath));
5812
- if (fs16.existsSync(bridgePath)) {
5813
- const existing = fs16.readFileSync(bridgePath, "utf-8");
5064
+ const importBase = relativeImportPath(path18.dirname(bridgePath), generatedFile);
5065
+ fs14.ensureDirSync(path18.dirname(bridgePath));
5066
+ if (fs14.existsSync(bridgePath)) {
5067
+ const existing = fs14.readFileSync(bridgePath, "utf-8");
5814
5068
  if (existing.length > 0 && !/@iui-managed/.test(existing)) {
5815
5069
  return;
5816
5070
  }
@@ -5831,17 +5085,18 @@ import "${importBase}";
5831
5085
  function writeProjectBootstrapArtifacts(packageDir, iuiRoot2) {
5832
5086
  writeBootstrapGenerated(iuiRoot2);
5833
5087
  writeBootstrapBridge(packageDir, iuiRoot2);
5088
+ removeStaleComponentSlotOutput(iuiRoot2, [packageDir]);
5834
5089
  }
5835
5090
 
5836
5091
  // src/services/workspace-bootstrap.ts
5837
5092
  function workspaceManifestPath(iuiRoot2) {
5838
- return path21.join(iuiRoot2, IUI_DIR, "workspace.json");
5093
+ return path19.join(iuiRoot2, IUI_DIR, "workspace.json");
5839
5094
  }
5840
5095
  function readWorkspaceManifest(iuiRoot2) {
5841
5096
  const p = workspaceManifestPath(iuiRoot2);
5842
- if (!fs17.existsSync(p)) return null;
5097
+ if (!fs15.existsSync(p)) return null;
5843
5098
  try {
5844
- const raw = fs17.readJsonSync(p);
5099
+ const raw = fs15.readJsonSync(p);
5845
5100
  if (!Array.isArray(raw.packages)) return null;
5846
5101
  return {
5847
5102
  iuiRoot: raw.iuiRoot ?? iuiRoot2,
@@ -5853,40 +5108,45 @@ function readWorkspaceManifest(iuiRoot2) {
5853
5108
  }
5854
5109
  }
5855
5110
  function writeWorkspaceManifest(iuiRoot2, packageDirs) {
5856
- const unique = [...new Set(packageDirs.map((dir) => path21.resolve(dir)))];
5111
+ const unique = [...new Set(packageDirs.map((dir) => path19.resolve(dir)))];
5857
5112
  atomicWriteJson(workspaceManifestPath(iuiRoot2), {
5858
- packages: unique.map((dir) => path21.relative(iuiRoot2, dir) || "."),
5113
+ packages: unique.map((dir) => path19.relative(iuiRoot2, dir) || "."),
5859
5114
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
5860
5115
  });
5861
5116
  }
5862
5117
  function resolveRegisteredPackageDirs(iuiRoot2) {
5863
- const resolvedRoot = path21.resolve(iuiRoot2);
5118
+ const resolvedRoot = path19.resolve(iuiRoot2);
5864
5119
  const manifest = readWorkspaceManifest(resolvedRoot);
5865
5120
  if (!manifest) return [resolvedRoot];
5866
5121
  const dirs = manifest.packages.map(
5867
- (rel) => path21.resolve(resolvedRoot, rel === "." ? "" : rel)
5122
+ (rel) => path19.resolve(resolvedRoot, rel === "." ? "" : rel)
5868
5123
  );
5869
- if (!dirs.some((dir) => path21.resolve(dir) === resolvedRoot)) {
5124
+ if (!dirs.some((dir) => path19.resolve(dir) === resolvedRoot)) {
5870
5125
  dirs.unshift(resolvedRoot);
5871
5126
  }
5872
5127
  return dirs;
5873
5128
  }
5129
+ function registeredPackageDirs(iuiRoot2) {
5130
+ return resolveRegisteredPackageDirs(resolveIuiProjectRoot(iuiRoot2)).filter(
5131
+ (dir) => fs15.existsSync(path19.join(dir, "package.json"))
5132
+ );
5133
+ }
5874
5134
  function registerWorkspacePackage(iuiRoot2, packageDir) {
5875
- const resolvedRoot = path21.resolve(iuiRoot2);
5876
- const resolvedPackage = path21.resolve(packageDir);
5135
+ const resolvedRoot = path19.resolve(iuiRoot2);
5136
+ const resolvedPackage = path19.resolve(packageDir);
5877
5137
  const existing = resolveRegisteredPackageDirs(resolvedRoot);
5878
- if (!existing.some((dir) => path21.resolve(dir) === resolvedPackage)) {
5138
+ if (!existing.some((dir) => path19.resolve(dir) === resolvedPackage)) {
5879
5139
  existing.push(resolvedPackage);
5880
5140
  }
5881
5141
  writeWorkspaceManifest(resolvedRoot, existing);
5882
5142
  }
5883
5143
  function registerAllWorkspacePackages(iuiRoot2) {
5884
- const resolvedRoot = path21.resolve(iuiRoot2);
5144
+ const resolvedRoot = path19.resolve(iuiRoot2);
5885
5145
  const workspaceRoot = findWorkspaceRoot(resolvedRoot);
5886
5146
  const targets = /* @__PURE__ */ new Set([resolvedRoot]);
5887
5147
  if (workspaceRoot) {
5888
5148
  for (const pkgDir of listWorkspacePackageDirs(workspaceRoot)) {
5889
- targets.add(path21.resolve(pkgDir));
5149
+ targets.add(path19.resolve(pkgDir));
5890
5150
  }
5891
5151
  }
5892
5152
  const dirs = [...targets];
@@ -5897,18 +5157,17 @@ function bootstrapRegisteredPackages(iuiRoot2) {
5897
5157
  const resolvedRoot = resolveIuiProjectRoot(iuiRoot2);
5898
5158
  const bootstrapped = [];
5899
5159
  for (const packageDir of resolveRegisteredPackageDirs(resolvedRoot)) {
5900
- if (!fs17.existsSync(path21.join(packageDir, "package.json"))) continue;
5160
+ if (!fs15.existsSync(path19.join(packageDir, "package.json"))) continue;
5901
5161
  ensureProjectNpmrc(packageDir);
5902
- writeSlotBridge(packageDir, resolvedRoot);
5903
5162
  writeProjectBootstrapArtifacts(packageDir, resolvedRoot);
5904
5163
  bootstrapped.push(packageDir);
5905
5164
  }
5906
5165
  return bootstrapped;
5907
5166
  }
5908
5167
  async function bootstrapWorkspacePackage(packageDir, iuiRoot2) {
5909
- const resolvedPackage = path21.resolve(packageDir);
5168
+ const resolvedPackage = path19.resolve(packageDir);
5910
5169
  const resolvedIuiRoot = resolveIuiProjectRoot(iuiRoot2);
5911
- if (!fs17.existsSync(path21.join(resolvedPackage, "package.json"))) {
5170
+ if (!fs15.existsSync(path19.join(resolvedPackage, "package.json"))) {
5912
5171
  throw new CLIError(
5913
5172
  `No package.json found in ${resolvedPackage}.`,
5914
5173
  "Run iui init from a workspace app directory that contains package.json."
@@ -5921,7 +5180,7 @@ async function bootstrapWorkspacePackage(packageDir, iuiRoot2) {
5921
5180
  }
5922
5181
  registerWorkspacePackage(resolvedIuiRoot, resolvedPackage);
5923
5182
  bootstrapRegisteredPackages(resolvedIuiRoot);
5924
- ok("Slot bridge ready");
5183
+ ok("Bootstrap bridge ready");
5925
5184
  hint(
5926
5185
  "This app is linked to an existing IUI setup \u2014 packages and configs stay at the IUI root."
5927
5186
  );
@@ -5933,28 +5192,28 @@ async function bootstrapWorkspacePackage(packageDir, iuiRoot2) {
5933
5192
  }
5934
5193
 
5935
5194
  // src/services/slot-registry.ts
5936
- var STATE_SCHEMA_VERSION = 1;
5195
+ var STATE_SCHEMA_VERSION = 2;
5937
5196
  function statePath(cwd) {
5938
5197
  return iuiCacheFile(cwd, "slotState");
5939
5198
  }
5940
5199
  function now() {
5941
5200
  return (/* @__PURE__ */ new Date()).toISOString();
5942
5201
  }
5943
- function checksumFor(components, slots) {
5944
- return sha256(JSON.stringify({ components, slots }));
5202
+ function checksumFor(components, packages) {
5203
+ return sha256(JSON.stringify({ components, packages }));
5945
5204
  }
5946
5205
  function backupCorruptFile(filePath) {
5947
- if (!fs18.existsSync(filePath)) return;
5206
+ if (!fs16.existsSync(filePath)) return;
5948
5207
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
5949
5208
  try {
5950
- fs18.moveSync(filePath, `${filePath}.corrupt-${stamp}`, { overwrite: false });
5209
+ fs16.moveSync(filePath, `${filePath}.corrupt-${stamp}`, { overwrite: false });
5951
5210
  } catch {
5952
5211
  }
5953
5212
  }
5954
5213
  function readJsonObject(filePath, fallback, issues, label) {
5955
- if (!fs18.existsSync(filePath)) return fallback;
5214
+ if (!fs16.existsSync(filePath)) return fallback;
5956
5215
  try {
5957
- const value = fs18.readJsonSync(filePath);
5216
+ const value = fs16.readJsonSync(filePath);
5958
5217
  if (value && typeof value === "object" && !Array.isArray(value)) {
5959
5218
  return value;
5960
5219
  }
@@ -5966,9 +5225,9 @@ function readJsonObject(filePath, fallback, issues, label) {
5966
5225
  }
5967
5226
  function readState(cwd, issues) {
5968
5227
  const filePath = statePath(cwd);
5969
- if (!fs18.existsSync(filePath)) return null;
5228
+ if (!fs16.existsSync(filePath)) return null;
5970
5229
  try {
5971
- const raw = fs18.readJsonSync(filePath);
5230
+ const raw = fs16.readJsonSync(filePath);
5972
5231
  if (raw.schemaVersion !== STATE_SCHEMA_VERSION) {
5973
5232
  issues.push("registration state schema was upgraded");
5974
5233
  return null;
@@ -5997,37 +5256,15 @@ function updateState(cwd, state, phase, patch = {}) {
5997
5256
  writeState(cwd, next);
5998
5257
  return next;
5999
5258
  }
6000
- function buildDesiredState(registry, packageVersion, currentSlots, packages) {
5259
+ function buildDesiredComponents(registry, packageVersion) {
6001
5260
  const components = {};
6002
- const slots = {};
6003
- const timestamp = now();
6004
5261
  for (const item of registry.items) {
6005
5262
  components[item.name] = packageVersion;
6006
- slots[item.name] = {
6007
- component: item.name,
6008
- slotType: "component",
6009
- registeredAt: currentSlots[item.name]?.registeredAt ?? timestamp,
6010
- version: packageVersion
6011
- };
6012
- if (item.slots.length > 0) {
6013
- slots[item.name].supportedSlots = [...item.slots].sort();
6014
- }
6015
- }
6016
- for (const [packageId, meta] of Object.entries(packages)) {
6017
- const def = ASSET_PACKAGES_MAP[packageId];
6018
- if (!def) continue;
6019
- const key = `asset:${packageId}`;
6020
- slots[key] = {
6021
- component: packageId,
6022
- slotType: def.slotType,
6023
- registeredAt: currentSlots[key]?.registeredAt ?? timestamp,
6024
- version: meta.version
6025
- };
6026
5263
  }
6027
- return { components, slots };
5264
+ return components;
6028
5265
  }
6029
- function hasManifestDrift(currentComponents, currentSlots, desiredComponents, desiredSlots) {
6030
- return JSON.stringify(currentComponents) !== JSON.stringify(desiredComponents) || JSON.stringify(currentSlots) !== JSON.stringify(desiredSlots);
5266
+ function hasManifestDrift(currentComponents, desiredComponents) {
5267
+ return JSON.stringify(currentComponents) !== JSON.stringify(desiredComponents);
6031
5268
  }
6032
5269
  function shouldSkipWritesFastPath(params) {
6033
5270
  const {
@@ -6072,7 +5309,7 @@ async function ensureSlotRegistry(options = {}) {
6072
5309
  }
6073
5310
  const iuiRoot2 = resolveIuiProjectRoot(cwd);
6074
5311
  return withRegistryLock(iuiRoot2, async () => {
6075
- const iuiPath = path22.join(iuiRoot2, IUI_DIR);
5312
+ const iuiPath = path20.join(iuiRoot2, IUI_DIR);
6076
5313
  const issues = [];
6077
5314
  cleanupTempFiles(iuiPath);
6078
5315
  const registry = ensureInstalledManifest(
@@ -6098,37 +5335,25 @@ async function ensureSlotRegistry(options = {}) {
6098
5335
  issues,
6099
5336
  ".iui/packages.json"
6100
5337
  );
6101
- const currentSlots = readJsonObject(
6102
- slotManifestPath(iuiRoot2),
6103
- {},
6104
- issues,
6105
- ".iui/slots.json"
6106
- );
6107
- const desired = buildDesiredState(
6108
- registry,
6109
- packageVersion,
6110
- currentSlots,
6111
- currentPackages
6112
- );
6113
- const checksum = checksumFor(desired.components, desired.slots);
5338
+ const desiredComponents = buildDesiredComponents(registry, packageVersion);
5339
+ const checksum = checksumFor(desiredComponents, currentPackages);
6114
5340
  if (previousState?.status === "running" || previousState?.status === "failed") {
6115
5341
  issues.push("interrupted registration was resumed");
6116
5342
  }
6117
5343
  if (previousState?.checksum && previousState.checksum !== checksum) {
6118
- issues.push("slot registry checksum changed");
5344
+ issues.push("registry checksum changed");
6119
5345
  }
6120
- const driftDetected = hasManifestDrift(
6121
- currentComponents,
6122
- currentSlots,
6123
- desired.components,
6124
- desired.slots
6125
- );
5346
+ const driftDetected = hasManifestDrift(currentComponents, desiredComponents);
6126
5347
  if (driftDetected) {
6127
- issues.push("slot manifests drifted");
5348
+ issues.push("component manifest drifted");
6128
5349
  }
6129
- const generationIssues = validateGeneratedSlotImports(iuiRoot2);
6130
- const assetBoundIssues = validateGeneratedAssetBoundImports(iuiRoot2);
6131
- const integrityIssues = [...generationIssues, ...assetBoundIssues];
5350
+ const staleSlotOutput = findStaleComponentSlotOutput(
5351
+ iuiRoot2,
5352
+ registeredPackageDirs(iuiRoot2)
5353
+ );
5354
+ const integrityIssues = staleSlotOutput.map(
5355
+ (file) => `stale component-slot output: ${path20.relative(iuiRoot2, file) || file}`
5356
+ );
6132
5357
  if (shouldSkipWritesFastPath({
6133
5358
  mode,
6134
5359
  previousState,
@@ -6146,8 +5371,8 @@ async function ensureSlotRegistry(options = {}) {
6146
5371
  if (mode === "validate") {
6147
5372
  if (integrityIssues.length > 0) {
6148
5373
  throw new CLIError(
6149
- "Slot registry integrity check failed.",
6150
- integrityIssues.map((issue) => `- ${issue}`).join("\n")
5374
+ "Stale component-slot files from an older iui version were found.",
5375
+ "Run iui doctor --fix (or iui update) to regenerate .iui/generated and remove them."
6151
5376
  );
6152
5377
  }
6153
5378
  return {
@@ -6170,32 +5395,32 @@ async function ensureSlotRegistry(options = {}) {
6170
5395
  writeState(iuiRoot2, state);
6171
5396
  updateState(iuiRoot2, state, "state-loaded");
6172
5397
  await retry(() => {
6173
- writeComponentManifest(desired.components, iuiRoot2);
5398
+ writeComponentManifest(desiredComponents, iuiRoot2);
6174
5399
  writePackageManifest(currentPackages, iuiRoot2);
6175
- writeSlotManifest(desired.slots, iuiRoot2);
6176
5400
  });
6177
5401
  let next = updateState(iuiRoot2, state, "manifests-written", {
6178
5402
  checksum,
6179
5403
  repairedIssues: issues
6180
5404
  });
6181
5405
  await retry(async () => {
6182
- writeComponentSlotFiles(iuiRoot2);
6183
5406
  writeAssetsConfig(iuiRoot2);
6184
5407
  ensureProjectConfig(iuiRoot2);
6185
- await writeAssetBoundFiles(iuiRoot2);
6186
- writeSlotHelperFile(iuiRoot2);
6187
5408
  if (projectHasViteTooling(cwd)) {
6188
5409
  ensureInventiveUiViteConfig(cwd);
6189
5410
  }
6190
5411
  });
6191
5412
  bootstrapRegisteredPackages(iuiRoot2);
6192
- next = updateState(iuiRoot2, next, "slot-files-written", { repairedIssues: issues });
6193
- if (integrityIssues.length > 0) {
5413
+ next = updateState(iuiRoot2, next, "generated-files-written", { repairedIssues: issues });
5414
+ const leftover = findStaleComponentSlotOutput(iuiRoot2, registeredPackageDirs(iuiRoot2));
5415
+ if (leftover.length > 0) {
6194
5416
  throw new CLIError(
6195
- "Slot registry integrity check failed.",
6196
- integrityIssues.map((issue) => `- ${issue}`).join("\n")
5417
+ "Could not remove stale component-slot output.",
5418
+ leftover.map((file) => `- ${path20.relative(iuiRoot2, file) || file}`).join("\n")
6197
5419
  );
6198
5420
  }
5421
+ if (integrityIssues.length > 0) {
5422
+ issues.push(...integrityIssues.map((issue) => `removed ${issue}`));
5423
+ }
6199
5424
  next = updateState(iuiRoot2, next, "integrity-verified", { repairedIssues: issues });
6200
5425
  updateState(iuiRoot2, next, "complete", {
6201
5426
  status: "complete",
@@ -6204,7 +5429,7 @@ async function ensureSlotRegistry(options = {}) {
6204
5429
  repairedIssues: issues
6205
5430
  });
6206
5431
  if (!options.quiet && issues.length > 0) {
6207
- ok("Slot registry repaired");
5432
+ ok("Project registry repaired");
6208
5433
  }
6209
5434
  return {
6210
5435
  status: issues.length > 0 ? "repaired" : "valid",
@@ -6212,7 +5437,7 @@ async function ensureSlotRegistry(options = {}) {
6212
5437
  repairedIssues: issues
6213
5438
  };
6214
5439
  } catch (error) {
6215
- const message = error instanceof Error ? error.message : "Slot registry update failed";
5440
+ const message = error instanceof Error ? error.message : "Project registry update failed";
6216
5441
  if (state) {
6217
5442
  updateState(iuiRoot2, state, "state-loaded", {
6218
5443
  status: "failed",
@@ -6286,15 +5511,15 @@ async function installComponentsPackage(opts) {
6286
5511
  mode: "repair"
6287
5512
  });
6288
5513
  if (result.status === "skipped") {
6289
- warn("Component slot registry was not generated.");
5514
+ warn("Component registry was not generated.");
6290
5515
  hint(
6291
5516
  "Run iui init in this package (or iui doctor). Hoisted node_modules are supported \u2014 a root-level install is not required."
6292
5517
  );
6293
5518
  } else {
6294
5519
  ok(
6295
- result.status === "repaired" ? `Component slots repaired for ${COMPONENTS_PACKAGE} ${dim(`v${pkgVersion}`)}` : `Component slots ready for ${COMPONENTS_PACKAGE} ${dim(`v${pkgVersion}`)}`
5520
+ result.status === "repaired" ? `Components registry repaired for ${COMPONENTS_PACKAGE} ${dim(`v${pkgVersion}`)}` : `Components ready for ${COMPONENTS_PACKAGE} ${dim(`v${pkgVersion}`)}`
6296
5521
  );
6297
- hint('Import components from "@inventive-ui/components"; slots are available automatically.');
5522
+ hint('Import components from "@inventive-ui/components".');
6298
5523
  }
6299
5524
  return { previousVersion, version: pkgVersion };
6300
5525
  }
@@ -6367,7 +5592,7 @@ async function initCommand(opts) {
6367
5592
  try {
6368
5593
  heading("Initialize Project");
6369
5594
  const existingIuiRoot = findIuiProjectRoot(invocationCwd);
6370
- if (existingIuiRoot && path23.resolve(existingIuiRoot) !== path23.resolve(invocationCwd)) {
5595
+ if (existingIuiRoot && path21.resolve(existingIuiRoot) !== path21.resolve(invocationCwd)) {
6371
5596
  await bootstrapWorkspacePackage(invocationCwd, existingIuiRoot);
6372
5597
  return;
6373
5598
  }
@@ -6386,10 +5611,10 @@ async function initCommand(opts) {
6386
5611
  return;
6387
5612
  }
6388
5613
  const originalCwd = process.cwd();
6389
- if (path23.resolve(initRoot) !== path23.resolve(originalCwd)) {
5614
+ if (path21.resolve(initRoot) !== path21.resolve(originalCwd)) {
6390
5615
  process.chdir(initRoot);
6391
5616
  hint(
6392
- `Monorepo --workspace: initializing at ${path23.relative(invocationCwd, initRoot) || initRoot}`
5617
+ `Monorepo --workspace: initializing at ${path21.relative(invocationCwd, initRoot) || initRoot}`
6393
5618
  );
6394
5619
  } else if (!sharedWorkspace && findIuiProjectRoot(initRoot) === null) {
6395
5620
  hint("Initializing this package only \u2014 other monorepo apps are untouched.");
@@ -6450,7 +5675,7 @@ async function initCommand(opts) {
6450
5675
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
6451
5676
  initScope: sharedWorkspace ? "workspace" : "package",
6452
5677
  configs: {
6453
- theme: "./iui.config.ts",
5678
+ theme: "./theme.config.ts",
6454
5679
  assets: "./assets.config.json",
6455
5680
  components: "./component.config.ts"
6456
5681
  }
@@ -6514,12 +5739,12 @@ async function initCommand(opts) {
6514
5739
  ensureTsConfigForIui(framework.framework, initRoot);
6515
5740
  if (framework.framework === "vite") {
6516
5741
  ensureInventiveUiViteConfig(initRoot);
6517
- ok("Config files ready (iui.config.ts, tsconfig.json, tsconfig.node.json, vite.config.ts)");
5742
+ ok("Config files ready (theme.config.ts, tsconfig.json, tsconfig.node.json, vite.config.ts)");
6518
5743
  } else {
6519
5744
  if (removeStaleIuiViteConfig(initRoot)) {
6520
5745
  hint("Removed vite.config.ts (React-only preset \u2014 no Vite tooling required).");
6521
5746
  }
6522
- ok("Config files ready (iui.config.ts, tsconfig.json)");
5747
+ ok("Config files ready (theme.config.ts, tsconfig.json)");
6523
5748
  }
6524
5749
  step("Scaffolding component.config.ts\u2026");
6525
5750
  const fetchedRegistry = await fetchComponentRegistry(auth.token);
@@ -7272,17 +6497,17 @@ async function deployTokenRevokeCommand(tokenId) {
7272
6497
  }
7273
6498
 
7274
6499
  // src/commands/setup.ts
7275
- import path26 from "path";
7276
- import fs20 from "fs-extra";
6500
+ import path24 from "path";
6501
+ import fs18 from "fs-extra";
7277
6502
  import ora6 from "ora";
7278
6503
 
7279
6504
  // src/commands/doctor.ts
7280
- import path25 from "path";
6505
+ import path23 from "path";
7281
6506
 
7282
6507
  // src/services/health.ts
7283
6508
  import { execFileSync as execFileSync2 } from "child_process";
7284
- import path24 from "path";
7285
- import fs19 from "fs-extra";
6509
+ import path22 from "path";
6510
+ import fs17 from "fs-extra";
7286
6511
  function installDevTypeScript(cwd) {
7287
6512
  const pm = detectPackageManager(cwd);
7288
6513
  try {
@@ -7310,23 +6535,24 @@ function checkPackageCompatibility(cwd = process.cwd()) {
7310
6535
  summary: `Core packages installed (framework ${frameworkVersion}, components ${componentsVersion})`
7311
6536
  };
7312
6537
  }
7313
- function checkGeneratedSlotValidity(cwd = process.cwd()) {
7314
- const issues = validateGeneratedSlotImports(cwd);
7315
- if (issues.length > 0) {
6538
+ function checkStaleComponentSlotOutput(cwd = process.cwd()) {
6539
+ const iuiRoot2 = resolveIuiProjectRoot(cwd);
6540
+ const stale = findStaleComponentSlotOutput(iuiRoot2, [cwd]);
6541
+ if (stale.length > 0) {
7316
6542
  return {
7317
6543
  ok: false,
7318
- summary: "Managed slot imports are invalid",
7319
- details: issues.map((i) => `- ${i}`).join("\n")
6544
+ summary: `${stale.length} stale component-slot file${stale.length === 1 ? "" : "s"} from an older iui version`,
6545
+ details: stale.slice(0, 8).map((file) => `- ${path22.relative(iuiRoot2, file) || file}`).join("\n")
7320
6546
  };
7321
6547
  }
7322
6548
  return {
7323
6549
  ok: true,
7324
- summary: "Managed slot imports are valid"
6550
+ summary: "No stale component-slot output"
7325
6551
  };
7326
6552
  }
7327
6553
  function checkComponentConfigValidity(cwd = process.cwd(), options = {}) {
7328
- const configPath = path24.join(cwd, COMPONENT_CONFIG_FILE);
7329
- if (!fs19.existsSync(configPath)) {
6554
+ const configPath = path22.join(cwd, COMPONENT_CONFIG_FILE);
6555
+ if (!fs17.existsSync(configPath)) {
7330
6556
  return {
7331
6557
  ok: false,
7332
6558
  summary: "component.config.ts not found",
@@ -7334,8 +6560,8 @@ function checkComponentConfigValidity(cwd = process.cwd(), options = {}) {
7334
6560
  };
7335
6561
  }
7336
6562
  const tsPkgDir = resolvePackageDir("typescript", cwd);
7337
- const tscPath = tsPkgDir ? path24.join(tsPkgDir, "bin", "tsc") : path24.join(cwd, "node_modules", "typescript", "bin", "tsc");
7338
- if (!fs19.existsSync(tscPath)) {
6563
+ const tscPath = tsPkgDir ? path22.join(tsPkgDir, "bin", "tsc") : path22.join(cwd, "node_modules", "typescript", "bin", "tsc");
6564
+ if (!fs17.existsSync(tscPath)) {
7339
6565
  if (!options.autoFix) {
7340
6566
  return {
7341
6567
  ok: false,
@@ -7403,33 +6629,36 @@ ${stderr}`.trim() };
7403
6629
  function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
7404
6630
  const warnings = [];
7405
6631
  const hints = [];
7406
- const configPath = path24.join(cwd, PROJECT_CONFIG_FILE);
7407
- if (fs19.existsSync(configPath)) {
7408
- const configContent = fs19.readFileSync(configPath, "utf-8");
6632
+ const configPath = path22.join(
6633
+ cwd,
6634
+ fs17.existsSync(path22.join(cwd, PROJECT_CONFIG_FILE)) || !fs17.existsSync(path22.join(cwd, "iui.config.ts")) ? PROJECT_CONFIG_FILE : "iui.config.ts"
6635
+ );
6636
+ if (fs17.existsSync(configPath)) {
6637
+ const configContent = fs17.readFileSync(configPath, "utf-8");
7409
6638
  if (/packageSafelist\s*:\s*false/.test(configContent)) {
7410
6639
  warnings.push(
7411
- "Deprecated iui.config build.packageSafelist \u2014 remove it; Framework always merges IUI package compile contracts"
6640
+ "Deprecated theme.config build.packageSafelist \u2014 remove it; Framework always merges IUI package compile contracts"
7412
6641
  );
7413
6642
  }
7414
6643
  if (/includeShadeMatrix\s*:/.test(configContent)) {
7415
6644
  warnings.push(
7416
- "Deprecated compiler flags in iui.config build.* \u2014 remove them; compile policy is Framework-internal"
6645
+ "Deprecated compiler flags in theme.config build.* \u2014 remove them; compile policy is Framework-internal"
7417
6646
  );
7418
6647
  hints.push("Use theme + optional scan.dirs only. See Framework docs/01-compile-first-guide.md");
7419
6648
  }
7420
6649
  if (/scanPackages\s*:/.test(configContent) || /scan\.packages\s*:/.test(configContent)) {
7421
6650
  warnings.push(
7422
- "Deprecated scanPackages in iui.config \u2014 IUI packages are discovered from package.json dependencies"
6651
+ "Deprecated scanPackages in theme.config \u2014 IUI packages are discovered from package.json dependencies"
7423
6652
  );
7424
6653
  }
7425
6654
  }
7426
6655
  if (projectHasViteTooling(cwd)) {
7427
6656
  const viteCandidates = ["vite.config.ts", "vite.config.mjs", "vite.config.js"];
7428
- const vitePath = viteCandidates.map((name) => path24.join(cwd, name)).find((p) => fs19.existsSync(p));
6657
+ const vitePath = viteCandidates.map((name) => path22.join(cwd, name)).find((p) => fs17.existsSync(p));
7429
6658
  if (!vitePath) {
7430
6659
  warnings.push("Vite tooling detected but no vite.config.* found");
7431
6660
  } else {
7432
- const viteContent = fs19.readFileSync(vitePath, "utf-8");
6661
+ const viteContent = fs17.readFileSync(vitePath, "utf-8");
7433
6662
  if (!/inventiveUiVite\s*\(/.test(viteContent)) {
7434
6663
  warnings.push("vite.config is missing inventiveUiVite() \u2014 compile-first CSS will not generate");
7435
6664
  hints.push("Wire plugins: [...inventiveUiVite({ root: import.meta.dirname }), react()]");
@@ -7443,11 +6672,11 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
7443
6672
  "webpack.config.mjs",
7444
6673
  "webpack.config.ts"
7445
6674
  ];
7446
- const webpackPath = webpackCandidates.map((name) => path24.join(cwd, name)).find((p) => fs19.existsSync(p));
6675
+ const webpackPath = webpackCandidates.map((name) => path22.join(cwd, name)).find((p) => fs17.existsSync(p));
7447
6676
  if (!webpackPath) {
7448
6677
  warnings.push("Webpack tooling detected but no webpack.config.* found");
7449
6678
  } else {
7450
- const webpackContent = fs19.readFileSync(webpackPath, "utf-8");
6679
+ const webpackContent = fs17.readFileSync(webpackPath, "utf-8");
7451
6680
  if (!/inventiveUiWebpack\s*\(/.test(webpackContent)) {
7452
6681
  warnings.push("webpack.config is missing inventiveUiWebpack() \u2014 compile-first CSS will not generate");
7453
6682
  hints.push('Wire plugins: [...inventiveUiWebpack()] from "@inventive-ui/framework/webpack"');
@@ -7457,11 +6686,11 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
7457
6686
  }
7458
6687
  if (projectHasNextTooling(cwd)) {
7459
6688
  const nextCandidates = ["next.config.ts", "next.config.mjs", "next.config.js", "next.config.cjs"];
7460
- const nextPath = nextCandidates.map((name) => path24.join(cwd, name)).find((p) => fs19.existsSync(p));
6689
+ const nextPath = nextCandidates.map((name) => path22.join(cwd, name)).find((p) => fs17.existsSync(p));
7461
6690
  if (!nextPath) {
7462
6691
  warnings.push("Next.js detected but no next.config.* found");
7463
6692
  } else {
7464
- const nextContent = fs19.readFileSync(nextPath, "utf-8");
6693
+ const nextContent = fs17.readFileSync(nextPath, "utf-8");
7465
6694
  if (!/withIUI\s*\(/.test(nextContent)) {
7466
6695
  warnings.push("next.config is missing withIUI() \u2014 compile-first CSS will not generate");
7467
6696
  hints.push('Wrap config: export default withIUI({ ... }) from "@inventive-ui/framework/next"');
@@ -7474,18 +6703,18 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
7474
6703
  "src/app/layout.jsx",
7475
6704
  "app/providers.tsx",
7476
6705
  "src/app/providers.tsx"
7477
- ].map((rel) => path24.join(cwd, rel));
7478
- const readableLayouts = layoutCandidates.filter((file) => fs19.existsSync(file));
6706
+ ].map((rel) => path22.join(cwd, rel));
6707
+ const readableLayouts = layoutCandidates.filter((file) => fs17.existsSync(file));
7479
6708
  const hasRegistry = readableLayouts.some((file) => {
7480
6709
  try {
7481
- return /\bIUIRegistry\b/.test(fs19.readFileSync(file, "utf-8"));
6710
+ return /\bIUIRegistry\b/.test(fs17.readFileSync(file, "utf-8"));
7482
6711
  } catch {
7483
6712
  return false;
7484
6713
  }
7485
6714
  });
7486
6715
  const hasBootstrapImport = readableLayouts.some((file) => {
7487
6716
  try {
7488
- const content = fs19.readFileSync(file, "utf-8");
6717
+ const content = fs17.readFileSync(file, "utf-8");
7489
6718
  return /next\/bootstrap/.test(content) || /["']iui-bootstrap["']/.test(content) || /iui\/bootstrap/.test(content);
7490
6719
  } catch {
7491
6720
  return false;
@@ -7493,7 +6722,7 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
7493
6722
  });
7494
6723
  const hasProvider = readableLayouts.some((file) => {
7495
6724
  try {
7496
- return /\bIUIProvider\b/.test(fs19.readFileSync(file, "utf-8"));
6725
+ return /\bIUIProvider\b/.test(fs17.readFileSync(file, "utf-8"));
7497
6726
  } catch {
7498
6727
  return false;
7499
6728
  }
@@ -7524,14 +6753,14 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
7524
6753
  "src/app/providers.tsx",
7525
6754
  "app/layout.tsx",
7526
6755
  "src/app/layout.tsx"
7527
- ].map((rel) => path24.join(cwd, rel));
6756
+ ].map((rel) => path22.join(cwd, rel));
7528
6757
  for (const file of entryCandidates) {
7529
- if (!fs19.existsSync(file)) continue;
6758
+ if (!fs17.existsSync(file)) continue;
7530
6759
  try {
7531
- const content = fs19.readFileSync(file, "utf-8");
6760
+ const content = fs17.readFileSync(file, "utf-8");
7532
6761
  if (/from\s+['"][^'"]*\.generated['"]/.test(content) || /import\s+['"][^'"]*\.generated['"]/.test(content)) {
7533
6762
  warnings.push(
7534
- `Do not import .generated style-map files into the browser (${path24.relative(cwd, file)})`
6763
+ `Do not import .generated style-map files into the browser (${path22.relative(cwd, file)})`
7535
6764
  );
7536
6765
  hints.push(
7537
6766
  "Keep style maps on the scanner path (default src + .iui/generated, or override build.scanDirs) \u2014 see Framework compile-first docs"
@@ -7551,9 +6780,9 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
7551
6780
  hints.push(
7552
6781
  "Compile-first: avoid dynamic utility templates like `p-${n}` \u2014 use static strings, style maps, or safelist (ESLint: customPlugin/no-dynamic-utility-class)"
7553
6782
  );
7554
- const giPath = path24.join(cwd, ".gitignore");
7555
- if (fs19.existsSync(giPath)) {
7556
- const gi = fs19.readFileSync(giPath, "utf-8");
6783
+ const giPath = path22.join(cwd, ".gitignore");
6784
+ if (fs17.existsSync(giPath)) {
6785
+ const gi = fs17.readFileSync(giPath, "utf-8");
7557
6786
  if (!gi.includes(".iui/cache/")) {
7558
6787
  warnings.push(".gitignore missing IUI cache directory (.iui/cache/)");
7559
6788
  hints.push("Run iui init or append .iui/cache/ from the IUI docs");
@@ -7564,11 +6793,11 @@ function checkCompileFirstReadiness(cwd = process.cwd(), _options = {}) {
7564
6793
  function checkMetadataPortability(cwd = process.cwd()) {
7565
6794
  const warnings = [];
7566
6795
  const hints = [];
7567
- const iuiPath = path24.join(cwd, IUI_DIR);
7568
- const projectPath = path24.join(iuiPath, "project.json");
7569
- if (fs19.existsSync(projectPath)) {
6796
+ const iuiPath = path22.join(cwd, IUI_DIR);
6797
+ const projectPath = path22.join(iuiPath, "project.json");
6798
+ if (fs17.existsSync(projectPath)) {
7570
6799
  try {
7571
- const meta = fs19.readJsonSync(projectPath);
6800
+ const meta = fs17.readJsonSync(projectPath);
7572
6801
  const repoUrl = meta.repoUrl ?? "";
7573
6802
  if (/^[A-Za-z]:[\\/]/.test(repoUrl) || repoUrl.startsWith("/") && !repoUrl.startsWith("//") || repoUrl.startsWith("file:")) {
7574
6803
  warnings.push("project.json repoUrl is a local filesystem path \u2014 use a git remote URL");
@@ -7577,15 +6806,15 @@ function checkMetadataPortability(cwd = process.cwd()) {
7577
6806
  } catch {
7578
6807
  }
7579
6808
  }
7580
- const workspacePath = path24.join(iuiPath, "workspace.json");
7581
- if (fs19.existsSync(workspacePath)) {
6809
+ const workspacePath = path22.join(iuiPath, "workspace.json");
6810
+ if (fs17.existsSync(workspacePath)) {
7582
6811
  try {
7583
- const ws = fs19.readJsonSync(workspacePath);
6812
+ const ws = fs17.readJsonSync(workspacePath);
7584
6813
  if (ws.iuiRoot) {
7585
6814
  warnings.push("workspace.json contains deprecated iuiRoot \u2014 remove it (root is implicit)");
7586
6815
  }
7587
6816
  for (const pkg of ws.packages ?? []) {
7588
- if (/^[A-Za-z]:[\\/]/.test(pkg) || path24.isAbsolute(pkg)) {
6817
+ if (/^[A-Za-z]:[\\/]/.test(pkg) || path22.isAbsolute(pkg)) {
7589
6818
  warnings.push(`workspace.json packages entry is absolute: ${pkg}`);
7590
6819
  hints.push("packages should be relative paths from the IUI root");
7591
6820
  }
@@ -7594,9 +6823,9 @@ function checkMetadataPortability(cwd = process.cwd()) {
7594
6823
  }
7595
6824
  }
7596
6825
  const scanCachePath = iuiCacheFile(cwd, "scan");
7597
- if (fs19.existsSync(scanCachePath)) {
6826
+ if (fs17.existsSync(scanCachePath)) {
7598
6827
  try {
7599
- const cache = fs19.readJsonSync(scanCachePath);
6828
+ const cache = fs17.readJsonSync(scanCachePath);
7600
6829
  const absoluteKeys = Object.keys(cache.files ?? {}).filter(
7601
6830
  (key) => /^[A-Za-z]:[\\/]/.test(key) || key.startsWith("/") && !key.startsWith("//")
7602
6831
  );
@@ -7613,38 +6842,70 @@ function checkMetadataPortability(cwd = process.cwd()) {
7613
6842
  }
7614
6843
  return { warnings, hints };
7615
6844
  }
7616
- function checkAssetBoundBindings(cwd = process.cwd()) {
7617
- const assetsPath = path24.join(cwd, ASSETS_CONFIG_FILE);
7618
- if (!fs19.existsSync(assetsPath)) {
7619
- return { ok: true, summary: "Asset binding check skipped (no assets.config.json)" };
6845
+ var ICON_LIBRARY_PACKAGES = {
6846
+ "material-symbols": "material-symbols",
6847
+ materialSymbols: "material-symbols",
6848
+ "material-icons": "icons-material",
6849
+ lucide: "icons-lucide",
6850
+ phosphor: "icons-phosphor"
6851
+ };
6852
+ function checkAssetPipeline(cwd = process.cwd()) {
6853
+ const assetsPath = path22.join(cwd, ASSETS_CONFIG_FILE);
6854
+ if (!fs17.existsSync(assetsPath)) {
6855
+ return { ok: true, summary: "Asset check skipped (no assets.config.json)" };
7620
6856
  }
7621
6857
  let assets2;
7622
6858
  try {
7623
- assets2 = fs19.readJsonSync(assetsPath);
6859
+ assets2 = fs17.readJsonSync(assetsPath);
7624
6860
  } catch {
7625
6861
  return { ok: false, summary: "assets.config.json is not valid JSON" };
7626
6862
  }
7627
- if (assets2.binding !== "scanned") {
7628
- return { ok: true, summary: "Asset slots use lazy binding (default)" };
6863
+ const packagesDir = path22.join(cwd, "node_modules", "@inventive-ui");
6864
+ const frameworkPkg = path22.join(packagesDir, "framework", "package.json");
6865
+ if (fs17.existsSync(frameworkPkg)) {
6866
+ const framework = fs17.readJsonSync(frameworkPkg);
6867
+ if (!framework.exports?.["./assets"]) {
6868
+ return {
6869
+ ok: false,
6870
+ summary: "Installed @inventive-ui/framework has no asset pipeline",
6871
+ details: "Update it: iui update"
6872
+ };
6873
+ }
6874
+ }
6875
+ const library = assets2.icon?.library;
6876
+ const pkg = library ? ICON_LIBRARY_PACKAGES[library] : void 0;
6877
+ if (!pkg) return { ok: true, summary: "Asset config valid" };
6878
+ const iconsDir = path22.join(packagesDir, pkg, "dist", "icons");
6879
+ if (!fs17.existsSync(iconsDir)) {
6880
+ return {
6881
+ ok: false,
6882
+ summary: `Icon library "${library}" is configured but @inventive-ui/${pkg} is not installed`,
6883
+ details: `Install it: iui install assets @inventive-ui/${pkg}`
6884
+ };
7629
6885
  }
7630
- const registerBound = path24.join(generatedAssetsDir(cwd), "register-bound.ts");
7631
- if (!fs19.existsSync(registerBound)) {
6886
+ const glyphs = [
6887
+ ...Object.entries(assets2.icon?.globalIcons ?? {}).map(([alias, glyph]) => [`@${alias}`, glyph]),
6888
+ ["placeholder", assets2.icon?.placeholder?.name],
6889
+ ["fallback", assets2.icon?.fallback]
6890
+ ].filter((entry) => typeof entry[1] === "string" && entry[1].length > 0);
6891
+ const missing = glyphs.filter(([, glyph]) => !fs17.existsSync(path22.join(iconsDir, `${glyph}.js`)));
6892
+ if (missing.length > 0) {
7632
6893
  return {
7633
6894
  ok: false,
7634
- summary: 'binding is "scanned" but .iui/generated/assets/register-bound.ts is missing',
7635
- details: "Run any iui command to refresh the slot registry, or reinstall asset packages."
6895
+ summary: `${missing.length} icon alias${missing.length === 1 ? "" : "es"} point at glyphs "${library}" does not have`,
6896
+ details: missing.slice(0, 8).map(([name, glyph]) => `${name} \u2192 ${glyph}`).join(", ")
7636
6897
  };
7637
6898
  }
7638
- return { ok: true, summary: "Scanned asset bindings present" };
6899
+ return { ok: true, summary: `Asset config valid (${glyphs.length} icon names checked in ${library})` };
7639
6900
  }
7640
6901
  function checkBootstrapSync(cwd = process.cwd(), options = {}) {
7641
6902
  const iuiRoot2 = resolveIuiProjectRoot(cwd);
7642
6903
  const generatedPath = bootstrapGeneratedPath(iuiRoot2);
7643
- const bridgePath = path24.join(cwd, "src", "iui", "bootstrap.ts");
7644
- if (!fs19.existsSync(generatedPath)) {
6904
+ const bridgePath = path22.join(cwd, "src", "iui", "bootstrap.ts");
6905
+ if (!fs17.existsSync(generatedPath)) {
7645
6906
  if (options.autoFix) {
7646
6907
  writeProjectBootstrapArtifacts(cwd, iuiRoot2);
7647
- if (fs19.existsSync(generatedPath)) {
6908
+ if (fs17.existsSync(generatedPath)) {
7648
6909
  return { ok: true, summary: "Generated bootstrap artifacts repaired" };
7649
6910
  }
7650
6911
  }
@@ -7654,10 +6915,10 @@ function checkBootstrapSync(cwd = process.cwd(), options = {}) {
7654
6915
  details: "Expected .iui/generated/bootstrap.generated.tsx \u2014 run iui doctor --fix."
7655
6916
  };
7656
6917
  }
7657
- if (!fs19.existsSync(bridgePath)) {
6918
+ if (!fs17.existsSync(bridgePath)) {
7658
6919
  if (options.autoFix) {
7659
6920
  writeProjectBootstrapArtifacts(cwd, iuiRoot2);
7660
- if (fs19.existsSync(bridgePath)) {
6921
+ if (fs17.existsSync(bridgePath)) {
7661
6922
  return { ok: true, summary: "Bootstrap bridge repaired" };
7662
6923
  }
7663
6924
  }
@@ -7670,8 +6931,8 @@ function checkBootstrapSync(cwd = process.cwd(), options = {}) {
7670
6931
  const configs = resolveProjectConfigPaths(iuiRoot2);
7671
6932
  const missing = [];
7672
6933
  for (const [key, rel] of Object.entries(configs)) {
7673
- const abs = path24.resolve(iuiRoot2, rel.replace(/^\.\//, ""));
7674
- if (!fs19.existsSync(abs)) missing.push(`${key}: ${rel}`);
6934
+ const abs = path22.resolve(iuiRoot2, rel.replace(/^\.\//, ""));
6935
+ if (!fs17.existsSync(abs)) missing.push(`${key}: ${rel}`);
7675
6936
  }
7676
6937
  if (missing.length > 0) {
7677
6938
  return {
@@ -7681,8 +6942,11 @@ function checkBootstrapSync(cwd = process.cwd(), options = {}) {
7681
6942
  };
7682
6943
  }
7683
6944
  const expected = expectedBootstrapImportPaths(iuiRoot2);
7684
- const generated = fs19.readFileSync(generatedPath, "utf8");
6945
+ const generated = fs17.readFileSync(generatedPath, "utf8");
7685
6946
  const stale = [];
6947
+ if (/["']\.\/slot\.generated["']|@inventive-ui\/framework\/slots/.test(generated)) {
6948
+ stale.push("bootstrap still imports removed component-slot output");
6949
+ }
7686
6950
  for (const [key, importPath] of Object.entries(expected)) {
7687
6951
  if (!generated.includes(`"${importPath}"`)) {
7688
6952
  stale.push(`${key} import should be "${importPath}"`);
@@ -7691,11 +6955,11 @@ function checkBootstrapSync(cwd = process.cwd(), options = {}) {
7691
6955
  if (stale.length > 0) {
7692
6956
  if (options.autoFix) {
7693
6957
  writeProjectBootstrapArtifacts(cwd, iuiRoot2);
7694
- const refreshed = fs19.readFileSync(bootstrapGeneratedPath(iuiRoot2), "utf8");
6958
+ const refreshed = fs17.readFileSync(bootstrapGeneratedPath(iuiRoot2), "utf8");
7695
6959
  const stillStale = Object.entries(expected).filter(
7696
6960
  ([, importPath]) => !refreshed.includes(`"${importPath}"`)
7697
6961
  );
7698
- if (stillStale.length === 0) {
6962
+ if (stillStale.length === 0 && !/slot\.generated/.test(refreshed)) {
7699
6963
  return { ok: true, summary: "Generated bootstrap refreshed from project.json" };
7700
6964
  }
7701
6965
  }
@@ -7709,6 +6973,24 @@ function checkBootstrapSync(cwd = process.cwd(), options = {}) {
7709
6973
  }
7710
6974
 
7711
6975
  // src/commands/doctor.ts
6976
+ function repairStaleSlotOutput(targetCwd) {
6977
+ if (!isInsideProject(targetCwd)) return;
6978
+ writeProjectBootstrapArtifacts(targetCwd, resolveIuiProjectRoot(targetCwd));
6979
+ }
6980
+ function reportStaleSlotOutput(targetCwd, pass, fail2) {
6981
+ const staleSlots = checkStaleComponentSlotOutput(targetCwd);
6982
+ if (staleSlots.ok) {
6983
+ pass(staleSlots.summary);
6984
+ return;
6985
+ }
6986
+ fail2(staleSlots.summary);
6987
+ if (staleSlots.details) {
6988
+ for (const line of staleSlots.details.split("\n")) {
6989
+ hint(line);
6990
+ }
6991
+ }
6992
+ hint("Fix: run iui doctor --fix to remove it and regenerate bootstrap");
6993
+ }
7712
6994
  async function runConfigTierDiagnostics(targetCwd, opts, counters, options = {}) {
7713
6995
  const pass = (label) => {
7714
6996
  checkPass(label);
@@ -7719,7 +7001,7 @@ async function runConfigTierDiagnostics(targetCwd, opts, counters, options = {})
7719
7001
  counters.failed++;
7720
7002
  };
7721
7003
  const includePackageJson = options.includePackageJson !== false;
7722
- const includeSlotCheck = options.includeSlotCheck === true;
7004
+ const includeStaleSlotCheck = options.includeStaleSlotCheck === true;
7723
7005
  if (includePackageJson) {
7724
7006
  if (hasPackageJson(targetCwd)) pass("package.json found");
7725
7007
  else fail2("package.json missing");
@@ -7734,20 +7016,10 @@ async function runConfigTierDiagnostics(targetCwd, opts, counters, options = {})
7734
7016
  }
7735
7017
  ensureComponentConfig(readComponentPackageManifest(targetCwd), targetCwd);
7736
7018
  await ensureSlotRegistry({ cwd: targetCwd, quiet: true, mode: "repair" });
7019
+ repairStaleSlotOutput(targetCwd);
7737
7020
  }
7738
- if (includeSlotCheck && isInsideProject(targetCwd) && getInstalledPackageVersion(COMPONENTS_PACKAGE, targetCwd)) {
7739
- const slotValidity = checkGeneratedSlotValidity(targetCwd);
7740
- if (slotValidity.ok) {
7741
- pass(slotValidity.summary);
7742
- } else {
7743
- fail2(slotValidity.summary);
7744
- if (slotValidity.details) {
7745
- for (const line of slotValidity.details.split("\n")) {
7746
- hint(line);
7747
- }
7748
- }
7749
- hint("Fix: reinstall @inventive-ui/components and rerun iui doctor");
7750
- }
7021
+ if (includeStaleSlotCheck && isInsideProject(targetCwd)) {
7022
+ reportStaleSlotOutput(targetCwd, pass, fail2);
7751
7023
  }
7752
7024
  const configValidity = checkComponentConfigValidity(targetCwd, {
7753
7025
  autoFix: opts?.fix === true
@@ -7817,12 +7089,12 @@ async function runConfigTierDiagnostics(targetCwd, opts, counters, options = {})
7817
7089
  hint(hint2);
7818
7090
  }
7819
7091
  }
7820
- const assetBound = checkAssetBoundBindings(targetCwd);
7821
- if (assetBound.ok) {
7822
- pass(assetBound.summary);
7092
+ const assetPipeline = checkAssetPipeline(targetCwd);
7093
+ if (assetPipeline.ok) {
7094
+ pass(assetPipeline.summary);
7823
7095
  } else {
7824
- warn(assetBound.summary);
7825
- if (assetBound.details) hint(assetBound.details);
7096
+ warn(assetPipeline.summary);
7097
+ if (assetPipeline.details) hint(assetPipeline.details);
7826
7098
  }
7827
7099
  }
7828
7100
  async function runPackageDiagnostics(targetCwd, opts, counters) {
@@ -7837,7 +7109,7 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
7837
7109
  if (opts?.configOnly) {
7838
7110
  await runConfigTierDiagnostics(targetCwd, opts, counters, {
7839
7111
  includePackageJson: true,
7840
- includeSlotCheck: true
7112
+ includeStaleSlotCheck: true
7841
7113
  });
7842
7114
  return;
7843
7115
  }
@@ -7852,6 +7124,7 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
7852
7124
  }
7853
7125
  ensureComponentConfig(readComponentPackageManifest(targetCwd), targetCwd);
7854
7126
  await ensureSlotRegistry({ cwd: targetCwd, quiet: true, mode: "repair" });
7127
+ repairStaleSlotOutput(targetCwd);
7855
7128
  }
7856
7129
  if (isInsideProject(targetCwd)) {
7857
7130
  pass("Inventive UI project initialized");
@@ -7899,9 +7172,6 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
7899
7172
  const packages = readPackageManifest(targetCwd);
7900
7173
  const pkgCount = Object.keys(packages).length;
7901
7174
  pass(`${pkgCount} asset package${pkgCount !== 1 ? "s" : ""} installed`);
7902
- const slots = readSlotManifest(targetCwd);
7903
- const slotCount = Object.keys(slots).length;
7904
- pass(`${slotCount} slot${slotCount !== 1 ? "s" : ""} registered`);
7905
7175
  const compatibility = checkPackageCompatibility(targetCwd);
7906
7176
  if (compatibility.ok) {
7907
7177
  pass(compatibility.summary);
@@ -7942,18 +7212,7 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
7942
7212
  pass("Inventive UI packages are on the latest version");
7943
7213
  }
7944
7214
  }
7945
- const slotValidity = checkGeneratedSlotValidity(targetCwd);
7946
- if (slotValidity.ok) {
7947
- pass(slotValidity.summary);
7948
- } else {
7949
- fail2(slotValidity.summary);
7950
- if (slotValidity.details) {
7951
- for (const line of slotValidity.details.split("\n")) {
7952
- hint(line);
7953
- }
7954
- }
7955
- hint("Fix: reinstall @inventive-ui/components and rerun iui doctor");
7956
- }
7215
+ reportStaleSlotOutput(targetCwd, pass, fail2);
7957
7216
  const bootstrapSync = checkBootstrapSync(targetCwd, {
7958
7217
  autoFix: opts?.fix === true
7959
7218
  });
@@ -7972,13 +7231,13 @@ async function runPackageDiagnostics(targetCwd, opts, counters) {
7972
7231
  }
7973
7232
  await runConfigTierDiagnostics(targetCwd, opts, counters, {
7974
7233
  includePackageJson: false,
7975
- includeSlotCheck: false
7234
+ includeStaleSlotCheck: false
7976
7235
  });
7977
7236
  }
7978
7237
  async function doctorCommand(opts) {
7979
7238
  try {
7980
7239
  const invocationCwd = process.cwd();
7981
- const targets = opts?.cwd ? [path25.resolve(opts.cwd)] : resolveSetupDoctorTargets(invocationCwd);
7240
+ const targets = opts?.cwd ? [path23.resolve(opts.cwd)] : resolveSetupDoctorTargets(invocationCwd);
7982
7241
  const installRoot = resolveDependencyInstallRoot(invocationCwd);
7983
7242
  const multiPackage = targets.length > 1;
7984
7243
  heading("Diagnostics");
@@ -8021,7 +7280,7 @@ async function doctorCommand(opts) {
8021
7280
  for (const targetCwd of targets) {
8022
7281
  if (multiPackage) {
8023
7282
  newline();
8024
- const label = path25.relative(installRoot, targetCwd) || path25.basename(targetCwd);
7283
+ const label = path23.relative(installRoot, targetCwd) || path23.basename(targetCwd);
8025
7284
  kv("Package", label);
8026
7285
  }
8027
7286
  await runPackageDiagnostics(targetCwd, opts, counters);
@@ -8034,7 +7293,7 @@ async function doctorCommand(opts) {
8034
7293
  } else {
8035
7294
  fail(`${counters.failed} issue${counters.failed > 1 ? "s" : ""} found`);
8036
7295
  hint("Resolve the issues above and re-run iui doctor");
8037
- hint("Checklist: compatibility, managed slots, config validity, required types");
7296
+ hint("Checklist: compatibility, generated bootstrap, config validity, required types");
8038
7297
  if (!opts?.fix) {
8039
7298
  hint("Use iui doctor --fix to apply safe automatic repairs");
8040
7299
  }
@@ -8049,9 +7308,9 @@ async function doctorCommand(opts) {
8049
7308
 
8050
7309
  // src/commands/setup.ts
8051
7310
  function detectDevScript(cwd) {
8052
- const pkgPath = path26.join(cwd, "package.json");
7311
+ const pkgPath = path24.join(cwd, "package.json");
8053
7312
  try {
8054
- const pkg = fs20.readJsonSync(pkgPath);
7313
+ const pkg = fs18.readJsonSync(pkgPath);
8055
7314
  if (pkg.scripts?.dev) return "npm run dev";
8056
7315
  if (pkg.scripts?.start) return "npm run start";
8057
7316
  } catch {
@@ -8060,8 +7319,8 @@ function detectDevScript(cwd) {
8060
7319
  return null;
8061
7320
  }
8062
7321
  function relativePackageLabel(installRoot, packageDir) {
8063
- const rel = path26.relative(installRoot, packageDir);
8064
- return rel && rel !== "." ? rel : path26.basename(packageDir);
7322
+ const rel = path24.relative(installRoot, packageDir);
7323
+ return rel && rel !== "." ? rel : path24.basename(packageDir);
8065
7324
  }
8066
7325
  async function setupCommand(opts) {
8067
7326
  try {
@@ -8070,7 +7329,7 @@ async function setupCommand(opts) {
8070
7329
  const installRoot = resolveDependencyInstallRoot(cwd);
8071
7330
  const workspaceRoot = findWorkspaceRoot(cwd);
8072
7331
  const inMonorepo = workspaceRoot !== null;
8073
- const installFromChild = inMonorepo && path26.resolve(installRoot) !== path26.resolve(cwd);
7332
+ const installFromChild = inMonorepo && path24.resolve(installRoot) !== path24.resolve(cwd);
8074
7333
  if (!hasPackageJson(cwd) && !hasPackageJson(installRoot)) {
8075
7334
  throw new CLIError(
8076
7335
  "No package.json found in the current directory.",
@@ -8104,7 +7363,7 @@ async function setupCommand(opts) {
8104
7363
  for (const w of warnings) warn(w);
8105
7364
  kv("Package manager", `${pm} (${source})`);
8106
7365
  if (installFromChild) {
8107
- const rel = path26.relative(cwd, installRoot) || ".";
7366
+ const rel = path24.relative(cwd, installRoot) || ".";
8108
7367
  kv("Install directory", rel === ".." || rel.includes("..") ? installRoot : rel);
8109
7368
  }
8110
7369
  const installCmd2 = syncInstallCommand(pm);
@@ -8118,7 +7377,7 @@ async function setupCommand(opts) {
8118
7377
  } catch (err) {
8119
7378
  installSpinner.fail("Dependency install failed");
8120
7379
  const detail = formatExecSyncError(err);
8121
- const manual = path26.resolve(installRoot) === path26.resolve(cwd) ? installCmd2 : `cd ${JSON.stringify(installRoot)} && ${installCmd2}`;
7380
+ const manual = path24.resolve(installRoot) === path24.resolve(cwd) ? installCmd2 : `cd ${JSON.stringify(installRoot)} && ${installCmd2}`;
8122
7381
  throw new CLIError(
8123
7382
  detail ? `Could not install project dependencies.
8124
7383
  ${detail}` : "Could not install project dependencies.",
@@ -8245,23 +7504,6 @@ async function listCommand(opts) {
8245
7504
  newline();
8246
7505
  info(`${pkgKeys.length} asset package${pkgKeys.length !== 1 ? "s" : ""} installed`);
8247
7506
  }
8248
- heading("Slot Registry");
8249
- const slots = readSlotManifest();
8250
- const slotKeys = Object.keys(slots);
8251
- if (slotKeys.length === 0) {
8252
- info("No component slots available yet.");
8253
- } else {
8254
- for (const [key, record] of Object.entries(slots)) {
8255
- const displayName = itemsLookup[key]?.title ?? key;
8256
- const slotInfo = record.supportedSlots?.length ? `${record.slotType} \xB7 slots: ${record.supportedSlots.join(", ")}` : `${record.slotType}`;
8257
- bulletItem(
8258
- displayName.padEnd(26),
8259
- `${slotInfo} \xB7 v${record.version}`
8260
- );
8261
- }
8262
- newline();
8263
- info(`${slotKeys.length} slot${slotKeys.length !== 1 ? "s" : ""} registered`);
8264
- }
8265
7507
  newline();
8266
7508
  } catch (error) {
8267
7509
  handleError(error);
@@ -8276,7 +7518,7 @@ async function updateCommand(opts = {}) {
8276
7518
  const auth = await ensureAuthSession();
8277
7519
  await ensureLicenseSession();
8278
7520
  const inProject = isInsideProject();
8279
- const currentCliVersion = true ? "0.0.10" : "unknown";
7521
+ const currentCliVersion = true ? "0.0.12" : "unknown";
8280
7522
  const latestCliVersion = await fetchLatestCliVersion(auth.token);
8281
7523
  const cliUpdateAvailable = latestCliVersion !== null && isVersionGreater(latestCliVersion, currentCliVersion);
8282
7524
  if (latestCliVersion && cliUpdateAvailable) {
@@ -8558,7 +7800,7 @@ var AUTH_EXEMPT_COMMANDS = /* @__PURE__ */ new Set([
8558
7800
  "doctor",
8559
7801
  "list"
8560
7802
  ]);
8561
- program.name("iui").description("The official CLI for the Inventive UI Design System").version(true ? "0.0.10" : "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");
7803
+ program.name("iui").description("The official CLI for the Inventive UI Design System").version(true ? "0.0.12" : "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");
8562
7804
  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));
8563
7805
  program.command("logout").description("Remove stored credentials").action(logoutCommand);
8564
7806
  program.command("whoami").description("Show authenticated identity and license details").action(whoamiCommand);
@@ -8641,7 +7883,7 @@ program.command("update").description("Check for and apply framework, component,
8641
7883
  var assets = program.command("assets").description("Manage asset packages (icons, illustrations, logos, etc.)");
8642
7884
  assets.command("remove <package>").description("Remove an installed asset package").action((pkg) => assetsRemoveCommand(pkg));
8643
7885
  assets.command("list").description("Show all available and installed asset packages").action(assetsListCommand);
8644
- 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));
7886
+ 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));
8645
7887
  if (shouldShowBanner()) {
8646
7888
  printBanner();
8647
7889
  }
@@ -8656,7 +7898,7 @@ program.hook("preAction", async (_thisCommand, actionCommand) => {
8656
7898
  const root = topLevelCommandName(actionCommand);
8657
7899
  const globalOpts = program.opts();
8658
7900
  if (globalOpts.cwd) {
8659
- process.chdir(path27.resolve(globalOpts.cwd));
7901
+ process.chdir(path25.resolve(globalOpts.cwd));
8660
7902
  }
8661
7903
  if (isInsideProject()) {
8662
7904
  try {
@@ -8670,14 +7912,14 @@ program.hook("preAction", async (_thisCommand, actionCommand) => {
8670
7912
  mode: slotPolicy.mode
8671
7913
  });
8672
7914
  if (result.status === "repaired") {
8673
- info("Slot registry repaired");
7915
+ info("Project registry repaired");
8674
7916
  }
8675
7917
  } catch (error) {
8676
7918
  if (error instanceof CLIError) {
8677
7919
  warn(error.message);
8678
7920
  if (error.hint) hint(error.hint);
8679
7921
  } else {
8680
- warn("Slot registry validation failed; run iui doctor for diagnostics.");
7922
+ warn("Project registry validation failed; run iui doctor for diagnostics.");
8681
7923
  }
8682
7924
  }
8683
7925
  }