@nikala-ui/cli 0.11.0 → 0.12.1

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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Giorgi Magradze
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO QUALITY AND FITNESS FOR A PARTICULAR
17
+ PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,48 +1,194 @@
1
1
  # @nikala-ui/cli
2
2
 
3
- Command Line Interface (CLI) for **Nikala UI** a copy-paste component system for **SolidJS** built natively for **Tailwind CSS v4**.
3
+ The Nikala UI CLI initializes SolidJS projects and copies Nikala UI components, application blocks, and reactive hooks directly into the consuming project. It is designed for Tailwind CSS v4 and a local source ownership workflow.
4
4
 
5
- Honoring the iconic Georgian painter **Niko Pirosmani (Nikala)**.
5
+ Nikala UI honors the work of Georgian painter Niko Pirosmani (Nikala).
6
6
 
7
- Official Documentation & Interactive Demos: [nikala.dev](https://nikala.dev)
7
+ Documentation and interactive examples: [nikala.dev](https://nikala.dev)
8
8
 
9
- ---
9
+ ## Installation
10
10
 
11
- ## Installation & Usage
11
+ Run the CLI without installing it globally:
12
12
 
13
- Execute directly using your preferred package manager:
13
+ ```bash
14
+ bunx @nikala-ui/cli <command>
15
+ ```
16
+
17
+ The package also exposes the `nikala` binary when installed as a project dependency.
18
+
19
+ ## Initialize a project
20
+
21
+ Run `init` from the root of a SolidJS project:
22
+
23
+ ```bash
24
+ bunx @nikala-ui/cli init
25
+ ```
26
+
27
+ Initialization creates or updates the Nikala project configuration, path aliases, Tailwind CSS v4 theme tokens, and the local `cn` helper. It installs the runtime and styling dependencies required by the generated setup.
28
+
29
+ Options:
30
+
31
+ ```bash
32
+ # Skip interactive prompts and use defaults
33
+ bunx @nikala-ui/cli init --defaults
34
+
35
+ # Skip dependency installation
36
+ bunx @nikala-ui/cli init --skip-dependencies
37
+
38
+ # Generate AI assistant rules
39
+ bunx @nikala-ui/cli init --ai
40
+ ```
41
+
42
+ AI rules can also be generated or updated independently:
43
+
44
+ ```bash
45
+ bunx @nikala-ui/cli rules
46
+ bunx @nikala-ui/cli ai
47
+ ```
48
+
49
+ ## Add components, blocks, and hooks
50
+
51
+ Add one or more UI components:
14
52
 
15
53
  ```bash
16
- # Add components
17
54
  bunx @nikala-ui/cli add button dialog
55
+ ```
56
+
57
+ Add reactive hooks with `--hook` or `-h`:
58
+
59
+ ```bash
60
+ bunx @nikala-ui/cli add --hook create-clipboard create-debounce
61
+ bunx @nikala-ui/cli add -h create-scroll-into-view
62
+ ```
63
+
64
+ Add marketing or application blocks with `--block` or `-b`:
65
+
66
+ ```bash
67
+ bunx @nikala-ui/cli add --block hero-01
68
+ ```
69
+
70
+ If no item names are provided, the CLI opens an interactive searchable selector. Dependencies declared by the selected registry items are installed automatically.
71
+
72
+ Options:
73
+
74
+ ```bash
75
+ # Add every available item in the selected category
76
+ bunx @nikala-ui/cli add --all
77
+
78
+ # Overwrite existing local files
79
+ bunx @nikala-ui/cli add button --overwrite
80
+ ```
81
+
82
+ The CLI copies source files into the configured local directories. The project owns those files and can modify them without importing a runtime Nikala UI component package.
83
+
84
+ ## Upgrade installed items
85
+
86
+ Upgrade selected locally installed components or hooks to the latest registry versions:
87
+
88
+ ```bash
89
+ bunx @nikala-ui/cli upgrade button
90
+ bunx @nikala-ui/cli update button
91
+ bunx @nikala-ui/cli upgrade --all
92
+ ```
93
+
94
+ `update` is an alias for `upgrade`. Without item names, the CLI opens a selector containing installed items.
18
95
 
19
- # Upgrade / update installed components & hooks to latest registry versions
20
- bunx @nikala-ui/cli upgrade
21
- bunx @nikala-ui/cli update button --all
96
+ ## Remove installed items
22
97
 
23
- # Remove / uninstall installed components or hooks
98
+ Remove local components or hooks:
99
+
100
+ ```bash
24
101
  bunx @nikala-ui/cli remove button
25
- bunx @nikala-ui/cli uninstall -h create-clipboard
102
+ bunx @nikala-ui/cli uninstall button
103
+ bunx @nikala-ui/cli clean --hook create-clipboard
104
+ ```
26
105
 
27
- # Initialize project
28
- bunx @nikala-ui/cli init
106
+ Options:
107
+
108
+ ```bash
109
+ # Remove hooks instead of UI components
110
+ bunx @nikala-ui/cli remove -h create-clipboard
111
+
112
+ # Remove all items in the selected category
113
+ bunx @nikala-ui/cli remove --all
29
114
  ```
30
115
 
31
- ---
116
+ The CLI asks for confirmation before deleting local source files. `uninstall` and `clean` are aliases for `remove`.
32
117
 
33
- ## Available Commands
118
+ ## List registry items
34
119
 
35
- - `nikala init` Initializes configuration, `@` path aliases, and Tailwind CSS v4 variables.
36
- - `nikala add` — Interactive searchable multiselect menu for component installation.
37
- - `nikala validate` (or `nikala doctor`) — Runs health diagnostics on workspace configuration, packages, and CSS design tokens.
38
- - `nikala diff` — Inspects line-by-line code differences between local components and upstream registry manifests.
39
- - `nikala theme set [primary] [base]` — Customizes primary brand accent colors and base gray palettes directly from the terminal.
120
+ List available registry items and show which ones are installed locally:
40
121
 
41
- ---
122
+ ```bash
123
+ bunx @nikala-ui/cli list
124
+ bunx @nikala-ui/cli ls
125
+ ```
126
+
127
+ Filters and output options:
128
+
129
+ ```bash
130
+ bunx @nikala-ui/cli list --installed
131
+ bunx @nikala-ui/cli list --component
132
+ bunx @nikala-ui/cli list --block
133
+ bunx @nikala-ui/cli list --hook
134
+ bunx @nikala-ui/cli list --json
135
+ ```
136
+
137
+ ## Customize the theme
138
+
139
+ Open the interactive theme selector:
140
+
141
+ ```bash
142
+ bunx @nikala-ui/cli theme
143
+ ```
42
144
 
43
- ## Documentation
145
+ Set the primary accent and base palette directly:
146
+
147
+ ```bash
148
+ bunx @nikala-ui/cli theme set amber zinc
149
+ ```
150
+
151
+ The command updates the local Tailwind CSS v4 design tokens defined by the project setup.
152
+
153
+ ## Validate a project
154
+
155
+ Run diagnostics for the Nikala configuration, required dependencies, and CSS design tokens:
156
+
157
+ ```bash
158
+ bunx @nikala-ui/cli validate
159
+ bunx @nikala-ui/cli doctor
160
+ ```
161
+
162
+ `doctor` is an alias for `validate`.
163
+
164
+ ## Inspect local differences
165
+
166
+ Compare a locally installed component with its current registry source:
167
+
168
+ ```bash
169
+ bunx @nikala-ui/cli diff button
170
+ bunx @nikala-ui/cli diff
171
+ ```
172
+
173
+ The command prints line-by-line differences between local source files and the latest registry manifest.
174
+
175
+ ## Local project structure
176
+
177
+ After initialization and component installation, a typical project contains:
178
+
179
+ ```text
180
+ src/
181
+ ├── components/
182
+ │ ├── blocks/
183
+ │ └── ui/
184
+ ├── hooks/
185
+ ├── index.css
186
+ └── lib/
187
+ └── cn.ts
188
+ nikala.config.json
189
+ ```
44
190
 
45
- For full documentation, component lists, and theming guides, visit the official repository at [github.com/nikala-ui/ui](https://github.com/nikala-ui/ui).
191
+ The exact directories are controlled by `nikala.config.json`. Components, blocks, and hooks remain local source files that can be customized by the project owner.
46
192
 
47
193
  ## License
48
194
 
@@ -61,9 +61,6 @@ export async function add(components = [], options = {}) {
61
61
  const componentsDir = path.resolve(cwd, config.alias.components);
62
62
  console.log(pc.cyan(`\n🎨 Adding items to project...\n`));
63
63
  const requiredNpmDeps = new Set();
64
- if (isHookMode) {
65
- requiredNpmDeps.add("@nikala-ui/hooks");
66
- }
67
64
  for (const target of resolvedTargets) {
68
65
  const item = await getRegistryItem(target, config.registries);
69
66
  if (!item) {
@@ -1,6 +1,7 @@
1
1
  interface InitOptions {
2
2
  defaults?: boolean;
3
3
  ai?: boolean;
4
+ skipDependencies?: boolean;
4
5
  }
5
6
  /**
6
7
  * Initializes Nikala UI workspace configuration and sets up design tokens.
@@ -101,8 +101,10 @@ export async function init(options) {
101
101
  else {
102
102
  requiredDeps.push("tailwindcss", "@tailwindcss/vite");
103
103
  }
104
- console.log(pc.yellow("\n📦 Installing required runtime & Tailwind CSS dependencies..."));
105
- await installDependencies(requiredDeps, cwd);
104
+ if (!options.skipDependencies) {
105
+ console.log(pc.yellow("\n📦 Installing required runtime & Tailwind CSS dependencies..."));
106
+ await installDependencies(requiredDeps, cwd);
107
+ }
106
108
  // 2. Configure path aliases
107
109
  await configureAliases(cwd);
108
110
  // 3. Generate cn.ts helper
package/dist/index.js CHANGED
@@ -10,18 +10,19 @@ import { upgradeCommand } from "./commands/upgrade.js";
10
10
  import { removeCommand } from "./commands/remove.js";
11
11
  import { listCommand } from "./commands/list.js";
12
12
  import { setupAiRules } from "./utils/init/setup-ai-rules.js";
13
- console.log(`\n🎨 ${pc.bold(pc.red("Nikala UI"))} ${pc.dim("v0.11.0")} — SolidJS + Tailwind v4 components`);
13
+ console.log(`\n🎨 ${pc.bold(pc.red("Nikala UI"))} ${pc.dim("v0.12.1")} — SolidJS + Tailwind v4 components`);
14
14
  console.log(` ${pc.italic(pc.dim("Honoring Niko Pirosmani (Nikala)"))}\n`);
15
15
  console.log(` ${pc.dim("Docs:")} ${pc.underline(pc.cyan("https://nikala.dev"))}\n`);
16
16
  const program = new Command();
17
17
  program
18
18
  .name("nikala")
19
19
  .description("Nikala UI — SolidJS + Tailwind v4 components")
20
- .version("0.11.0");
20
+ .version("0.12.1");
21
21
  program
22
22
  .command("init")
23
23
  .description("Initialize Nikala UI in your project")
24
24
  .option("-d, --defaults", "Skip prompts and use defaults")
25
+ .option("--skip-dependencies", "Skip dependency installation (used by higher-level tooling)")
25
26
  .option("--ai", "Generate AI assistant rules (.cursor/rules/nikala.mdc, .cursorrules, AGENTS.md)")
26
27
  .action(init);
27
28
  program
@@ -12,36 +12,43 @@ export async function configureAliases(cwd) {
12
12
  if (await fs.pathExists(targetConfigPath)) {
13
13
  let configContent = await fs.readFile(targetConfigPath, "utf-8");
14
14
  let modified = false;
15
+ // 1. Inject Tailwind CSS v4 Vite plugin if missing
15
16
  if (!configContent.includes("@tailwindcss/vite")) {
16
17
  configContent = `import tailwindcss from "@tailwindcss/vite";\n${configContent}`;
17
18
  if (configContent.includes("plugins: [")) {
18
19
  configContent = configContent.replace("plugins: [", "plugins: [\n tailwindcss(), ");
20
+ modified = true;
19
21
  }
20
- else if (configContent.includes("defineConfig({")) {
21
- configContent = configContent.replace("defineConfig({", "defineConfig({\n plugins: [tailwindcss()],");
22
+ else {
23
+ const defineConfigRegex = /(defineConfig\s*\(\s*(?:async\s*)?(?:\([^)]*\)\s*=>\s*)?\{)/;
24
+ if (defineConfigRegex.test(configContent)) {
25
+ configContent = configContent.replace(defineConfigRegex, "$1\n plugins: [tailwindcss()],");
26
+ modified = true;
27
+ }
22
28
  }
23
- modified = true;
24
29
  }
30
+ // 2. Inject path alias (@ -> ./src)
25
31
  if (!configContent.includes('"@"') && !configContent.includes("'@'")) {
26
32
  if (!configContent.includes('import path from "node:path"') && !configContent.includes('import path from "path"')) {
27
33
  configContent = `import path from "node:path";\n${configContent}`;
28
34
  }
29
- if (configContent.includes("defineConfig({")) {
30
- configContent = configContent.replace("defineConfig({", `defineConfig({\n resolve: {\n alias: {\n "@": path.resolve(__dirname, "./src"),\n },\n },`);
35
+ const defineConfigRegex = /(defineConfig\s*\(\s*(?:async\s*)?(?:\([^)]*\)\s*=>\s*)?\{)/;
36
+ if (defineConfigRegex.test(configContent)) {
37
+ configContent = configContent.replace(defineConfigRegex, `$1\n resolve: {\n alias: {\n "@": path.resolve(process.cwd(), "./src"),\n },\n },`);
38
+ modified = true;
31
39
  }
32
- modified = true;
33
40
  }
34
41
  if (modified) {
35
42
  await fs.writeFile(targetConfigPath, configContent, "utf-8");
36
43
  console.log(pc.green(`✓ Configured Tailwind CSS v4 plugin and path alias in ${path.basename(targetConfigPath)}`));
37
44
  }
38
45
  }
46
+ // 3. Configure tsconfig.json path mappings (@/* -> ./src/*)
39
47
  const tsconfigPath = path.join(cwd, "tsconfig.json");
40
48
  if (await fs.pathExists(tsconfigPath)) {
41
49
  const tsconfig = await readTsConfig(cwd);
42
50
  if (tsconfig) {
43
51
  tsconfig.compilerOptions = tsconfig.compilerOptions || {};
44
- tsconfig.compilerOptions.baseUrl = ".";
45
52
  tsconfig.compilerOptions.paths = tsconfig.compilerOptions.paths || {};
46
53
  // Correct path mapping with leading relative dot ./src/*
47
54
  tsconfig.compilerOptions.paths["@/*"] = ["./src/*"];
package/dist/utils/pkg.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import fs from "fs-extra";
2
2
  import path from "node:path";
3
- import { execSync } from "node:child_process";
3
+ import { execFileSync } from "node:child_process";
4
4
  import pc from "picocolors";
5
5
  import stripJsonComments from "strip-json-comments";
6
+ // Standard npm package name regex validator (supports scoped packages and version specifiers)
7
+ const NPM_PACKAGE_REGEX = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*(@[a-zA-Z0-9^~.*><=-]+)?$/;
6
8
  /**
7
9
  * Detects the package manager used in the target project workspace by checking lockfiles.
8
10
  *
@@ -47,27 +49,16 @@ export async function installDependencies(dependencies, cwd = process.cwd()) {
47
49
  // Failed to parse original package.json
48
50
  }
49
51
  }
50
- const depsString = dependencies.join(" ");
51
- let command = "";
52
- switch (pkgManager) {
53
- case "bun":
54
- command = `bun add ${depsString}`;
55
- break;
56
- case "pnpm":
57
- command = `pnpm add ${depsString}`;
58
- break;
59
- case "yarn":
60
- command = `yarn add ${depsString}`;
61
- break;
62
- case "npm":
63
- default:
64
- command = `npm install ${depsString}`;
65
- break;
66
- }
52
+ // Validate and sanitize dependency names to prevent any shell metacharacter injection
53
+ const validDeps = dependencies.filter((dep) => NPM_PACKAGE_REGEX.test(dep));
54
+ if (validDeps.length === 0)
55
+ return;
56
+ const subCommand = pkgManager === "npm" ? "install" : "add";
57
+ const args = [subCommand, ...validDeps];
67
58
  console.log(pc.yellow(`\n📦 Installing required component dependencies (${pkgManager})...`));
68
- console.log(pc.white(` ${command}\n`));
59
+ console.log(pc.white(` ${pkgManager} ${args.join(" ")}\n`));
69
60
  try {
70
- execSync(command, { cwd, stdio: "inherit" });
61
+ execFileSync(pkgManager, args, { cwd, stdio: "inherit" });
71
62
  // 2. Validate package.json integrity after installation and restore stripped fields if necessary
72
63
  if (originalPkgJson && (await fs.pathExists(pkgPath))) {
73
64
  try {
@@ -97,6 +88,6 @@ export async function installDependencies(dependencies, cwd = process.cwd()) {
97
88
  }
98
89
  catch (error) {
99
90
  console.log(pc.red(`❌ Failed to install dependencies automatically.`));
100
- console.log(pc.yellow(` Please run manually: ${command}`));
91
+ console.log(pc.yellow(` Please run manually: ${pkgManager} ${args.join(" ")}`));
101
92
  }
102
93
  }
@@ -171,16 +171,16 @@ export const PRIMARY_COLORS = {
171
171
  },
172
172
  },
173
173
  yellow: {
174
- light: "oklch(0.75 0.18 90)",
175
- dark: "oklch(0.82 0.16 90)",
174
+ light: "oklch(0.795 0.184 86.047)",
175
+ dark: "oklch(0.852 0.199 91.936)",
176
176
  lightFg: "oklch(0.1450 0 0)",
177
177
  darkFg: "oklch(0.1450 0 0)",
178
178
  charts: {
179
- chart1: "oklch(0.82 0.18 90)",
180
- chart2: "oklch(0.72 0.16 80)",
181
- chart3: "oklch(0.62 0.14 100)",
182
- chart4: "oklch(0.88 0.12 95)",
183
- chart5: "oklch(0.52 0.15 85)",
179
+ chart1: "oklch(0.795 0.184 86.047)",
180
+ chart2: "oklch(0.65 0.16 50)",
181
+ chart3: "oklch(0.55 0.15 85)",
182
+ chart4: "oklch(0.85 0.12 60)",
183
+ chart5: "oklch(0.45 0.14 75)",
184
184
  },
185
185
  },
186
186
  lime: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nikala-ui/cli",
3
- "version": "0.11.0",
3
+ "version": "0.12.1",
4
4
  "description": "Command line interface for Nikala UI",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",