@elsapiens/cli 0.1.0 → 0.1.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.
package/README.md CHANGED
@@ -14,7 +14,10 @@ npm install -g @elsapiens/cli
14
14
 
15
15
  ## Features
16
16
 
17
- - Create new projects with elSapiens SDK
17
+ - Create new projects with complete elSapiens SDK setup
18
+ - Full AppLayout with sidebar and topbar
19
+ - All providers pre-configured (Theme, Auth, Locale, Help)
20
+ - Services ready to use (Logger, ApiClient, ShortcutManager)
18
21
  - Add pages with correct structure and patterns
19
22
  - Add components with TypeScript templates
20
23
  - Interactive prompts for configuration
@@ -28,10 +31,6 @@ npm install -g @elsapiens/cli
28
31
  # Interactive mode
29
32
  el init my-app
30
33
 
31
- # With template selection
32
- el init my-app --template minimal
33
- el init my-app --template full
34
-
35
34
  # Skip prompts
36
35
  el init my-app --yes
37
36
 
@@ -39,30 +38,45 @@ el init my-app --yes
39
38
  el init my-app --no-git
40
39
  ```
41
40
 
42
- **Templates:**
43
-
44
- | Template | Description |
45
- |----------|-------------|
46
- | `minimal` | Basic setup with single Dashboard page |
47
- | `full` | Complete setup with Dashboard, Settings, and examples |
48
-
49
- **Generated Structure (minimal):**
41
+ **Generated Structure:**
50
42
 
51
43
  ```
52
44
  my-app/
53
45
  ├── package.json
54
46
  ├── vite.config.ts
55
47
  ├── tsconfig.json
48
+ ├── tsconfig.node.json
49
+ ├── tailwind.config.js
50
+ ├── postcss.config.js
56
51
  ├── index.html
52
+ ├── .env.example
57
53
  ├── .gitignore
58
54
  └── src/
59
- ├── main.tsx
60
- ├── App.tsx
61
- ├── index.css
55
+ ├── main.tsx # All providers configured
56
+ ├── App.tsx # Full AppLayout with sidebar/topbar
57
+ ├── index.css # Design system styles
58
+ ├── help-topics.ts # Help system topics
59
+ ├── services/
60
+ │ └── index.ts # Logger, ApiClient, ShortcutManager
61
+ ├── translations/
62
+ │ └── common.ts # i18n translations
62
63
  └── pages/
63
- └── Dashboard.tsx
64
+ ├── Dashboard.tsx
65
+ └── Settings.tsx
64
66
  ```
65
67
 
68
+ **Included Features:**
69
+
70
+ | Feature | Description |
71
+ |---------|-------------|
72
+ | ThemeProvider | Dark/light mode with system detection |
73
+ | AuthProvider | Authentication context |
74
+ | LocaleProvider | Internationalization support |
75
+ | HelpProvider | Help system with keyboard shortcuts |
76
+ | AppLayout | Sidebar navigation + topbar |
77
+ | AuthGuard | Route protection |
78
+ | Services | Logger, ApiClient, ShortcutManager |
79
+
66
80
  ### Add Page
67
81
 
68
82
  ```bash
@@ -89,33 +103,6 @@ el add page Users --path src/features/users/pages
89
103
  | `list` | Data listing with search, filters, and table |
90
104
  | `settings` | Configuration page with form sections and toggles |
91
105
 
92
- **Page Structure:**
93
-
94
- All pages follow the established alignment pattern:
95
-
96
- ```tsx
97
- <div className="p-6">
98
- {/* Page Header - pl-6 to align with table spacer */}
99
- <div className="flex items-center justify-between mb-8 pl-6">
100
- <div>
101
- <h1 className="text-2xl font-bold text-foreground">Title</h1>
102
- <p className="text-muted-foreground">Description</p>
103
- </div>
104
- {/* Actions */}
105
- </div>
106
-
107
- {/* Content with Cards */}
108
- <Card padding="none">
109
- <CardHeader className="p-6">
110
- <CardTitle>Section</CardTitle>
111
- </CardHeader>
112
- <CardContent className="p-6 pt-0">
113
- {/* Content */}
114
- </CardContent>
115
- </Card>
116
- </div>
117
- ```
118
-
119
106
  ### Add Component
120
107
 
121
108
  ```bash
@@ -150,7 +137,6 @@ $ el init my-dashboard
150
137
  elSapiens CLI v0.1.0
151
138
 
152
139
  ? Project name: my-dashboard
153
- ? Select template: Minimal
154
140
  ? Initialize git repository? Yes
155
141
 
156
142
  Creating project...
@@ -160,6 +146,10 @@ Creating project...
160
146
  ✓ src/main.tsx
161
147
  ✓ src/App.tsx
162
148
  ✓ src/pages/Dashboard.tsx
149
+ ✓ src/pages/Settings.tsx
150
+ ✓ src/services/index.ts
151
+ ✓ src/translations/common.ts
152
+ ✓ src/help-topics.ts
163
153
 
164
154
  Done! Run:
165
155
  cd my-dashboard
@@ -206,7 +196,6 @@ Create a new elSapiens project.
206
196
 
207
197
  | Option | Description |
208
198
  |--------|-------------|
209
- | `-t, --template <type>` | Project template (minimal, full) |
210
199
  | `--no-git` | Skip git initialization |
211
200
  | `-y, --yes` | Skip prompts, use defaults |
212
201
 
@@ -240,7 +229,6 @@ elsapiens init my-app
240
229
  # Add command aliases
241
230
  el add page Users
242
231
  el generate page Users
243
- el g page Users
244
232
  ```
245
233
 
246
234
  ## Requirements
@@ -250,26 +238,99 @@ el g page Users
250
238
 
251
239
  ## Development
252
240
 
241
+ ### Building from Source
242
+
253
243
  ```bash
254
244
  # Clone the repository
255
245
  git clone https://github.com/elsapiens/sdk.git
256
- cd sdk/packages/cli
246
+ cd sdk
257
247
 
258
- # Install dependencies
248
+ # Install all dependencies
259
249
  pnpm install
260
250
 
261
- # Build
251
+ # Build all packages (required for CLI to work)
262
252
  pnpm build
263
253
 
264
- # Test locally
265
- node dist/index.js --help
266
- node dist/index.js init test-app
254
+ # Or build just the CLI
255
+ cd packages/cli && pnpm build
256
+ ```
257
+
258
+ ### Using CLI from Git Checkout (Without npm)
259
+
260
+ You can use the CLI directly from a git checkout without publishing to npm:
261
+
262
+ ```bash
263
+ # Create a project using the local CLI build
264
+ node /path/to/sdk/packages/cli/dist/index.js init my-project
265
+
266
+ # Or set up an alias for convenience
267
+ alias el-dev="node /path/to/sdk/packages/cli/dist/index.js"
268
+ el-dev init my-project
269
+ ```
270
+
271
+ ### Testing Template Changes
272
+
273
+ ```bash
274
+ # 1. Make changes to templates
275
+ code packages/cli/src/templates/app/page-dashboard.ejs
276
+
277
+ # 2. Rebuild the CLI
278
+ cd packages/cli && pnpm build
279
+
280
+ # 3. Create a fresh test project
281
+ rm -rf /tmp/test-project
282
+ node dist/index.js init /tmp/test-project
283
+
284
+ # 4. Test the changes
285
+ cd /tmp/test-project && pnpm install && pnpm dev
286
+ ```
287
+
288
+ ### Install Globally (One-Time Setup)
267
289
 
268
- # Link globally for testing
290
+ The easiest way to install the CLI globally from your local SDK:
291
+
292
+ ```bash
293
+ cd packages/cli
294
+
295
+ # Run the setup script (builds and links globally)
296
+ pnpm setup:global
297
+ ```
298
+
299
+ After setup, use the `el` command from anywhere:
300
+
301
+ ```bash
302
+ el init my-project
303
+ el add page Users
304
+ el add component UserCard
305
+ ```
306
+
307
+ ### Manual Linking
308
+
309
+ ```bash
310
+ cd packages/cli
311
+ pnpm build
269
312
  pnpm link --global
313
+
314
+ # Verify
270
315
  el --version
271
316
  ```
272
317
 
318
+ ### Unlink
319
+
320
+ ```bash
321
+ cd packages/cli
322
+ pnpm unlink:global
323
+ ```
324
+
325
+ ### Shell Alias (Alternative)
326
+
327
+ Add to `~/.zshrc` or `~/.bashrc`:
328
+
329
+ ```bash
330
+ export ELSDK_PATH="/path/to/elSDK"
331
+ alias el="node $ELSDK_PATH/packages/cli/dist/index.js"
332
+ ```
333
+
273
334
  ## Publishing
274
335
 
275
336
  ```bash
package/dist/index.js CHANGED
@@ -230,25 +230,6 @@ async function initCommand(projectName, options) {
230
230
  cancel2("Project creation cancelled.");
231
231
  }
232
232
  }
233
- let template = options.template;
234
- if (!options.yes) {
235
- template = await select2({
236
- message: "Select a template:",
237
- options: [
238
- {
239
- value: "minimal",
240
- label: "Minimal",
241
- hint: "Basic setup with a single Dashboard page"
242
- },
243
- {
244
- value: "full",
245
- label: "Full",
246
- hint: "Complete setup with Dashboard, Settings, and example components"
247
- }
248
- ],
249
- initialValue: template
250
- });
251
- }
252
233
  const s = spinner2();
253
234
  s.start("Creating project...");
254
235
  try {
@@ -256,8 +237,7 @@ async function initCommand(projectName, options) {
256
237
  const pascalName = toPascalCase(name);
257
238
  const packageJson = await renderApp("package", {
258
239
  projectName: name,
259
- pascalName,
260
- template
240
+ pascalName
261
241
  });
262
242
  await writeFile(path3.join(projectDir, "package.json"), packageJson);
263
243
  const viteConfig = await renderApp("vite-config", {
@@ -265,10 +245,24 @@ async function initCommand(projectName, options) {
265
245
  pascalName
266
246
  });
267
247
  await writeFile(path3.join(projectDir, "vite.config.ts"), viteConfig);
248
+ const tailwindConfig = await renderApp("tailwind-config", {
249
+ projectName: name,
250
+ pascalName
251
+ });
252
+ await writeFile(path3.join(projectDir, "tailwind.config.js"), tailwindConfig);
253
+ const postcssConfig = await renderApp("postcss-config", {
254
+ projectName: name,
255
+ pascalName
256
+ });
257
+ await writeFile(path3.join(projectDir, "postcss.config.js"), postcssConfig);
268
258
  const tsconfig = await renderApp("tsconfig", {
269
259
  projectName: name
270
260
  });
271
261
  await writeFile(path3.join(projectDir, "tsconfig.json"), tsconfig);
262
+ const tsconfigNode = await renderApp("tsconfig-node", {
263
+ projectName: name
264
+ });
265
+ await writeFile(path3.join(projectDir, "tsconfig.node.json"), tsconfigNode);
272
266
  const indexHtml = await renderApp("index-html", {
273
267
  projectName: name,
274
268
  pascalName
@@ -281,14 +275,17 @@ async function initCommand(projectName, options) {
281
275
  await writeFile(path3.join(projectDir, "src", "main.tsx"), mainTsx);
282
276
  const appTsx = await renderApp("app", {
283
277
  projectName: name,
284
- pascalName,
285
- template
278
+ pascalName
286
279
  });
287
280
  await writeFile(path3.join(projectDir, "src", "App.tsx"), appTsx);
288
281
  const indexCss = await renderApp("index-css", {
289
282
  projectName: name
290
283
  });
291
284
  await writeFile(path3.join(projectDir, "src", "index.css"), indexCss);
285
+ const viteEnv = await renderApp("vite-env", {
286
+ projectName: name
287
+ });
288
+ await writeFile(path3.join(projectDir, "src", "vite-env.d.ts"), viteEnv);
292
289
  const dashboardPage = await renderApp("page-dashboard", {
293
290
  projectName: name,
294
291
  pascalName
@@ -297,16 +294,87 @@ async function initCommand(projectName, options) {
297
294
  path3.join(projectDir, "src", "pages", "Dashboard.tsx"),
298
295
  dashboardPage
299
296
  );
300
- if (template === "full") {
301
- const settingsPage = await renderApp("page-settings", {
302
- projectName: name,
303
- pascalName
304
- });
305
- await writeFile(
306
- path3.join(projectDir, "src", "pages", "Settings.tsx"),
307
- settingsPage
308
- );
309
- }
297
+ const settingsPage = await renderApp("page-settings", {
298
+ projectName: name,
299
+ pascalName
300
+ });
301
+ await writeFile(
302
+ path3.join(projectDir, "src", "pages", "Settings.tsx"),
303
+ settingsPage
304
+ );
305
+ const translationsCommonEn = await renderApp("translations-common-en", {
306
+ projectName: name,
307
+ pascalName
308
+ });
309
+ await writeFile(
310
+ path3.join(projectDir, "src", "translations", "common", "en.ts"),
311
+ translationsCommonEn
312
+ );
313
+ const translationsCommonIndex = await renderApp("translations-common-index", {
314
+ projectName: name,
315
+ pascalName
316
+ });
317
+ await writeFile(
318
+ path3.join(projectDir, "src", "translations", "common", "index.ts"),
319
+ translationsCommonIndex
320
+ );
321
+ const translationsSettingsEn = await renderApp("translations-settings-en", {
322
+ projectName: name,
323
+ pascalName
324
+ });
325
+ await writeFile(
326
+ path3.join(projectDir, "src", "translations", "settings", "en.ts"),
327
+ translationsSettingsEn
328
+ );
329
+ const translationsSettingsIndex = await renderApp("translations-settings-index", {
330
+ projectName: name,
331
+ pascalName
332
+ });
333
+ await writeFile(
334
+ path3.join(projectDir, "src", "translations", "settings", "index.ts"),
335
+ translationsSettingsIndex
336
+ );
337
+ const helpTopics = await renderApp("help-topics", {
338
+ projectName: name,
339
+ pascalName
340
+ });
341
+ await writeFile(
342
+ path3.join(projectDir, "src", "help-topics.ts"),
343
+ helpTopics
344
+ );
345
+ const servicesSetup = await renderApp("services-setup", {
346
+ projectName: name,
347
+ pascalName
348
+ });
349
+ await writeFile(
350
+ path3.join(projectDir, "src", "services", "index.ts"),
351
+ servicesSetup
352
+ );
353
+ const envExample = await renderApp("env-example", {
354
+ projectName: name,
355
+ pascalName
356
+ });
357
+ await writeFile(path3.join(projectDir, ".env.example"), envExample);
358
+ const eslintConfig = await renderApp("eslint-config", {
359
+ projectName: name,
360
+ pascalName
361
+ });
362
+ await writeFile(path3.join(projectDir, "eslint.config.js"), eslintConfig);
363
+ const vitestConfig = await renderApp("vitest-config", {
364
+ projectName: name,
365
+ pascalName
366
+ });
367
+ await writeFile(path3.join(projectDir, "vitest.config.ts"), vitestConfig);
368
+ const testSetup = await renderApp("test-setup", {
369
+ projectName: name,
370
+ pascalName
371
+ });
372
+ await writeFile(path3.join(projectDir, "src", "test", "setup.ts"), testSetup);
373
+ const huskyPreCommit = await renderApp("husky-pre-commit", {
374
+ projectName: name,
375
+ pascalName
376
+ });
377
+ await writeFile(path3.join(projectDir, ".husky", "pre-commit"), huskyPreCommit);
310
378
  const gitignore = `# Dependencies
311
379
  node_modules/
312
380
 
@@ -331,6 +399,9 @@ Thumbs.db
331
399
  # Logs
332
400
  *.log
333
401
  npm-debug.log*
402
+
403
+ # Coverage
404
+ coverage/
334
405
  `;
335
406
  await writeFile(path3.join(projectDir, ".gitignore"), gitignore);
336
407
  s.stop("Project created!");
@@ -341,8 +412,10 @@ npm-debug.log*
341
412
  });
342
413
  if (initGit) {
343
414
  try {
344
- execSync("git init", { cwd: projectDir, stdio: "ignore" });
345
- logger.success("Git repository initialized");
415
+ execSync("git init -b main", { cwd: projectDir, stdio: "ignore" });
416
+ execSync("git add .", { cwd: projectDir, stdio: "ignore" });
417
+ execSync('git commit -m "Initial commit"', { cwd: projectDir, stdio: "ignore" });
418
+ logger.success("Git repository initialized with initial commit");
346
419
  } catch {
347
420
  logger.warn("Failed to initialize git repository");
348
421
  }
@@ -550,7 +623,7 @@ var VERSION = "0.1.0";
550
623
  function createCli() {
551
624
  const program = new Command();
552
625
  program.name("elsapiens").description("CLI scaffolding tool for elSapiens SDK projects").version(VERSION, "-v, --version", "Display version number");
553
- program.command("init [project-name]").alias("create").description("Create a new elSapiens project").option("-t, --template <type>", "Project template (minimal or full)", "minimal").option("--no-git", "Skip git initialization").option("-y, --yes", "Skip prompts and use defaults").action(initCommand);
626
+ program.command("init [project-name]").alias("create").description("Create a new elSapiens project with full setup").option("--no-git", "Skip git initialization").option("-y, --yes", "Skip prompts and use defaults").action(initCommand);
554
627
  program.command("add").alias("generate").alias("g").description("Add a page or component to the project").addCommand(
555
628
  new Command("page").argument("[name]", "Page name").description("Add a new page").option("-t, --template <type>", "Page template (dashboard, list, settings)", "dashboard").option("-p, --path <dir>", "Custom pages directory").action(addCommand.page)
556
629
  ).addCommand(