@dawitworku/projectcli 0.2.0 โ†’ 0.2.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/README.md CHANGED
@@ -1,75 +1,110 @@
1
- # projectcli
1
+ # ProjectCLI ๐Ÿš€
2
2
 
3
- Interactive project generator.
3
+ > **The Swiss Army Knife for Project Scaffolding.**
4
+ > Bootstrapping new projects shouldn't require memorizing 50 different CLI commands.
4
5
 
5
- Run it as a single command, pick language โ†’ framework, and it scaffolds the project by calling the underlying official CLIs (Vite, Next.js, Nest, etc.).
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![npm version](https://badge.fury.io/js/@dawitworku%2Fprojectcli.svg)](https://badge.fury.io/js/@dawitworku%2Fprojectcli)
8
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
6
9
 
7
- ## Run with npx (recommended)
10
+ **ProjectCLI** is an interactive, cross-language project generator. Instead of remembering usage for `create-react-app`, `cargo new`, `poetry new`, `laravel new`, `rails new`, etc., just run `projectcli`.
8
11
 
9
- After you publish this package to npm:
12
+ We handle the complexity of calling the official CLIs for you.
13
+
14
+ ## โœจ Features
15
+
16
+ - **Multi-Language Support**: Rust, Go, Python, JavaScript, TypeScript, PHP, Java, C#, Ruby, Swift, Dart.
17
+ - **Unified Interface**: One interactive wizard to rule them all.
18
+ - **Smart Context Awareness**: Running `projectcli` inside an existing project automatically offers to add libraries, CI/CD, or Dockerfiles tailored to that language.
19
+ - **Preflight Checks**: Warns you if you are missing required tools (e.g. `cargo`, `go`, `node`) before you start.
20
+ - **Remote Templates**: Clone any GitHub repository and automatically strip `.git` history for a fresh start.
21
+ - **CI/CD & Docker**: One-click generation of GitHub Actions workflows and Dockerfiles.
22
+
23
+ ## ๐Ÿš€ Quick Start
24
+
25
+ Run instantly with `npx`:
10
26
 
11
27
  ```bash
12
28
  npx @dawitworku/projectcli@latest
13
29
  ```
14
30
 
15
- You can also run non-interactively:
31
+ Or install globally:
16
32
 
17
33
  ```bash
18
- npx @dawitworku/projectcli@latest --language "TypeScript" --framework "NestJS" --name my-api --pm npm
34
+ npm install -g @dawitworku/projectcli
35
+ projectcli
19
36
  ```
20
37
 
21
- ## Run (dev)
38
+ ## ๐ŸŽฎ Interactive Mode
39
+
40
+ Just run `projectcli` and follow the prompts:
41
+
42
+ 1. Select **Language** (fuzzy search supported).
43
+ 2. Select **Framework** (React, Vue, Next.js, Actix, Axum, Django, FastAPI, etc.).
44
+ 3. Choose **Project Name**.
45
+ 4. (Optional) Add **CI/CD** or **Docker**.
46
+
47
+ ## ๐Ÿ›  Advanced Usage
48
+
49
+ ### Context Awareness
50
+
51
+ Run it inside a project to detect the language and offer relevant tools:
22
52
 
23
53
  ```bash
24
- npm install
25
- npm start
54
+ cd my-rust-project
55
+ projectcli
56
+ # Output: "โœ“ Detected active Rust project"
57
+ # Options: [Add GitHub Actions CI], [Add Dockerfile], [Add Dependencies]
26
58
  ```
27
59
 
28
- ## Install as a single-word command
60
+ ### Remote Templates
29
61
 
30
- From this repo folder:
62
+ Clone a starter kit from GitHub and make it your own instantly:
31
63
 
32
64
  ```bash
33
- npm install
34
- npm link
65
+ projectcli --template https://github.com/example/starter-repo --name my-app
35
66
  ```
36
67
 
37
- Then you can run:
68
+ ### Automation / CI Use
69
+
70
+ Skip the interactive prompts for scripts or specialized workflows:
38
71
 
39
72
  ```bash
40
- projectcli
73
+ projectcli --language Rust --framework Actix --name my-api --ci --docker --yes
41
74
  ```
42
75
 
43
- ## Add libraries to an existing project
76
+ ### Configuration
44
77
 
45
- Run inside a project folder:
78
+ Save your preferences (like default package manager):
46
79
 
47
80
  ```bash
48
- projectcli add
81
+ projectcli config
49
82
  ```
50
83
 
51
- ## Notes
84
+ ## ๐Ÿ“ฆ Supported Generators (Partial List)
52
85
 
53
- - If you type a project name that already exists, the CLI will ask for another name (it wonโ€™t quit).
54
- - Some generators (like Vite/Next/etc.) can still ask their own questions โ€” those prompts come from the underlying tool.
86
+ | Language | Frameworks / Tools |
87
+ | ------------------------- | ------------------------------------------------------------- |
88
+ | **JavaScript/TypeScript** | React (Vite), Vue, Next.js, NestJS, Express, Astro, Svelte... |
89
+ | **Rust** | Binary, Library, Actix Web, Axum, Rocket, Taurus... |
90
+ | **Python** | Poetry, Setuptools, Django, Flask, FastAPI... |
91
+ | **Go** | Binary, Fiber, Gin, Chi, Echo... |
92
+ | **PHP** | Laravel, Symfony, Slim... |
93
+ | **Java/Kotlin** | Spring Boot, Gradle/Maven... |
94
+ | **...and more** | C#, Ruby, Swift, Dart |
55
95
 
56
- ## Useful flags
96
+ ## ๐Ÿค Contributing
57
97
 
58
- ```bash
59
- projectcli --help
60
- projectcli --version
61
- projectcli --list
62
- projectcli --language "JavaScript" --framework "Astro" --name myapp --pm pnpm
63
- projectcli --language "TypeScript" --framework "TanStack Start" --name myapp --pm npm
64
- projectcli --language "TypeScript" --framework "NestJS" --name myapi --pm pnpm
65
- projectcli --dry-run --language "JavaScript" --framework "Vite (React)" --name demo --pm pnpm
66
- ```
98
+ We love contributions! Whether it's adding a new framework to the registry or fixing a bug.
99
+
100
+ 1. Fork it.
101
+ 2. Create your feature branch (`git checkout -b feature/new-framework`).
102
+ 3. Commit your changes (`git commit -am 'Add support for X'`).
103
+ 4. Push to the branch (`git push origin feature/new-framework`).
104
+ 5. Create a new Pull Request.
67
105
 
68
- ## How it works
106
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for more details.
69
107
 
70
- - Choose language
71
- - Choose framework
72
- - Enter project name
73
- - CLI runs the underlying generator commands (npm/cargo/django-admin/etc.)
108
+ ## ๐Ÿ“ License
74
109
 
75
- If a generator command is missing on your machine, install it and re-run.
110
+ MIT ยฉ [Dawit Worku](https://github.com/dawitworku)
package/package.json CHANGED
@@ -1,7 +1,16 @@
1
1
  {
2
2
  "name": "@dawitworku/projectcli",
3
- "version": "0.2.0",
4
- "description": "Interactive project generator (language -> framework -> create).",
3
+ "version": "0.2.1",
4
+ "description": "The ultimate interactive project generator (language -> framework -> create).",
5
+ "author": "Dawit Worku",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/dawitworku/projectcli"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/dawitworku/projectcli/issues"
12
+ },
13
+ "homepage": "https://github.com/dawitworku/projectcli#readme",
5
14
  "license": "MIT",
6
15
  "type": "commonjs",
7
16
  "bin": {
package/src/config.js ADDED
@@ -0,0 +1,34 @@
1
+ const fs = require("node:fs");
2
+ const path = require("node:path");
3
+ const os = require("node:os");
4
+
5
+ const CONFIG_PATH = path.join(os.homedir(), ".projectcli.json");
6
+
7
+ function loadConfig() {
8
+ try {
9
+ if (fs.existsSync(CONFIG_PATH)) {
10
+ const content = fs.readFileSync(CONFIG_PATH, "utf8");
11
+ return JSON.parse(content);
12
+ }
13
+ } catch (err) {
14
+ // ignore
15
+ }
16
+ return {};
17
+ }
18
+
19
+ function saveConfig(data) {
20
+ try {
21
+ const current = loadConfig();
22
+ const updated = { ...current, ...data };
23
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify(updated, null, 2));
24
+ return true;
25
+ } catch (err) {
26
+ return false;
27
+ }
28
+ }
29
+
30
+ module.exports = {
31
+ loadConfig,
32
+ saveConfig,
33
+ CONFIG_PATH,
34
+ };
package/src/index.js CHANGED
@@ -28,8 +28,13 @@ try {
28
28
  const { getLanguages, getFrameworks, getGenerator } = require("./registry");
29
29
  const { runSteps } = require("./run");
30
30
  const { runAdd } = require("./add");
31
+ const { checkBinaries } = require("./preflight");
32
+ const { gitClone, removeGitFolder } = require("./remote");
31
33
  const { generateCI, generateDocker } = require("./cicd");
32
34
  const { getDescription } = require("./descriptions");
35
+ const { detectLanguage, detectPackageManager } = require("./detect");
36
+ const { loadConfig } = require("./config");
37
+ const { runConfig } = require("./settings");
33
38
 
34
39
  const RUST_KEYWORDS = new Set(
35
40
  [
@@ -134,6 +139,7 @@ function parseArgs(argv) {
134
139
  ci: false,
135
140
  docker: false,
136
141
  learning: false,
142
+ template: undefined,
137
143
  };
138
144
 
139
145
  const nextValue = (i) => {
@@ -151,7 +157,12 @@ function parseArgs(argv) {
151
157
  else if (a === "--ci") out.ci = true;
152
158
  else if (a === "--docker") out.docker = true;
153
159
  else if (a === "--learning") out.learning = true;
154
- else if (a.startsWith("--language="))
160
+ else if (a.startsWith("--template="))
161
+ out.template = a.slice("--template=".length);
162
+ else if (a === "--template") {
163
+ out.template = nextValue(i);
164
+ i++;
165
+ } else if (a.startsWith("--language="))
155
166
  out.language = a.slice("--language=".length);
156
167
  else if (a === "--language") {
157
168
  out.language = nextValue(i);
@@ -197,6 +208,7 @@ function printHelp() {
197
208
  console.log(
198
209
  " projectcli --language <lang> --framework <fw> --name <project>"
199
210
  );
211
+ console.log(" projectcli config # configure defaults");
200
212
  console.log("");
201
213
  console.log("Flags:");
202
214
  console.log(" --help, -h Show help");
@@ -213,9 +225,11 @@ function printHelp() {
213
225
  console.log(" --ci Auto-add GitHub Actions CI");
214
226
  console.log(" --docker Auto-add Dockerfile");
215
227
  console.log(" --learning Enable learning mode (shows descriptions)");
228
+ console.log(" --template Clone from a Git repository URL");
216
229
  }
217
230
 
218
231
  const BACK = "__back__";
232
+ const COMMUNITY = "Community / Remote";
219
233
 
220
234
  function withBack(choices) {
221
235
  return [
@@ -310,6 +324,87 @@ async function main(options = {}) {
310
324
  return;
311
325
  }
312
326
 
327
+ if (cmd === "config") {
328
+ await runConfig({ prompt });
329
+ return;
330
+ }
331
+
332
+ // Smart Context Detection
333
+ if (
334
+ cmd === "init" &&
335
+ rest.length === 0 &&
336
+ !args.language &&
337
+ !args.framework &&
338
+ !args.template &&
339
+ !args.name
340
+ ) {
341
+ const detected = detectLanguage(process.cwd());
342
+ if (detected && detected !== "Unknown") {
343
+ console.clear();
344
+ console.log(
345
+ gradient.pastel.multiline(
346
+ figlet.textSync("ProjectCLI", { font: "Standard" })
347
+ )
348
+ );
349
+ console.log(chalk.bold.magenta(" The Swiss Army Knife for Developers"));
350
+ console.log("");
351
+ console.log(
352
+ chalk.green(`โœ“ Detected active ${chalk.bold(detected)} project.`)
353
+ );
354
+
355
+ const { action } = await prompt([
356
+ {
357
+ type: "list",
358
+ name: "action",
359
+ message: "What would you like to do?",
360
+ choices: [
361
+ { name: "Add Library / Dependency", value: "add" },
362
+ { name: "Add GitHub Actions CI", value: "ci" },
363
+ { name: "Add Dockerfile", value: "docker" },
364
+ new inquirer.Separator(),
365
+ { name: "Start New Project Here", value: "new" },
366
+ { name: "Exit", value: "exit" },
367
+ ],
368
+ },
369
+ ]);
370
+
371
+ if (action === "exit") process.exit(0);
372
+
373
+ if (action === "add") {
374
+ // reuse the add logic, passing empty args so it detects locally
375
+ await runAdd({ prompt, argv: [] });
376
+ return;
377
+ }
378
+
379
+ if (action === "ci" || action === "docker") {
380
+ const pm = detectPackageManager(process.cwd());
381
+ let langArg = detected;
382
+ if (detected === "JavaScript/TypeScript") langArg = "JavaScript";
383
+ if (detected === "Java/Kotlin") langArg = "Java";
384
+
385
+ const steps =
386
+ action === "ci"
387
+ ? generateCI(process.cwd(), langArg, pm)
388
+ : generateDocker(process.cwd(), langArg);
389
+
390
+ if (steps.length > 0) {
391
+ console.log("\nApplying changes...");
392
+ await runSteps(steps, { projectRoot: process.cwd() });
393
+ console.log(chalk.green("Done!"));
394
+ } else {
395
+ console.log(
396
+ chalk.yellow(
397
+ "No standard template available for this language yet."
398
+ )
399
+ );
400
+ }
401
+ return;
402
+ }
403
+
404
+ // If 'new', fall through to normal wizard
405
+ }
406
+ }
407
+
313
408
  // Clear console for a fresh start
314
409
  console.clear();
315
410
 
@@ -332,13 +427,26 @@ async function main(options = {}) {
332
427
  throw new Error("No languages configured.");
333
428
  }
334
429
 
430
+ const userConfig = loadConfig();
431
+
335
432
  const allowedPms = ["npm", "pnpm", "yarn", "bun"];
336
- const preselectedPm =
433
+ let preselectedPm =
337
434
  typeof args.pm === "string" && allowedPms.includes(args.pm)
338
435
  ? args.pm
339
436
  : undefined;
340
437
 
438
+ if (!preselectedPm && userConfig.packageManager) {
439
+ if (allowedPms.includes(userConfig.packageManager)) {
440
+ preselectedPm = userConfig.packageManager;
441
+ }
442
+ }
443
+
444
+ if (userConfig.learningMode && args.learning === false) {
445
+ args.learning = true;
446
+ }
447
+
341
448
  const state = {
449
+ template: args.template || undefined,
342
450
  language:
343
451
  args.language && languages.includes(args.language)
344
452
  ? args.language
@@ -360,7 +468,10 @@ async function main(options = {}) {
360
468
  state.language === "JavaScript" || state.language === "TypeScript";
361
469
 
362
470
  let step = "language";
363
- if (!state.language) step = "language";
471
+ if (state.template) {
472
+ if (!state.name) step = "name";
473
+ else step = "confirm";
474
+ } else if (!state.language) step = "language";
364
475
  else if (!state.framework) step = "framework";
365
476
  else if (needsPackageManager && !state.pm) step = "pm";
366
477
  else if (!state.name) step = "name";
@@ -453,6 +564,38 @@ async function main(options = {}) {
453
564
  }
454
565
 
455
566
  state.framework = answer.framework;
567
+
568
+ // Preflight Checks
569
+ const gen = getGenerator(state.language, state.framework);
570
+ if (gen && gen.check && gen.check.length > 0) {
571
+ /* eslint-disable-next-line no-console */
572
+ console.log(chalk.dim("\n(checking requirements...)"));
573
+ const results = await checkBinaries(gen.check);
574
+ const missing = results.filter((r) => !r.ok);
575
+
576
+ if (missing.length > 0) {
577
+ console.log(chalk.red.bold("\nMissing required tools:"));
578
+ missing.forEach((m) => console.log(chalk.red(` - ${m.bin}`)));
579
+ console.log(
580
+ chalk.yellow("You may not be able to build or run this project.\n")
581
+ );
582
+
583
+ const { proceed } = await prompt([
584
+ {
585
+ type: "confirm",
586
+ name: "proceed",
587
+ message: "Continue anyway?",
588
+ default: false,
589
+ },
590
+ ]);
591
+
592
+ if (!proceed) {
593
+ step = "framework";
594
+ continue;
595
+ }
596
+ }
597
+ }
598
+
456
599
  step = "pm";
457
600
  continue;
458
601
  }
@@ -528,6 +671,10 @@ async function main(options = {}) {
528
671
 
529
672
  const v = String(projectName || "").trim();
530
673
  if (v.toLowerCase() === "back") {
674
+ if (state.template) {
675
+ console.log("Operation cancelled.");
676
+ process.exit(0);
677
+ }
531
678
  step =
532
679
  state.language === "JavaScript" || state.language === "TypeScript"
533
680
  ? "pm"
@@ -541,13 +688,75 @@ async function main(options = {}) {
541
688
  }
542
689
 
543
690
  if (step === "confirm") {
691
+ const projectRoot = path.resolve(process.cwd(), state.name);
692
+ const targetExists = fs.existsSync(projectRoot);
693
+
694
+ if (state.template) {
695
+ if (targetExists && !args.dryRun) {
696
+ console.error(
697
+ `\nError: Target folder already exists: ${projectRoot}`
698
+ );
699
+ state.name = undefined;
700
+ step = "name";
701
+ continue;
702
+ }
703
+
704
+ console.log("\nProject Configuration:");
705
+ console.log(` Template: ${state.template}`);
706
+ console.log(` Folder: ${state.name}`);
707
+ console.log("");
708
+
709
+ if (!args.yes) {
710
+ const { action } = await prompt([
711
+ {
712
+ type: "list",
713
+ name: "action",
714
+ message: "Clone this template?",
715
+ choices: [
716
+ { name: "Clone template", value: "create" },
717
+ { name: "Cancel", value: "cancel" },
718
+ ],
719
+ },
720
+ ]);
721
+ if (action === "cancel") {
722
+ console.log("Aborted.");
723
+ return;
724
+ }
725
+ }
726
+
727
+ if (args.dryRun) {
728
+ console.log(
729
+ `[Dry Run] Would clone ${state.template} to ${projectRoot}`
730
+ );
731
+ return;
732
+ }
733
+
734
+ console.log(chalk.dim("\nCloning repository..."));
735
+ try {
736
+ await gitClone(state.template, projectRoot);
737
+ // Remove .git to make it a fresh project
738
+ removeGitFolder(projectRoot);
739
+
740
+ console.log(
741
+ chalk.green(`\nSuccess! Created project at ${projectRoot}`)
742
+ );
743
+ console.log(
744
+ chalk.dim(
745
+ "You may need to run 'npm install' or similar inside the folder."
746
+ )
747
+ );
748
+ } catch (err) {
749
+ console.error(chalk.red("\nFailed to clone template:"), err.message);
750
+ process.exit(1);
751
+ }
752
+ return;
753
+ }
754
+
544
755
  const generator = getGenerator(state.language, state.framework);
545
756
  if (!generator) {
546
757
  throw new Error("Generator not found (registry mismatch).");
547
758
  }
548
759
 
549
- const projectRoot = path.resolve(process.cwd(), state.name);
550
- const targetExists = fs.existsSync(projectRoot);
551
760
  if (targetExists && !args.dryRun) {
552
761
  console.error(`\nError: Target folder already exists: ${projectRoot}`);
553
762
  state.name = undefined;
@@ -0,0 +1,25 @@
1
+ const { spawn } = require("node:child_process");
2
+
3
+ function checkBinary(binary, args = ["--version"]) {
4
+ return new Promise((resolve) => {
5
+ const child = spawn(binary, args, {
6
+ stdio: "ignore",
7
+ shell: false,
8
+ });
9
+ child.on("error", () => resolve(false));
10
+ child.on("close", (code) => resolve(code === 0));
11
+ });
12
+ }
13
+
14
+ function checkBinaries(binaries) {
15
+ if (!binaries || binaries.length === 0) return [];
16
+ const checks = binaries.map((bin) =>
17
+ checkBinary(bin).then((ok) => ({ bin, ok }))
18
+ );
19
+ return Promise.all(checks);
20
+ }
21
+
22
+ module.exports = {
23
+ checkBinary,
24
+ checkBinaries,
25
+ };
package/src/registry.js CHANGED
@@ -33,6 +33,7 @@ const REGISTRY = {
33
33
  "Vite (Vanilla)": {
34
34
  id: "js.vite.vanilla",
35
35
  label: "Vite (Vanilla)",
36
+ check: ["npm"],
36
37
  commands: (ctx) => {
37
38
  const projectName = getProjectName(ctx);
38
39
  const pm = getPackageManager(ctx);
@@ -409,6 +410,7 @@ const REGISTRY = {
409
410
  Django: {
410
411
  id: "py.django",
411
412
  label: "Django",
413
+ check: ["django-admin"],
412
414
  commands: (ctx) => {
413
415
  const projectName = getProjectName(ctx);
414
416
  return [
@@ -423,6 +425,7 @@ const REGISTRY = {
423
425
  Flask: {
424
426
  id: "py.flask.basic",
425
427
  label: "Flask (basic)",
428
+ check: ["python3"],
426
429
  commands: (_ctx) => [
427
430
  { type: "mkdir", path: "." },
428
431
  {
@@ -502,6 +505,7 @@ const REGISTRY = {
502
505
  "Cargo (bin)": {
503
506
  id: "rs.cargo.bin",
504
507
  label: "Cargo (bin)",
508
+ check: ["cargo"],
505
509
  commands: (ctx) => {
506
510
  const projectName = getProjectName(ctx);
507
511
  return [
@@ -516,6 +520,7 @@ const REGISTRY = {
516
520
  "Cargo (lib)": {
517
521
  id: "rs.cargo.lib",
518
522
  label: "Cargo (lib)",
523
+ check: ["cargo"],
519
524
  commands: (ctx) => {
520
525
  const projectName = getProjectName(ctx);
521
526
  return [
@@ -558,6 +563,7 @@ const REGISTRY = {
558
563
  "Go module (basic)": {
559
564
  id: "go.module.basic",
560
565
  label: "Go module (basic)",
566
+ check: ["go"],
561
567
  commands: (ctx) => {
562
568
  const projectName = getProjectName(ctx);
563
569
  return [
package/src/remote.js ADDED
@@ -0,0 +1,39 @@
1
+ const { spawn } = require("node:child_process");
2
+
3
+ function gitClone(url, targetDir) {
4
+ return new Promise((resolve, reject) => {
5
+ // git clone --depth 1 url targetDir
6
+ const child = spawn("git", ["clone", "--depth", "1", url, targetDir], {
7
+ stdio: "inherit",
8
+ shell: false,
9
+ });
10
+
11
+ child.on("error", (err) => reject(err));
12
+ child.on("close", (code) => {
13
+ if (code === 0) resolve();
14
+ else reject(new Error(`Git clone failed with code ${code}`));
15
+ });
16
+ });
17
+ }
18
+
19
+ /**
20
+ * Removes the .git folder from the target directory so it becomes a fresh project.
21
+ */
22
+ function removeGitFolder(targetDir) {
23
+ const fs = require("node:fs");
24
+ const path = require("node:path");
25
+ const gitPath = path.join(targetDir, ".git");
26
+
27
+ try {
28
+ if (fs.existsSync(gitPath)) {
29
+ fs.rmSync(gitPath, { recursive: true, force: true });
30
+ }
31
+ } catch (err) {
32
+ // ignore
33
+ }
34
+ }
35
+
36
+ module.exports = {
37
+ gitClone,
38
+ removeGitFolder,
39
+ };
@@ -0,0 +1,45 @@
1
+ const chalk = require("chalk");
2
+ const { loadConfig, saveConfig, CONFIG_PATH } = require("./config");
3
+
4
+ async function runConfig({ prompt }) {
5
+ const config = loadConfig();
6
+
7
+ console.log(chalk.bold.cyan("\nConfiguration Settings"));
8
+ console.log(chalk.dim(`File: ${CONFIG_PATH}\n`));
9
+
10
+ const answers = await prompt([
11
+ {
12
+ type: "list",
13
+ name: "packageManager",
14
+ message: "Default Package Manager (for JS/TS):",
15
+ choices: [
16
+ { name: "None (Always ask)", value: null },
17
+ new inquirerSeparator(),
18
+ { name: "npm", value: "npm" },
19
+ { name: "pnpm", value: "pnpm" },
20
+ { name: "yarn", value: "yarn" },
21
+ { name: "bun", value: "bun" },
22
+ ],
23
+ default: config.packageManager || null,
24
+ },
25
+ {
26
+ type: "confirm",
27
+ name: "learningMode",
28
+ message: "Enable Learning Mode by default?",
29
+ default: config.learningMode || false,
30
+ },
31
+ ]);
32
+
33
+ saveConfig(answers);
34
+ console.log(chalk.green("\nโœ“ Settings saved!"));
35
+ }
36
+
37
+ // Helper for pure inquirer usage if needed,
38
+ // though index.js passes the prompt instance.
39
+ function inquirerSeparator() {
40
+ // We can't easily import inquirer.Separator here without adding dependency
41
+ // or passing it in. Let's just use a string for now or skip it.
42
+ return { name: "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€", disabled: true };
43
+ }
44
+
45
+ module.exports = { runConfig };