inai-react-components 1.6.0 → 1.6.2

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.
@@ -274,14 +274,24 @@ export declare function getLegacyTailwindCssTemplate(theme: Theme, fontBody: Fon
274
274
  export declare function normalizeThemeCss(css: string, theme: string): string;
275
275
  /**
276
276
  * Copies the i18n base files (context, types, defaults) from the registry
277
- * to `<sourceRoot>/lib/`. ~75 components import `useUIMessages` from the
278
- * i18n context; the CLI rewrites those imports at install-time to the
279
- * unified `aliases.lib` directory, so the files must land there.
277
+ * to the unified lib directory. ~75 components import `useUIMessages`
278
+ * from the i18n context; the CLI rewrites those imports at install-time
279
+ * to the `aliases.lib` directory, so the files must land there.
280
280
  *
281
- * Never overwrites pre-existing files so a user's custom i18n provider
282
- * stays intact across re-runs.
281
+ * Normalizes `.js` import suffixes in the process (so the copied
282
+ * `i18n-context.tsx` reads without bundler-incompatible extensions) and
283
+ * never overwrites pre-existing files.
283
284
  */
284
285
  export declare function copyI18nFiles(registryDir: string | undefined, targetDir: string, libDirRelative: string): string[];
286
+ /**
287
+ * Copies the canonical `cn.ts` from the cached registry to the user's
288
+ * lib directory. We copy the REAL source file (not a hardcoded template)
289
+ * because components import extra type exports like `ClassNames` that
290
+ * any minimal template would miss. Returns `true` if the file was
291
+ * written, `false` if the registry copy was missing or a user file was
292
+ * already present.
293
+ */
294
+ export declare function copyCnFile(registryDir: string | undefined, targetDir: string, libDirRelative: string): boolean;
285
295
  export declare function runInit(config: InitConfig, targetDir: string, repoUrl?: string): Promise<{
286
296
  success: boolean;
287
297
  filesCreated: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@ import { cloneRegistry, getCacheDir } from "../utils/registry-resolver.js";
7
7
  import { THEME_NAMES } from "../utils/themes.js";
8
8
  import { detectFramework, frameworkLabel, getCssEntryPoint, } from "../utils/framework-detect.js";
9
9
  import { detectProjectLayout, } from "../utils/tsconfig-detect.js";
10
+ import { stripRelativeJsExtensions } from "../utils/paths.js";
10
11
  const AVAILABLE_THEMES = THEME_NAMES;
11
12
  const FONT_PRESETS = [
12
13
  // Sans-serif — geometric & modern
@@ -351,14 +352,41 @@ function copyTokensToProject(registryDir, targetDir, theme, sourceRoot) {
351
352
  }
352
353
  return copied;
353
354
  }
355
+ /**
356
+ * Read a source file from the registry and write it to the user's lib
357
+ * directory with imports normalized — `.js` suffixes stripped so the
358
+ * installed code reads naturally under bundler-style resolution (Vite,
359
+ * Next.js, TanStack Start, …). Never overwrites a pre-existing file so
360
+ * user customizations stay intact across re-runs.
361
+ *
362
+ * Returns the relative destination path if written, or `null` if skipped
363
+ * (file missing in registry, or already present in the user project).
364
+ */
365
+ function copyLibFileNormalized(srcPath, destPath) {
366
+ if (!fs.existsSync(srcPath))
367
+ return false;
368
+ if (fs.existsSync(destPath))
369
+ return false; // don't clobber user files
370
+ const raw = fs.readFileSync(srcPath, "utf-8");
371
+ // Strip `.js` from relative sibling imports so `i18n-context.tsx`'s
372
+ // `./i18n-types.js` becomes `./i18n-types`. We intentionally DON'T
373
+ // apply `rewriteLibImports` here — these files live inside the lib
374
+ // directory already, so their sibling imports are correctly relative
375
+ // and shouldn't be rerouted through the `@/lib/*` alias.
376
+ const normalized = stripRelativeJsExtensions(raw);
377
+ fs.mkdirSync(path.dirname(destPath), { recursive: true });
378
+ fs.writeFileSync(destPath, normalized);
379
+ return true;
380
+ }
354
381
  /**
355
382
  * Copies the i18n base files (context, types, defaults) from the registry
356
- * to `<sourceRoot>/lib/`. ~75 components import `useUIMessages` from the
357
- * i18n context; the CLI rewrites those imports at install-time to the
358
- * unified `aliases.lib` directory, so the files must land there.
383
+ * to the unified lib directory. ~75 components import `useUIMessages`
384
+ * from the i18n context; the CLI rewrites those imports at install-time
385
+ * to the `aliases.lib` directory, so the files must land there.
359
386
  *
360
- * Never overwrites pre-existing files so a user's custom i18n provider
361
- * stays intact across re-runs.
387
+ * Normalizes `.js` import suffixes in the process (so the copied
388
+ * `i18n-context.tsx` reads without bundler-incompatible extensions) and
389
+ * never overwrites pre-existing files.
362
390
  */
363
391
  export function copyI18nFiles(registryDir, targetDir, libDirRelative) {
364
392
  if (!registryDir)
@@ -366,20 +394,31 @@ export function copyI18nFiles(registryDir, targetDir, libDirRelative) {
366
394
  const files = ["i18n-context.tsx", "i18n-types.ts", "i18n-defaults.ts"];
367
395
  const srcBase = path.join(registryDir, "packages", "ui", "src", "lib");
368
396
  const destBase = path.join(targetDir, libDirRelative);
369
- fs.mkdirSync(destBase, { recursive: true });
370
397
  const copied = [];
371
398
  for (const file of files) {
372
399
  const src = path.join(srcBase, file);
373
- if (!fs.existsSync(src))
374
- continue;
375
400
  const dest = path.join(destBase, file);
376
- if (fs.existsSync(dest))
377
- continue; // don't clobber user files
378
- fs.copyFileSync(src, dest);
379
- copied.push(`${libDirRelative}/${file}`);
401
+ if (copyLibFileNormalized(src, dest)) {
402
+ copied.push(`${libDirRelative}/${file}`);
403
+ }
380
404
  }
381
405
  return copied;
382
406
  }
407
+ /**
408
+ * Copies the canonical `cn.ts` from the cached registry to the user's
409
+ * lib directory. We copy the REAL source file (not a hardcoded template)
410
+ * because components import extra type exports like `ClassNames` that
411
+ * any minimal template would miss. Returns `true` if the file was
412
+ * written, `false` if the registry copy was missing or a user file was
413
+ * already present.
414
+ */
415
+ export function copyCnFile(registryDir, targetDir, libDirRelative) {
416
+ if (!registryDir)
417
+ return false;
418
+ const src = path.join(registryDir, "packages", "ui", "src", "lib", "cn.ts");
419
+ const dest = path.join(targetDir, libDirRelative, "cn.ts");
420
+ return copyLibFileNormalized(src, dest);
421
+ }
383
422
  export async function runInit(config, targetDir, repoUrl) {
384
423
  const filesCreated = [];
385
424
  const sourceRoot = config.layout?.sourceRoot ?? "src";
@@ -393,27 +432,30 @@ export async function runInit(config, targetDir, repoUrl) {
393
432
  fs.mkdirSync(componentDir, { recursive: true });
394
433
  const blockDir = path.join(targetDir, config.blockPath);
395
434
  fs.mkdirSync(blockDir, { recursive: true });
396
- // 3. Create the unified lib directory under `<sourceRoot>/lib/` and
397
- // seed it with `cn.ts`. Every component/block lib file ships here;
398
- // the CLI rewrites all imports at install-time to point at the
399
- // `aliases.lib` alias so there's a single source of truth.
400
- //
401
- // Never overwrite an existing `cn.ts` the user may have their own.
435
+ // 3. Create the unified lib directory under `<sourceRoot>/lib/`. Every
436
+ // component/block lib file ships here; the CLI rewrites all imports
437
+ // at install-time to point at the `aliases.lib` alias so there's a
438
+ // single source of truth. `cn.ts` is seeded here so `init` users
439
+ // can start writing app code immediately — the real file (not a
440
+ // hardcoded template) is copied from the registry so secondary
441
+ // exports like `ClassNames` stay available to components. Never
442
+ // overwrite existing user files.
402
443
  const libDirRelative = `${sourceRoot}/lib`;
403
444
  const libDir = path.join(targetDir, libDirRelative);
404
445
  fs.mkdirSync(libDir, { recursive: true });
405
- const cnPath = path.join(libDir, "cn.ts");
406
- if (!fs.existsSync(cnPath)) {
407
- fs.writeFileSync(cnPath, getCnTemplate());
408
- filesCreated.push(`${libDirRelative}/cn.ts`);
409
- }
410
446
  // 4. Copy tokens and create CSS
411
447
  const cssRelPath = config.cssEntryPoint ?? `${sourceRoot}/index.css`;
412
448
  const cssPath = path.join(targetDir, cssRelPath);
413
449
  fs.mkdirSync(path.dirname(cssPath), { recursive: true });
414
450
  if (repoUrl) {
415
- // Remote mode: copy tokens from cached registry
451
+ // Remote mode: copy tokens and canonical lib files from the cached
452
+ // registry so users get the real `cn.ts` (including type exports
453
+ // like `ClassNames` that downstream components import) rather than
454
+ // a minimal hardcoded template.
416
455
  const registryDir = getCacheDir();
456
+ if (copyCnFile(registryDir, targetDir, libDirRelative)) {
457
+ filesCreated.push(`${libDirRelative}/cn.ts`);
458
+ }
417
459
  const tokenFiles = copyTokensToProject(registryDir, targetDir, config.theme, sourceRoot);
418
460
  filesCreated.push(...tokenFiles);
419
461
  // Copy i18n base files to the unified lib directory so that components'
@@ -424,7 +466,15 @@ export async function runInit(config, targetDir, repoUrl) {
424
466
  fs.writeFileSync(cssPath, getLocalTailwindCssTemplate(config.theme, config.fontBody, config.fontHeading, config.radius));
425
467
  }
426
468
  else {
427
- // Local mode: reference @company/tokens package
469
+ // Local mode: reference @company/tokens package. Without a registry
470
+ // to read from, we seed `cn.ts` with a minimal template — users in
471
+ // this mode are almost always developing the monorepo itself, where
472
+ // the real `@company/ui` package is resolvable via workspace links.
473
+ const cnPath = path.join(libDir, "cn.ts");
474
+ if (!fs.existsSync(cnPath)) {
475
+ fs.writeFileSync(cnPath, getCnTemplate());
476
+ filesCreated.push(`${libDirRelative}/cn.ts`);
477
+ }
428
478
  fs.writeFileSync(cssPath, getLegacyTailwindCssTemplate(config.theme, config.fontBody, config.fontHeading, config.radius));
429
479
  }
430
480
  filesCreated.push(cssRelPath);
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ const program = new Command();
17
17
  program
18
18
  .name("inai-ui")
19
19
  .description("CLI for InAI UI component library")
20
- .version("1.6.0");
20
+ .version("1.6.2");
21
21
  program
22
22
  .command("init [repo-url]")
23
23
  .description("Initialize InAI UI in your project. Optionally pass a Git repo URL to fetch components remotely.")
@@ -5,6 +5,11 @@ export declare function getRegistryCacheDir(name: string): string;
5
5
  * Clone (or fast-forward) a git registry into the legacy single-cache
6
6
  * directory. Preserved for backward compatibility with the v0.5.0
7
7
  * code path that called this directly.
8
+ *
9
+ * If a prior cache is present but refuses to fast-forward (dirty tree,
10
+ * diverged history, interrupted previous run), the cache is reset to
11
+ * match origin; if that also fails, the directory is nuked and a fresh
12
+ * clone is done. Users should never have to touch `~/.inai-ui/registry`.
8
13
  */
9
14
  export declare function cloneRegistry(repoUrl: string): string;
10
15
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"registry-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/registry-resolver.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAS7E,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAWrD;AAmBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,MAAM,CAAC,CAkGjB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAS7D"}
1
+ {"version":3,"file":"registry-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/registry-resolver.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAS7E,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AA8CD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAcrD;AAmBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,MAAM,CAAC,CA+FjB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAS7D"}
@@ -15,22 +15,71 @@ export function getCacheDir() {
15
15
  export function getRegistryCacheDir(name) {
16
16
  return path.join(REGISTRIES_CACHE_DIR, name);
17
17
  }
18
+ /**
19
+ * Attempt to refresh an existing git cache to the latest upstream state.
20
+ * Tries `git pull --ff-only` first, and if the working tree is dirty or
21
+ * has diverged from upstream (either of which aborts the fast-forward),
22
+ * falls back to a hard reset + clean so the cache matches origin exactly.
23
+ *
24
+ * The cache is an implementation detail of the CLI — users should never
25
+ * have to edit files inside it, so any local changes are unconditionally
26
+ * discarded in favor of whatever origin currently ships.
27
+ *
28
+ * Returns `true` on success, `false` if both pull and reset failed (in
29
+ * which case the caller should nuke the directory and re-clone).
30
+ */
31
+ function refreshGitCache(cacheDir) {
32
+ try {
33
+ execSync("git pull --ff-only", { cwd: cacheDir, stdio: "pipe" });
34
+ return true;
35
+ }
36
+ catch {
37
+ // Dirty tree, diverged history, or both. Salvage the clone by
38
+ // fetching fresh refs and resetting hard onto origin's default
39
+ // branch. `git clean -fd` drops any untracked files the user (or a
40
+ // previous botched run) left behind.
41
+ try {
42
+ execSync("git fetch --all --prune", { cwd: cacheDir, stdio: "pipe" });
43
+ // Derive the remote HEAD dynamically so we respect whatever branch
44
+ // origin tracks (main, master, develop, ...).
45
+ const remoteHead = execSync("git symbolic-ref refs/remotes/origin/HEAD", { cwd: cacheDir, stdio: ["pipe", "pipe", "pipe"] })
46
+ .toString()
47
+ .trim();
48
+ execSync(`git reset --hard ${remoteHead}`, {
49
+ cwd: cacheDir,
50
+ stdio: "pipe",
51
+ });
52
+ execSync("git clean -fd", { cwd: cacheDir, stdio: "pipe" });
53
+ return true;
54
+ }
55
+ catch {
56
+ return false;
57
+ }
58
+ }
59
+ }
18
60
  /**
19
61
  * Clone (or fast-forward) a git registry into the legacy single-cache
20
62
  * directory. Preserved for backward compatibility with the v0.5.0
21
63
  * code path that called this directly.
64
+ *
65
+ * If a prior cache is present but refuses to fast-forward (dirty tree,
66
+ * diverged history, interrupted previous run), the cache is reset to
67
+ * match origin; if that also fails, the directory is nuked and a fresh
68
+ * clone is done. Users should never have to touch `~/.inai-ui/registry`.
22
69
  */
23
70
  export function cloneRegistry(repoUrl) {
24
71
  if (fs.existsSync(path.join(LEGACY_CACHE_DIR, ".git"))) {
25
- execSync("git pull --ff-only", { cwd: LEGACY_CACHE_DIR, stdio: "pipe" });
26
- }
27
- else {
28
- fs.mkdirSync(CACHE_BASE, { recursive: true });
29
- if (fs.existsSync(LEGACY_CACHE_DIR)) {
30
- fs.rmSync(LEGACY_CACHE_DIR, { recursive: true });
72
+ if (refreshGitCache(LEGACY_CACHE_DIR)) {
73
+ return LEGACY_CACHE_DIR;
31
74
  }
32
- execSync(`git clone "${repoUrl}" "${LEGACY_CACHE_DIR}"`, { stdio: "pipe" });
75
+ // Salvage failed nuke and re-clone below.
76
+ fs.rmSync(LEGACY_CACHE_DIR, { recursive: true, force: true });
77
+ }
78
+ fs.mkdirSync(CACHE_BASE, { recursive: true });
79
+ if (fs.existsSync(LEGACY_CACHE_DIR)) {
80
+ fs.rmSync(LEGACY_CACHE_DIR, { recursive: true });
33
81
  }
82
+ execSync(`git clone "${repoUrl}" "${LEGACY_CACHE_DIR}"`, { stdio: "pipe" });
34
83
  return LEGACY_CACHE_DIR;
35
84
  }
36
85
  /**
@@ -89,18 +138,13 @@ export async function resolveRegistry(registry, projectDir, options = {}) {
89
138
  const cloneUrl = token ? embedTokenInGitUrl(registry.url, token) : registry.url;
90
139
  const branch = registry.branch ?? "main";
91
140
  if (fs.existsSync(path.join(cacheDir, ".git"))) {
92
- try {
93
- execSync("git pull --ff-only", { cwd: cacheDir, stdio: "pipe" });
94
- }
95
- catch {
96
- // If pull fails (network hiccup, diverged), fall back to cached copy.
141
+ if (!refreshGitCache(cacheDir)) {
142
+ // Salvage failed nuke and re-clone below.
143
+ fs.rmSync(cacheDir, { recursive: true, force: true });
97
144
  }
98
145
  }
99
- else {
146
+ if (!fs.existsSync(path.join(cacheDir, ".git"))) {
100
147
  fs.mkdirSync(REGISTRIES_CACHE_DIR, { recursive: true });
101
- if (fs.existsSync(cacheDir)) {
102
- fs.rmSync(cacheDir, { recursive: true });
103
- }
104
148
  execSync(`git clone --branch "${branch}" "${cloneUrl}" "${cacheDir}"`, { stdio: "pipe" });
105
149
  }
106
150
  return cacheDir;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inai-react-components",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "CLI for InAI UI component library — install components from a private registry into your React project",
5
5
  "private": false,
6
6
  "type": "module",