create-kimesh 0.1.0-nightly.20260120063147 → 0.1.0-nightly.20260120082346

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.d.ts CHANGED
@@ -1,2 +1,144 @@
1
- import { main$1 as main } from "./main-DQV-uvOc.js";
2
- export { main };
1
+ import { main$1 as main } from "./main-BD9ZzEkl.js";
2
+
3
+ //#region src/types.d.ts
4
+ /**
5
+ * Module metadata for CLI display and dependency resolution
6
+ */
7
+ interface ModuleDefinition {
8
+ /** Unique identifier matching npm package suffix */
9
+ id: string;
10
+ /** Display name for prompts */
11
+ label: string;
12
+ /** Short description shown in multiselect */
13
+ hint: string;
14
+ /** NPM package name */
15
+ npmPackage: string;
16
+ /** Module IDs this module depends on */
17
+ dependsOn?: string[];
18
+ /** Order priority for installation - lower = first */
19
+ installOrder: number;
20
+ }
21
+ /**
22
+ * Result of dependency resolution
23
+ */
24
+ interface ResolvedModules {
25
+ /** Modules to install - in dependency order */
26
+ modules: ModuleDefinition[];
27
+ /** Modules that were auto-added due to dependencies */
28
+ autoAdded: ModuleDefinition[];
29
+ }
30
+ /**
31
+ * User options collected from prompts
32
+ */
33
+ interface CreateOptions {
34
+ /** Project directory name */
35
+ projectName: string;
36
+ /** Resolved absolute path to project directory */
37
+ projectPath: string;
38
+ /** Template to scaffold from */
39
+ template: string;
40
+ /** Selected modules to install */
41
+ modules: string[];
42
+ /** Force override existing directory */
43
+ force: boolean;
44
+ }
45
+ /**
46
+ * Directory conflict resolution action
47
+ */
48
+ type ConflictAction = "override" | "different" | "abort";
49
+ //#endregion
50
+ //#region src/modules/registry.d.ts
51
+ /**
52
+ * Available modules for create-kimesh
53
+ */
54
+ declare const AVAILABLE_MODULES: ModuleDefinition[];
55
+ /**
56
+ * Get module by ID
57
+ */
58
+ declare function getModule(id: string): ModuleDefinition | undefined;
59
+ /**
60
+ * Get all module IDs
61
+ */
62
+ declare function getModuleIds(): string[];
63
+ /**
64
+ * Check if a module ID is valid
65
+ */
66
+ declare function isValidModuleId(id: string): boolean;
67
+ /**
68
+ * Parse comma-separated module string into array of valid module IDs
69
+ */
70
+ declare function parseModulesArg(modules: string): string[];
71
+ //#endregion
72
+ //#region src/modules/resolver.d.ts
73
+ /**
74
+ * Resolve module dependencies and return ordered list
75
+ *
76
+ * @param selectedIds - Array of module IDs selected by the user
77
+ * @returns ResolvedModules with ordered modules and auto-added dependencies
78
+ */
79
+ declare function resolveModules(selectedIds: string[]): ResolvedModules;
80
+ /**
81
+ * Check if a module has unmet dependencies in the selection
82
+ */
83
+ declare function hasUnmetDependencies(moduleId: string, selectedIds: string[]): string[];
84
+ /**
85
+ * Get display string for module with dependency info
86
+ */
87
+ declare function getModuleDisplayHint(module: ModuleDefinition): string;
88
+ //#endregion
89
+ //#region src/prompts/project-name.d.ts
90
+ /**
91
+ * Validate a project name
92
+ * @returns true if valid, error message string if invalid
93
+ */
94
+ declare function validateProjectName(name: string): true | string;
95
+ /**
96
+ * Prompt the user for a project name
97
+ *
98
+ * @param defaultName - Default project name to suggest
99
+ * @returns The validated project name
100
+ */
101
+ declare function promptProjectName(defaultName?: string): Promise<string>;
102
+ //#endregion
103
+ //#region src/prompts/directory-conflict.d.ts
104
+ /**
105
+ * Prompt user to resolve a directory conflict
106
+ *
107
+ * @param dirname - The name of the existing directory
108
+ * @returns The chosen action: 'override', 'different', or 'abort'
109
+ */
110
+ declare function promptDirectoryConflict(dirname: string): Promise<ConflictAction>;
111
+ /**
112
+ * Prompt user for a new directory name
113
+ *
114
+ * @param currentName - The current (conflicting) name
115
+ * @returns The new directory name
116
+ */
117
+ declare function promptNewDirectoryName(currentName: string): Promise<string>;
118
+ //#endregion
119
+ //#region src/prompts/module-selection.d.ts
120
+ /**
121
+ * Prompt user to select modules from the available list
122
+ *
123
+ * @returns Array of selected module IDs
124
+ */
125
+ declare function promptModuleSelection(): Promise<string[]>;
126
+ //#endregion
127
+ //#region src/scaffold/index.d.ts
128
+ interface ScaffoldOptions {
129
+ projectPath: string;
130
+ projectName: string;
131
+ template: string;
132
+ modules: ModuleDefinition[];
133
+ override: boolean;
134
+ }
135
+ interface ScaffoldResult {
136
+ success: boolean;
137
+ error?: string;
138
+ }
139
+ /**
140
+ * Scaffold a new Kimesh project with the given options
141
+ */
142
+ declare function scaffoldProject(options: ScaffoldOptions): Promise<ScaffoldResult>;
143
+ //#endregion
144
+ export { AVAILABLE_MODULES, ConflictAction, CreateOptions, ModuleDefinition, ResolvedModules, ScaffoldOptions, ScaffoldResult, getModule, getModuleDisplayHint, getModuleIds, hasUnmetDependencies, isValidModuleId, main, parseModulesArg, promptDirectoryConflict, promptModuleSelection, promptNewDirectoryName, promptProjectName, resolveModules, scaffoldProject, validateProjectName };
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import { main } from "./main-CXj_0-LW.js";
1
+ import { AVAILABLE_MODULES, getModule, getModuleDisplayHint, getModuleIds, hasUnmetDependencies, isValidModuleId, main, parseModulesArg, promptDirectoryConflict, promptModuleSelection, promptNewDirectoryName, promptProjectName, resolveModules, scaffoldProject, validateProjectName } from "./main-DgdkY0zh.js";
2
2
 
3
- export { main };
3
+ export { AVAILABLE_MODULES, getModule, getModuleDisplayHint, getModuleIds, hasUnmetDependencies, isValidModuleId, main, parseModulesArg, promptDirectoryConflict, promptModuleSelection, promptNewDirectoryName, promptProjectName, resolveModules, scaffoldProject, validateProjectName };
@@ -12,6 +12,17 @@ declare const main: citty0.CommandDef<{
12
12
  description: string;
13
13
  alias: string;
14
14
  };
15
+ force: {
16
+ type: "boolean";
17
+ description: string;
18
+ alias: string;
19
+ default: false;
20
+ };
21
+ modules: {
22
+ type: "string";
23
+ description: string;
24
+ alias: string;
25
+ };
15
26
  }>;
16
27
  //#endregion
17
28
  export { main as main$1 };
@@ -0,0 +1,712 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join, resolve } from "node:path";
3
+ import { defineCommand } from "citty";
4
+ import consola from "consola";
5
+ import pc from "picocolors";
6
+ import { mkdir, rm, writeFile } from "node:fs/promises";
7
+
8
+ //#region src/scaffold/index.ts
9
+ /**
10
+ * Scaffold a new Kimesh project with the given options
11
+ */
12
+ async function scaffoldProject(options) {
13
+ const { projectPath, projectName, modules, override } = options;
14
+ try {
15
+ if (existsSync(projectPath)) if (override) await rm(projectPath, {
16
+ recursive: true,
17
+ force: true
18
+ });
19
+ else return {
20
+ success: false,
21
+ error: `Directory "${projectPath}" already exists`
22
+ };
23
+ await mkdir(projectPath, { recursive: true });
24
+ const packageJson = generatePackageJson(projectName, modules);
25
+ await writeFile(join(projectPath, "package.json"), JSON.stringify(packageJson, null, 2));
26
+ const kimeshConfig = generateKimeshConfig(modules);
27
+ await writeFile(join(projectPath, "kimesh.config.ts"), kimeshConfig);
28
+ const tsconfig = generateTsConfig();
29
+ await writeFile(join(projectPath, "tsconfig.json"), JSON.stringify(tsconfig, null, 2));
30
+ await mkdir(join(projectPath, "src", "routes"), { recursive: true });
31
+ await mkdir(join(projectPath, "src", "components"), { recursive: true });
32
+ await mkdir(join(projectPath, "src", "composables"), { recursive: true });
33
+ await writeFile(join(projectPath, "src", "app.vue"), generateAppVue(modules));
34
+ await writeFile(join(projectPath, "src", "app.css"), generateAppCss(modules));
35
+ await writeFile(join(projectPath, "src", "routes", "__root.vue"), generateRootLayout());
36
+ await writeFile(join(projectPath, "src", "routes", "index.vue"), generateIndexRoute());
37
+ for (const module of modules) if (module.id === "pinia") await scaffoldPinia(projectPath);
38
+ await writeFile(join(projectPath, ".gitignore"), generateGitignore());
39
+ return { success: true };
40
+ } catch (error) {
41
+ return {
42
+ success: false,
43
+ error: error instanceof Error ? error.message : String(error)
44
+ };
45
+ }
46
+ }
47
+ function generatePackageJson(projectName, modules) {
48
+ const dependencies = {
49
+ vue: "^3.5.0",
50
+ "vue-router": "^4.4.0"
51
+ };
52
+ const devDependencies = {
53
+ kimesh: "workspace:*",
54
+ typescript: "^5.7.0",
55
+ vite: "^6.0.0",
56
+ "@types/node": "^22.0.0"
57
+ };
58
+ for (const module of modules) {
59
+ if (module.id === "tailwindcss") {
60
+ devDependencies["tailwindcss"] = "^4.0.0";
61
+ devDependencies["@tailwindcss/vite"] = "^4.0.0";
62
+ devDependencies["@kimesh/tailwindcss"] = "workspace:*";
63
+ }
64
+ if (module.id === "pinia") {
65
+ dependencies["pinia"] = "^3.0.0";
66
+ devDependencies["@kimesh/pinia"] = "workspace:*";
67
+ }
68
+ }
69
+ return {
70
+ name: projectName,
71
+ version: "0.0.0",
72
+ private: true,
73
+ type: "module",
74
+ scripts: {
75
+ dev: "km dev",
76
+ build: "km build",
77
+ "km:prepare": "km prepare"
78
+ },
79
+ dependencies,
80
+ devDependencies
81
+ };
82
+ }
83
+ function generateKimeshConfig(modules) {
84
+ const imports = [];
85
+ const moduleStrings = [];
86
+ const moduleOptions = [];
87
+ for (const module of modules) {
88
+ if (module.id === "tailwindcss") {
89
+ imports.push("import tailwindcss from \"@tailwindcss/vite\";");
90
+ moduleStrings.push("\"@kimesh/tailwindcss\"");
91
+ moduleOptions.push(`
92
+ tailwindcss: {
93
+ autoReference: true,
94
+ mainCss: "src/app.css",
95
+ },`);
96
+ }
97
+ if (module.id === "pinia") moduleStrings.push("\"@kimesh/pinia\"");
98
+ }
99
+ const importsSection = imports.length > 0 ? `${imports.join("\n")}\n\n` : "";
100
+ const modulesSection = moduleStrings.length > 0 ? `\n modules: [${moduleStrings.join(", ")}],` : "";
101
+ const moduleOptionsSection = moduleOptions.join("");
102
+ const vitePlugins = imports.length > 0 ? `\n\n vite: {\n plugins: [tailwindcss()],\n },` : "";
103
+ return `import { defineKmConfig } from "@kimesh/kit";
104
+ ${importsSection}export default defineKmConfig({
105
+ name: "kimesh-app",${modulesSection}
106
+
107
+ app: {
108
+ head: {
109
+ title: "Kimesh App",
110
+ titleTemplate: "%s | Kimesh",
111
+ meta: [
112
+ { charset: "utf-8" },
113
+ { name: "viewport", content: "width=device-width, initial-scale=1" },
114
+ ],
115
+ htmlAttrs: {
116
+ lang: "en",
117
+ },
118
+ },
119
+ },${moduleOptionsSection}${vitePlugins}
120
+ });
121
+ `;
122
+ }
123
+ function generateTsConfig() {
124
+ return {
125
+ compilerOptions: {
126
+ target: "ES2022",
127
+ module: "ESNext",
128
+ moduleResolution: "bundler",
129
+ strict: true,
130
+ jsx: "preserve",
131
+ resolveJsonModule: true,
132
+ isolatedModules: true,
133
+ esModuleInterop: true,
134
+ skipLibCheck: true,
135
+ baseUrl: ".",
136
+ paths: { "@/*": ["./src/*"] }
137
+ },
138
+ include: ["src/**/*.ts", "src/**/*.vue"],
139
+ exclude: ["node_modules"]
140
+ };
141
+ }
142
+ function generateAppVue(modules) {
143
+ const hasTailwind = modules.some((m) => m.id === "tailwindcss");
144
+ const cssImport = hasTailwind ? "\nimport \"./app.css\";" : "";
145
+ return `<script setup lang="ts">
146
+ import { KmOutlet } from "@kimesh/router-runtime";${cssImport}
147
+ </script>
148
+
149
+ <template>
150
+ <div id="app">
151
+ <KmOutlet />
152
+ </div>
153
+ </template>
154
+ `;
155
+ }
156
+ function generateAppCss(modules) {
157
+ const hasTailwind = modules.some((m) => m.id === "tailwindcss");
158
+ if (hasTailwind) return `@import "tailwindcss";
159
+
160
+ /* Custom styles */
161
+ `;
162
+ return `/* Global styles */
163
+ * {
164
+ box-sizing: border-box;
165
+ margin: 0;
166
+ padding: 0;
167
+ }
168
+
169
+ body {
170
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
171
+ line-height: 1.6;
172
+ color: #333;
173
+ }
174
+
175
+ a {
176
+ color: #42b883;
177
+ text-decoration: none;
178
+ }
179
+
180
+ a:hover {
181
+ text-decoration: underline;
182
+ }
183
+ `;
184
+ }
185
+ function generateRootLayout() {
186
+ return `<script lang="ts">
187
+ import { createFileRoute } from "@kimesh/router-runtime";
188
+
189
+ export const Route = createFileRoute("__root")({
190
+ head: {
191
+ // Root layout head config
192
+ },
193
+ });
194
+ </script>
195
+
196
+ <script setup lang="ts">
197
+ import { KmOutlet, KmLink } from "@kimesh/router-runtime";
198
+ </script>
199
+
200
+ <template>
201
+ <div class="layout">
202
+ <header>
203
+ <nav>
204
+ <KmLink to="/">Home</KmLink>
205
+ </nav>
206
+ </header>
207
+ <main>
208
+ <KmOutlet />
209
+ </main>
210
+ </div>
211
+ </template>
212
+
213
+ <style scoped>
214
+ .layout {
215
+ min-height: 100vh;
216
+ display: flex;
217
+ flex-direction: column;
218
+ }
219
+
220
+ header {
221
+ padding: 1rem 2rem;
222
+ border-bottom: 1px solid #eee;
223
+ }
224
+
225
+ nav {
226
+ display: flex;
227
+ gap: 1rem;
228
+ }
229
+
230
+ main {
231
+ flex: 1;
232
+ padding: 2rem;
233
+ max-width: 1200px;
234
+ margin: 0 auto;
235
+ width: 100%;
236
+ }
237
+ </style>
238
+ `;
239
+ }
240
+ function generateIndexRoute() {
241
+ return `<script lang="ts">
242
+ import { createFileRoute } from "@kimesh/router-runtime";
243
+
244
+ export const Route = createFileRoute("/")({
245
+ head: {
246
+ title: "Home",
247
+ meta: [
248
+ { name: "description", content: "Welcome to your Kimesh app" },
249
+ ],
250
+ },
251
+ });
252
+ </script>
253
+
254
+ <script setup lang="ts">
255
+ </script>
256
+
257
+ <template>
258
+ <div class="home">
259
+ <h1>Welcome to Kimesh</h1>
260
+ <p>File-based routing for Vue with nested layouts.</p>
261
+
262
+ <section>
263
+ <h2>Getting Started</h2>
264
+ <ul>
265
+ <li>Edit <code>src/routes/index.vue</code> to modify this page</li>
266
+ <li>Add new routes in <code>src/routes/</code> folder</li>
267
+ <li>Create layouts with <code>__root.vue</code> or folder layouts</li>
268
+ </ul>
269
+ </section>
270
+ </div>
271
+ </template>
272
+
273
+ <style scoped>
274
+ .home {
275
+ max-width: 800px;
276
+ }
277
+
278
+ h1 {
279
+ font-size: 2.5rem;
280
+ margin-bottom: 1rem;
281
+ background: linear-gradient(135deg, #42b883, #35495e);
282
+ -webkit-background-clip: text;
283
+ -webkit-text-fill-color: transparent;
284
+ background-clip: text;
285
+ }
286
+
287
+ p {
288
+ font-size: 1.25rem;
289
+ color: #666;
290
+ margin-bottom: 2rem;
291
+ }
292
+
293
+ section {
294
+ background: #f8f9fa;
295
+ padding: 1.5rem;
296
+ border-radius: 8px;
297
+ }
298
+
299
+ h2 {
300
+ margin-bottom: 1rem;
301
+ color: #35495e;
302
+ }
303
+
304
+ ul {
305
+ list-style: none;
306
+ padding: 0;
307
+ }
308
+
309
+ li {
310
+ padding: 0.5rem 0;
311
+ color: #666;
312
+ }
313
+
314
+ code {
315
+ background: #e9ecef;
316
+ padding: 0.2rem 0.4rem;
317
+ border-radius: 4px;
318
+ font-size: 0.9em;
319
+ }
320
+ </style>
321
+ `;
322
+ }
323
+ async function scaffoldPinia(projectPath) {
324
+ await mkdir(join(projectPath, "src", "stores"), { recursive: true });
325
+ const exampleStore = `import { defineStore } from "pinia";
326
+ import { ref, computed } from "vue";
327
+
328
+ export const useCounterStore = defineStore("counter", () => {
329
+ const count = ref(0);
330
+ const doubleCount = computed(() => count.value * 2);
331
+
332
+ function increment() {
333
+ count.value++;
334
+ }
335
+
336
+ function decrement() {
337
+ count.value--;
338
+ }
339
+
340
+ return { count, doubleCount, increment, decrement };
341
+ });
342
+ `;
343
+ await writeFile(join(projectPath, "src", "stores", "counter.ts"), exampleStore);
344
+ }
345
+ function generateGitignore() {
346
+ return `# Dependencies
347
+ node_modules/
348
+
349
+ # Build output
350
+ dist/
351
+ .output/
352
+ .kimesh/
353
+
354
+ # Logs
355
+ *.log
356
+
357
+ # Editor
358
+ .idea/
359
+ .vscode/
360
+ *.swp
361
+ *.swo
362
+
363
+ # OS
364
+ .DS_Store
365
+ Thumbs.db
366
+
367
+ # Environment
368
+ .env
369
+ .env.local
370
+ .env.*.local
371
+ `;
372
+ }
373
+
374
+ //#endregion
375
+ //#region src/modules/registry.ts
376
+ /**
377
+ * Available modules for create-kimesh
378
+ */
379
+ const AVAILABLE_MODULES = [
380
+ {
381
+ id: "tailwindcss",
382
+ label: "TailwindCSS",
383
+ hint: "Utility-first CSS framework",
384
+ npmPackage: "@kimesh/tailwindcss",
385
+ installOrder: 1
386
+ },
387
+ {
388
+ id: "shadcn",
389
+ label: "shadcn/ui",
390
+ hint: "Re-usable components built with Radix Vue",
391
+ npmPackage: "@kimesh/shadcn",
392
+ dependsOn: ["tailwindcss"],
393
+ installOrder: 2
394
+ },
395
+ {
396
+ id: "pinia",
397
+ label: "Pinia",
398
+ hint: "The intuitive store for Vue.js",
399
+ npmPackage: "@kimesh/pinia",
400
+ installOrder: 1
401
+ }
402
+ ];
403
+ /**
404
+ * Get module by ID
405
+ */
406
+ function getModule(id) {
407
+ return AVAILABLE_MODULES.find((m) => m.id === id);
408
+ }
409
+ /**
410
+ * Get all module IDs
411
+ */
412
+ function getModuleIds() {
413
+ return AVAILABLE_MODULES.map((m) => m.id);
414
+ }
415
+ /**
416
+ * Check if a module ID is valid
417
+ */
418
+ function isValidModuleId(id) {
419
+ return AVAILABLE_MODULES.some((m) => m.id === id);
420
+ }
421
+ /**
422
+ * Parse comma-separated module string into array of valid module IDs
423
+ */
424
+ function parseModulesArg(modules) {
425
+ return modules.split(",").map((m) => m.trim().toLowerCase()).filter((m) => m && isValidModuleId(m));
426
+ }
427
+
428
+ //#endregion
429
+ //#region src/modules/resolver.ts
430
+ /**
431
+ * Resolve module dependencies and return ordered list
432
+ *
433
+ * @param selectedIds - Array of module IDs selected by the user
434
+ * @returns ResolvedModules with ordered modules and auto-added dependencies
435
+ */
436
+ function resolveModules(selectedIds) {
437
+ const selected = new Set(selectedIds);
438
+ const autoAdded = [];
439
+ for (const id of selectedIds) {
440
+ const module = getModule(id);
441
+ if (!module?.dependsOn) continue;
442
+ for (const depId of module.dependsOn) if (!selected.has(depId)) {
443
+ const dep = getModule(depId);
444
+ if (dep) {
445
+ selected.add(depId);
446
+ autoAdded.push(dep);
447
+ }
448
+ }
449
+ }
450
+ const modules = Array.from(selected).map((id) => getModule(id)).filter((m) => m !== void 0).sort((a, b) => a.installOrder - b.installOrder);
451
+ return {
452
+ modules,
453
+ autoAdded
454
+ };
455
+ }
456
+ /**
457
+ * Check if a module has unmet dependencies in the selection
458
+ */
459
+ function hasUnmetDependencies(moduleId, selectedIds) {
460
+ const module = getModule(moduleId);
461
+ if (!module?.dependsOn) return [];
462
+ const selected = new Set(selectedIds);
463
+ return module.dependsOn.filter((depId) => !selected.has(depId));
464
+ }
465
+ /**
466
+ * Get display string for module with dependency info
467
+ */
468
+ function getModuleDisplayHint(module) {
469
+ if (module.dependsOn && module.dependsOn.length > 0) {
470
+ const deps = module.dependsOn.join(", ");
471
+ return `${module.hint} (requires ${deps})`;
472
+ }
473
+ return module.hint;
474
+ }
475
+
476
+ //#endregion
477
+ //#region src/prompts/project-name.ts
478
+ /**
479
+ * Validation regex for project names
480
+ * Valid: alphanumeric, hyphens, underscores
481
+ */
482
+ const PROJECT_NAME_REGEX = /^[\w-]+$/;
483
+ /**
484
+ * Validate a project name
485
+ * @returns true if valid, error message string if invalid
486
+ */
487
+ function validateProjectName(name) {
488
+ const trimmed = name.trim();
489
+ if (!trimmed) return "Project name cannot be empty";
490
+ if (!PROJECT_NAME_REGEX.test(trimmed)) return "Project name can only contain letters, numbers, hyphens, and underscores";
491
+ return true;
492
+ }
493
+ /**
494
+ * Prompt the user for a project name
495
+ *
496
+ * @param defaultName - Default project name to suggest
497
+ * @returns The validated project name
498
+ */
499
+ async function promptProjectName(defaultName = "kimesh-app") {
500
+ const result = await consola.prompt("What is your project name?", {
501
+ type: "text",
502
+ placeholder: defaultName,
503
+ default: defaultName
504
+ });
505
+ if (typeof result === "symbol") {
506
+ consola.info("Operation cancelled");
507
+ process.exit(0);
508
+ }
509
+ const trimmed = result.trim();
510
+ const validation = validateProjectName(trimmed);
511
+ if (validation !== true) {
512
+ consola.warn(validation);
513
+ return promptProjectName(defaultName);
514
+ }
515
+ return trimmed;
516
+ }
517
+
518
+ //#endregion
519
+ //#region src/prompts/directory-conflict.ts
520
+ /**
521
+ * Options for handling directory conflicts
522
+ */
523
+ const CONFLICT_OPTIONS = [
524
+ {
525
+ value: "override",
526
+ label: "Override its contents"
527
+ },
528
+ {
529
+ value: "different",
530
+ label: "Select a different directory"
531
+ },
532
+ {
533
+ value: "abort",
534
+ label: "Abort"
535
+ }
536
+ ];
537
+ /**
538
+ * Prompt user to resolve a directory conflict
539
+ *
540
+ * @param dirname - The name of the existing directory
541
+ * @returns The chosen action: 'override', 'different', or 'abort'
542
+ */
543
+ async function promptDirectoryConflict(dirname) {
544
+ const result = await consola.prompt(`Directory "${dirname}" already exists. What would you like to do?`, {
545
+ type: "select",
546
+ options: CONFLICT_OPTIONS
547
+ });
548
+ if (typeof result === "symbol") return "abort";
549
+ return result;
550
+ }
551
+ /**
552
+ * Prompt user for a new directory name
553
+ *
554
+ * @param currentName - The current (conflicting) name
555
+ * @returns The new directory name
556
+ */
557
+ async function promptNewDirectoryName(currentName) {
558
+ const result = await consola.prompt("Enter a new directory name:", {
559
+ type: "text",
560
+ placeholder: `${currentName}-new`
561
+ });
562
+ if (typeof result === "symbol") {
563
+ consola.info("Operation cancelled");
564
+ process.exit(0);
565
+ }
566
+ const trimmed = result.trim();
567
+ if (!trimmed) {
568
+ consola.warn("Directory name cannot be empty");
569
+ return promptNewDirectoryName(currentName);
570
+ }
571
+ if (!/^[\w-]+$/.test(trimmed)) {
572
+ consola.warn("Directory name can only contain letters, numbers, hyphens, and underscores");
573
+ return promptNewDirectoryName(currentName);
574
+ }
575
+ return trimmed;
576
+ }
577
+
578
+ //#endregion
579
+ //#region src/prompts/module-selection.ts
580
+ /**
581
+ * Prompt user to select modules from the available list
582
+ *
583
+ * @returns Array of selected module IDs
584
+ */
585
+ async function promptModuleSelection() {
586
+ const options = AVAILABLE_MODULES.map((mod) => ({
587
+ value: mod.id,
588
+ label: mod.label,
589
+ hint: getModuleDisplayHint(mod)
590
+ }));
591
+ const result = await consola.prompt("Which modules would you like to include? (space to select, enter to confirm)", {
592
+ type: "multiselect",
593
+ options,
594
+ required: false
595
+ });
596
+ if (typeof result === "symbol") {
597
+ consola.info("Operation cancelled");
598
+ process.exit(0);
599
+ }
600
+ return result;
601
+ }
602
+
603
+ //#endregion
604
+ //#region src/main.ts
605
+ const main = defineCommand({
606
+ meta: {
607
+ name: "create-kimesh",
608
+ version: "0.1.0",
609
+ description: "Create a new Kimesh project"
610
+ },
611
+ args: {
612
+ dir: {
613
+ type: "positional",
614
+ description: "Project directory",
615
+ required: false
616
+ },
617
+ template: {
618
+ type: "string",
619
+ description: "Template to use",
620
+ alias: "t"
621
+ },
622
+ force: {
623
+ type: "boolean",
624
+ description: "Override existing directory without prompting",
625
+ alias: "f",
626
+ default: false
627
+ },
628
+ modules: {
629
+ type: "string",
630
+ description: `Comma-separated modules to install (${getModuleIds().join(", ")})`,
631
+ alias: "m"
632
+ }
633
+ },
634
+ async run({ args }) {
635
+ consola.log("");
636
+ consola.log(pc.cyan(pc.bold(" ✨ Create Kimesh App")));
637
+ consola.log("");
638
+ const template = args.template || "default";
639
+ const forceOverride = args.force;
640
+ let projectName;
641
+ if (args.dir) {
642
+ const validation = validateProjectName(args.dir);
643
+ if (validation !== true) {
644
+ consola.error(validation);
645
+ process.exit(1);
646
+ }
647
+ projectName = args.dir;
648
+ } else projectName = await promptProjectName();
649
+ let projectPath = resolve(process.cwd(), projectName);
650
+ while (existsSync(projectPath)) {
651
+ if (forceOverride) {
652
+ consola.warn(`Directory "${projectName}" exists and will be overridden`);
653
+ break;
654
+ }
655
+ const action = await promptDirectoryConflict(projectName);
656
+ if (action === "abort") {
657
+ consola.info("Operation cancelled");
658
+ process.exit(0);
659
+ }
660
+ if (action === "override") {
661
+ consola.info(`Will override existing directory "${projectName}"`);
662
+ break;
663
+ }
664
+ projectName = await promptNewDirectoryName(projectName);
665
+ projectPath = resolve(process.cwd(), projectName);
666
+ }
667
+ let selectedModuleIds;
668
+ if (args.modules) {
669
+ selectedModuleIds = parseModulesArg(args.modules);
670
+ const inputModules = args.modules.split(",").map((m) => m.trim().toLowerCase());
671
+ const invalidModules = inputModules.filter((m) => m && !isValidModuleId(m));
672
+ if (invalidModules.length > 0) consola.warn(`Unknown modules ignored: ${invalidModules.join(", ")}. Available: ${getModuleIds().join(", ")}`);
673
+ } else selectedModuleIds = await promptModuleSelection();
674
+ const { modules, autoAdded } = resolveModules(selectedModuleIds);
675
+ if (autoAdded.length > 0) {
676
+ const autoAddedNames = autoAdded.map((m) => m.label).join(", ");
677
+ consola.info(`Auto-adding ${pc.cyan(autoAddedNames)} (required by selected modules)`);
678
+ }
679
+ consola.log("");
680
+ consola.info(pc.bold("Creating project with:"));
681
+ consola.info(` ${pc.dim("Name:")} ${pc.cyan(projectName)}`);
682
+ consola.info(` ${pc.dim("Path:")} ${pc.cyan(projectPath)}`);
683
+ consola.info(` ${pc.dim("Template:")} ${pc.green(template)}`);
684
+ if (modules.length > 0) {
685
+ const moduleNames = modules.map((m) => m.label).join(", ");
686
+ consola.info(` ${pc.dim("Modules:")} ${pc.magenta(moduleNames)}`);
687
+ } else consola.info(` ${pc.dim("Modules:")} ${pc.dim("none")}`);
688
+ consola.log("");
689
+ const shouldOverride = forceOverride || existsSync(projectPath);
690
+ consola.start("Scaffolding project...");
691
+ const result = await scaffoldProject({
692
+ projectPath,
693
+ projectName,
694
+ template,
695
+ modules,
696
+ override: shouldOverride
697
+ });
698
+ if (!result.success) {
699
+ consola.error(`Failed to scaffold project: ${result.error}`);
700
+ process.exit(1);
701
+ }
702
+ consola.success("Project created successfully!");
703
+ consola.log("");
704
+ consola.info(pc.bold("Next steps:"));
705
+ consola.info(` ${pc.cyan(`cd ${projectName}`)}`);
706
+ consola.info(` ${pc.cyan("bun install")}`);
707
+ consola.info(` ${pc.cyan("bun dev")}`);
708
+ }
709
+ });
710
+
711
+ //#endregion
712
+ export { AVAILABLE_MODULES, getModule, getModuleDisplayHint, getModuleIds, hasUnmetDependencies, isValidModuleId, main, parseModulesArg, promptDirectoryConflict, promptModuleSelection, promptNewDirectoryName, promptProjectName, resolveModules, scaffoldProject, validateProjectName };
package/dist/main.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { main$1 as main } from "./main-DQV-uvOc.js";
1
+ import { main$1 as main } from "./main-BD9ZzEkl.js";
2
2
  export { main };
package/dist/main.js CHANGED
@@ -1,3 +1,3 @@
1
- import { main } from "./main-CXj_0-LW.js";
1
+ import { main } from "./main-DgdkY0zh.js";
2
2
 
3
3
  export { main };
package/dist/run.js CHANGED
@@ -1,11 +1,10 @@
1
- import { main } from "./main-CXj_0-LW.js";
1
+ import { main } from "./main-DgdkY0zh.js";
2
2
  import { runMain } from "citty";
3
3
 
4
4
  //#region src/run.ts
5
5
  function run() {
6
6
  runMain(main);
7
7
  }
8
- run();
9
8
 
10
9
  //#endregion
11
10
  export { run };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-kimesh",
3
- "version": "0.1.0-nightly.20260120063147",
3
+ "version": "0.1.0-nightly.20260120082346",
4
4
  "description": "Create a new Kimesh project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,38 +0,0 @@
1
- import { defineCommand } from "citty";
2
- import consola from "consola";
3
- import pc from "picocolors";
4
-
5
- //#region src/main.ts
6
- const main = defineCommand({
7
- meta: {
8
- name: "create-kimesh",
9
- version: "0.1.0",
10
- description: "Create a new Kimesh project"
11
- },
12
- args: {
13
- dir: {
14
- type: "positional",
15
- description: "Project directory",
16
- required: false
17
- },
18
- template: {
19
- type: "string",
20
- description: "Template to use",
21
- alias: "t"
22
- }
23
- },
24
- async run({ args }) {
25
- const projectDir = args.dir || ".";
26
- const template = args.template || "default";
27
- consola.info(`Creating new Kimesh project in ${pc.cyan(projectDir)}`);
28
- consola.info(`Using template: ${pc.green(template)}`);
29
- consola.success("Project created successfully!");
30
- consola.info(`\nNext steps:`);
31
- consola.info(` cd ${projectDir}`);
32
- consola.info(` bun install`);
33
- consola.info(` bun dev`);
34
- }
35
- });
36
-
37
- //#endregion
38
- export { main };