pm-auto 1.0.3 → 1.0.5

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.
Files changed (43) hide show
  1. package/README.md +91 -36
  2. package/dist/build_command.js +1 -1
  3. package/dist/build_command.js.map +1 -1
  4. package/dist/config_path.d.ts +0 -1
  5. package/dist/config_path.d.ts.map +1 -1
  6. package/dist/config_path.js +0 -5
  7. package/dist/config_path.js.map +1 -1
  8. package/dist/config_reader.d.ts +3 -1
  9. package/dist/config_reader.d.ts.map +1 -1
  10. package/dist/config_reader.js +54 -6
  11. package/dist/config_reader.js.map +1 -1
  12. package/dist/display.d.ts +5 -2
  13. package/dist/display.d.ts.map +1 -1
  14. package/dist/display.js +5 -21
  15. package/dist/display.js.map +1 -1
  16. package/dist/index.js +30 -2
  17. package/dist/index.js.map +1 -1
  18. package/dist/install.d.ts +1 -1
  19. package/dist/install.d.ts.map +1 -1
  20. package/dist/install.js +3 -8
  21. package/dist/install.js.map +1 -1
  22. package/dist/orchestrator.d.ts.map +1 -1
  23. package/dist/orchestrator.js +4 -5
  24. package/dist/orchestrator.js.map +1 -1
  25. package/dist/types/index.d.ts +1 -0
  26. package/dist/types/index.d.ts.map +1 -1
  27. package/package.json +5 -3
  28. package/src/build_command.ts +119 -119
  29. package/src/config_path.ts +48 -54
  30. package/src/config_reader.ts +68 -10
  31. package/src/display.ts +1 -7
  32. package/src/index.ts +33 -2
  33. package/src/install.ts +3 -5
  34. package/src/orchestrator.ts +5 -6
  35. package/src/types/index.ts +17 -16
  36. package/test.json +87 -94
  37. package/tests/build_command.test.ts +37 -0
  38. package/tests/config_path.test.ts +120 -0
  39. package/tests/config_reader.test.ts +179 -0
  40. package/tests/display.test.ts +83 -0
  41. package/tests/install.test.ts +200 -0
  42. package/tsconfig.json +3 -2
  43. package/vitest.config.js +8 -0
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,sDAAsD;AACtD,SAAS,iBAAiB,CAAC,KAAc;IACvC,OAAO,CACL,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACpB,KAAK,CAAC,KAAK,CACT,CAAC,IAAI,EAAE,EAAE,CACP,OAAO,IAAI,KAAK,QAAQ;YACxB,IAAI,KAAK,IAAI;YACb,UAAU,IAAI,IAAI;YAClB,KAAK,CAAC,OAAO,CAAE,IAAY,CAAC,QAAQ,CAAC,CACxC,CACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,OAAe,EACf,QAAkB,EAClB,OAAa,EACb,EAAE;IACF,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,CACL,0BAA0B,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAE,QAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EACrG,MAAM,CACP,CAAC;QAEF,eAAe,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YACvD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;gBAC3C,OAAO;YACT,CAAC;YAED,IAAI,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC9B,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;gBACvC,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;gBACxB,WAAW,CAAC,iCAAiC,CAAC,CAAC;gBAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAC7B,KAAK,CAAC,OAAO,CAAC,CAAC;YACjB,CAAC;iBAAM,CAAC;gBACN,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;gBAEtB,WAAW,CAAC,mDAAmD,CAAC,CAAC;gBACjE,KAAK,CAAC,OAAO,CAAC,CAAC;YACjB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,OAAO,CACL,4BAA6B,QAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAC/D,MAAM,CACP,CAAC;QAEF,eAAe,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YACvD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;gBAC3C,OAAO;YACT,CAAC;YAED,IAAI,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC9B,MAAM,QAAQ,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;gBAChD,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;gBACxB,WAAW,CAAC,mCAAmC,CAAC,CAAC;gBACjD,KAAK,CAAC,OAAO,CAAC,CAAC;YACjB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC"}
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,sDAAsD;AACtD,SAAS,iBAAiB,CAAC,KAAc;IACvC,OAAO,CACL,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACpB,KAAK,CAAC,KAAK,CACT,CAAC,IAAI,EAAE,EAAE,CACP,OAAO,IAAI,KAAK,QAAQ;YACxB,IAAI,KAAK,IAAI;YACb,UAAU,IAAI,IAAI;YAClB,KAAK,CAAC,OAAO,CAAE,IAAY,CAAC,QAAQ,CAAC,CACxC,CACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,OAAe,EACf,QAAkB,EAClB,OAAa,EACb,EAAE;IACF,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,CACL,0BAA0B,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAE,QAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EACrG,MAAM,CACP,CAAC;QAEF,eAAe,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YACvD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;gBAC3C,OAAO;YACT,CAAC;YAED,IAAI,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC9B,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;gBAEvC,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;gBACxB,OAAO,CAAC,iCAAiC,EAAE,SAAS,CAAC,CAAC;gBACtD,KAAK,CAAC,OAAO,CAAC,CAAC;YACjB,CAAC;iBAAM,CAAC;gBACN,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;gBACtB,OAAO,CAAC,mDAAmD,EAAE,SAAS,CAAC,CAAC;gBACxE,KAAK,CAAC,OAAO,CAAC,CAAC;YACjB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,OAAO,CACL,4BAA6B,QAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAC/D,MAAM,CACP,CAAC;QAEF,eAAe,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YACvD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;gBAC3C,OAAO;YACT,CAAC;YAED,IAAI,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC9B,MAAM,QAAQ,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;gBAChD,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;gBACxB,OAAO,CAAC,mCAAmC,EAAE,SAAS,CAAC,CAAC;gBACxD,KAAK,CAAC,OAAO,CAAC,CAAC;YACjB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC"}
@@ -1,5 +1,6 @@
1
1
  export interface ConfigType {
2
2
  name: string;
3
+ description?: string;
3
4
  packageManager: string;
4
5
  packages: {
5
6
  command: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;CACvD;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;CACvD;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pm-auto",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "A CLI tool to define and install your tech stack presets with one command.",
5
5
  "keywords": [
6
6
  "pm-auto",
@@ -19,7 +19,8 @@
19
19
  "build": "tsc",
20
20
  "dev": "nodemon --exec tsx src/index.ts",
21
21
  "start": "node dist/index.js",
22
- "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
22
+ "prepublishOnly": "npm run build",
23
+ "test": "vitest run"
23
24
  },
24
25
  "dependencies": {
25
26
  "@clack/prompts": "^0.11.0",
@@ -34,6 +35,7 @@
34
35
  "ts-jest": "^29.4.5",
35
36
  "ts-node": "^10.9.2",
36
37
  "tsx": "^4.20.6",
37
- "typescript": "^5.9.3"
38
+ "typescript": "^5.9.3",
39
+ "vitest": "^4.0.13"
38
40
  }
39
41
  }
@@ -1,119 +1,119 @@
1
- import type { ConfigType, PackageType, CommandResult } from "./types/index.js";
2
-
3
- /**
4
- * Build commands from project configurations.
5
- */
6
-
7
- export function buildCommands(projects: ConfigType[]) {
8
- // Initialize arrays properly
9
-
10
- const commandArray: CommandResult[] = [];
11
- for (const project of projects) {
12
- const { packageManager, packages } = project;
13
-
14
- const commandPrefixes = {
15
- npm: {
16
- install: "npm install",
17
- run: "npx",
18
- },
19
- pnpm: {
20
- install: "pnpm add",
21
- run: "pnpm dlx",
22
- },
23
- yarn: {
24
- install: "yarn add",
25
- run: "yarn dlx",
26
- },
27
- };
28
-
29
- const manager =
30
- commandPrefixes[packageManager as keyof typeof commandPrefixes] ||
31
- commandPrefixes.npm;
32
-
33
- const result: CommandResult = {
34
- name: project.name,
35
- interactive: [],
36
- nonInteractive: [],
37
- };
38
-
39
- // Separate interactive from non-interactive packages
40
- const nonInteractive: PackageType[] = [];
41
- const interactive: PackageType[] = [];
42
-
43
- if (packages) {
44
- packages.forEach((pkg) => {
45
- if (pkg.interactive) {
46
- interactive.push(pkg);
47
- } else {
48
- nonInteractive.push(pkg);
49
- }
50
- });
51
- }
52
-
53
- // Add interactive packages as separate commands (sequential)
54
- interactive.forEach((pkg) => {
55
- result.interactive.push(`${manager.run} ${pkg.command}`);
56
- });
57
-
58
- // Batch all non-interactive packages into ONE command
59
- if (nonInteractive.length > 0) {
60
- const packageNames = nonInteractive.map((pkg) => pkg.command).join(" ");
61
- result.nonInteractive.push(`${manager.install} ${packageNames}`);
62
- }
63
-
64
- commandArray.push(result);
65
- }
66
-
67
- return commandArray;
68
- }
69
-
70
- export function buildUninstallCommands(projects: ConfigType[]) {
71
- const commandArray: CommandResult[] = [];
72
- for (const project of projects) {
73
- const { packageManager, packages } = project;
74
-
75
- const commandPrefixes = {
76
- npm: {
77
- install: "npm uninstall",
78
- },
79
- pnpm: {
80
- install: "pnpm uninstall",
81
- },
82
- yarn: {
83
- install: "yarn remove",
84
- },
85
- };
86
-
87
- const manager =
88
- commandPrefixes[packageManager as keyof typeof commandPrefixes] ||
89
- commandPrefixes.npm;
90
-
91
- const result: CommandResult = {
92
- name: project.name,
93
- interactive: [],
94
- nonInteractive: [],
95
- };
96
-
97
- // Separate interactive from non-interactive packages
98
- const nonInteractive: PackageType[] = [];
99
- const interactive: PackageType[] = [];
100
-
101
- if (packages) {
102
- packages.forEach((pkg) => {
103
- if (!pkg.interactive) {
104
- nonInteractive.push(pkg);
105
- }
106
- });
107
- }
108
-
109
- // Batch all non-interactive packages into ONE command
110
- if (nonInteractive.length > 0) {
111
- const packageNames = nonInteractive.map((pkg) => pkg.command).join(" ");
112
- result.nonInteractive.push(`${manager.install} ${packageNames}`);
113
- }
114
-
115
- commandArray.push(result);
116
- }
117
-
118
- return commandArray;
119
- }
1
+ import type { ConfigType, PackageType, CommandResult } from "./types/index.js";
2
+
3
+ /**
4
+ * Build commands from project configurations.
5
+ */
6
+
7
+ export function buildCommands(projects: ConfigType[]) {
8
+ // Initialize arrays properly
9
+
10
+ const commandArray: CommandResult[] = [];
11
+ for (const project of projects) {
12
+ const { packageManager, packages } = project;
13
+
14
+ const commandPrefixes = {
15
+ npm: {
16
+ install: "npm install",
17
+ run: "npx",
18
+ },
19
+ pnpm: {
20
+ install: "pnpm add",
21
+ run: "pnpm dlx",
22
+ },
23
+ yarn: {
24
+ install: "yarn add",
25
+ run: "yarn dlx",
26
+ },
27
+ };
28
+
29
+ const manager =
30
+ commandPrefixes[packageManager as keyof typeof commandPrefixes] ||
31
+ commandPrefixes.npm;
32
+
33
+ const result: CommandResult = {
34
+ name: project.name,
35
+ interactive: [],
36
+ nonInteractive: [],
37
+ };
38
+
39
+ // Separate interactive from non-interactive packages
40
+ const nonInteractive: PackageType[] = [];
41
+ const interactive: PackageType[] = [];
42
+
43
+ if (packages) {
44
+ packages.forEach((pkg) => {
45
+ if (pkg.interactive) {
46
+ interactive.push(pkg);
47
+ } else {
48
+ nonInteractive.push(pkg);
49
+ }
50
+ });
51
+ }
52
+
53
+ // Add interactive packages as separate commands (sequential)
54
+ interactive.forEach((pkg) => {
55
+ result.interactive.push(`${manager.run} ${pkg.command}`);
56
+ });
57
+
58
+ // Batch all non-interactive packages into ONE command
59
+ if (nonInteractive.length > 0) {
60
+ const packageNames = nonInteractive.map((pkg) => pkg.command).join(" ");
61
+ result.nonInteractive.push(`${manager.install} ${packageNames}`);
62
+ }
63
+
64
+ commandArray.push(result);
65
+ }
66
+
67
+ return commandArray;
68
+ }
69
+
70
+ export function buildUninstallCommands(projects: ConfigType[]) {
71
+ const commandArray: CommandResult[] = [];
72
+ for (const project of projects) {
73
+ const { packageManager, packages } = project;
74
+
75
+ const commandPrefixes = {
76
+ npm: {
77
+ install: "npm uninstall",
78
+ },
79
+ pnpm: {
80
+ install: "pnpm uninstall",
81
+ },
82
+ yarn: {
83
+ install: "yarn remove",
84
+ },
85
+ };
86
+
87
+ const manager =
88
+ commandPrefixes[packageManager as keyof typeof commandPrefixes] ||
89
+ commandPrefixes.npm;
90
+
91
+ const result: CommandResult = {
92
+ name: project.name,
93
+ interactive: [],
94
+ nonInteractive: [],
95
+ };
96
+
97
+ // Separate interactive from non-interactive packages
98
+ const nonInteractive: PackageType[] = [];
99
+ // const interactive: PackageType[] = [];
100
+
101
+ if (packages) {
102
+ packages.forEach((pkg) => {
103
+ if (!pkg.interactive) {
104
+ nonInteractive.push(pkg);
105
+ }
106
+ });
107
+ }
108
+
109
+ // Batch all non-interactive packages into ONE command
110
+ if (nonInteractive.length > 0) {
111
+ const packageNames = nonInteractive.map((pkg) => pkg.command).join(" ");
112
+ result.nonInteractive.push(`${manager.install} ${packageNames}`);
113
+ }
114
+
115
+ commandArray.push(result);
116
+ }
117
+
118
+ return commandArray;
119
+ }
@@ -1,54 +1,48 @@
1
- import * as fs from "fs";
2
- import * as path from "path";
3
- import * as os from "os";
4
- import { display } from "./display.js";
5
-
6
- const SETTINGS_DIR = path.join(os.homedir(), ".pm-auto");
7
- const SETTINGS_FILE = path.join(SETTINGS_DIR, "settings.json");
8
-
9
- interface Settings {
10
- configPath?: string;
11
- }
12
-
13
- export function saveConfigPath(configPath: string): void {
14
- // Create directory if it doesn't exist
15
- if (!fs.existsSync(SETTINGS_DIR)) {
16
- fs.mkdirSync(SETTINGS_DIR, { recursive: true });
17
- }
18
-
19
- //check if file exists
20
- try {
21
- const real = fs.realpathSync(configPath);
22
- const settings: Settings = { configPath: real };
23
- fs.writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2));
24
-
25
- display(`Config file path saved: ${configPath}`, "success");
26
- } catch (err: any) {
27
- display(`Error saving config file: ${err.message}`, "error");
28
- }
29
- }
30
-
31
- export function getConfigPath(): string | void {
32
- //check if settings exists
33
- if (!fs.existsSync(SETTINGS_FILE)) {
34
- display(
35
- "Run `pm-auto config <path>`, where <path> is the path to your config file",
36
- "info",
37
- );
38
- display("Config file path not set", "error");
39
- }
40
-
41
- try {
42
- const data = fs.readFileSync(SETTINGS_FILE, "utf8");
43
- const settings: Settings = JSON.parse(data);
44
- return settings.configPath || "";
45
- } catch (error: any) {
46
- display(`Error reading config file path: ${error.message}`, "error");
47
- }
48
- }
49
-
50
- export function clearConfigPath(): void {
51
- if (fs.existsSync(SETTINGS_FILE)) {
52
- fs.unlinkSync(SETTINGS_FILE);
53
- }
54
- }
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import * as os from "os";
4
+ import { display } from "./display.js";
5
+
6
+ const SETTINGS_DIR = path.join(os.homedir(), ".pm-auto");
7
+ const SETTINGS_FILE = path.join(SETTINGS_DIR, "settings.json");
8
+
9
+ interface Settings {
10
+ configPath?: string;
11
+ }
12
+
13
+ export function saveConfigPath(configPath: string): void {
14
+ // Create directory if it doesn't exist
15
+ if (!fs.existsSync(SETTINGS_DIR)) {
16
+ fs.mkdirSync(SETTINGS_DIR, { recursive: true });
17
+ }
18
+
19
+ //check if file exists
20
+ try {
21
+ const real = fs.realpathSync(configPath);
22
+ const settings: Settings = { configPath: real };
23
+ fs.writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2));
24
+
25
+ display(`Config file path saved: ${configPath}`, "success");
26
+ } catch (err: any) {
27
+ display(`Error saving config file: ${err.message}`, "error");
28
+ }
29
+ }
30
+
31
+ export function getConfigPath(): string | void {
32
+ //check if settings exists
33
+ if (!fs.existsSync(SETTINGS_FILE)) {
34
+ display(
35
+ "Run `pm-auto config <path>`, where <path> is the path to your config file",
36
+ "info",
37
+ );
38
+ display("Config file path not set", "error");
39
+ }
40
+
41
+ try {
42
+ const data = fs.readFileSync(SETTINGS_FILE, "utf8");
43
+ const settings: Settings = JSON.parse(data);
44
+ return settings.configPath || "";
45
+ } catch (error: any) {
46
+ display(`Error reading config file path: ${error.message}`, "error");
47
+ }
48
+ }
@@ -34,7 +34,7 @@ export function detectPackageManager(
34
34
  }
35
35
 
36
36
  /**
37
- * Get the installation commands from the config file, transforms into a js object and with the options given
37
+ * Gets the required packages from the config file, transforms into a js object and with the options given
38
38
  * it modifies the object and returns it
39
39
  */
40
40
  export const getConfigObject = async (
@@ -54,21 +54,23 @@ export const getConfigObject = async (
54
54
  "error",
55
55
  );
56
56
  }
57
+
57
58
  const configObject = JSON.parse(configContent);
58
59
  let result: ConfigType[] = Object.values(configObject);
59
60
 
60
61
  //filter the packages the user wants to install
61
62
  if (packages.length > 0) {
62
- result = packages.map((pkg) => {
63
- if (!configObject[pkg]) {
64
- display(
65
- `Package ${pkg} not found in the configuration file`,
66
- "warning",
67
- );
68
- }
69
- return configObject[pkg];
70
- });
63
+ result = packages
64
+ .map((pkgName) => {
65
+ const found = result.find((pkg) => pkg.name === pkgName);
66
+ if (!found) {
67
+ display(`Package '${pkgName}' not found in config`, "warning");
68
+ }
69
+ return found;
70
+ })
71
+ .filter((pkg) => pkg !== undefined);
71
72
  }
73
+
72
74
  /*
73
75
  * Config object modification with the options given
74
76
  */
@@ -125,3 +127,59 @@ export const getConfigObject = async (
125
127
  return result;
126
128
  }
127
129
  };
130
+
131
+ export const getConfigKeys = async (options: any) => {
132
+ const configPath = getConfigPath();
133
+
134
+ //read config file content
135
+ let configContent = "";
136
+ try {
137
+ configContent = await fs.readFile(configPath as string, "utf8");
138
+ } catch (error) {
139
+ display(
140
+ `File not found ${error} Try updating the config file path`,
141
+ "error",
142
+ );
143
+ }
144
+
145
+ const configObject = JSON.parse(configContent);
146
+ let keys = Object.keys(configObject);
147
+
148
+ keys.forEach((key) => {
149
+ if (options.desc) {
150
+ const description = !configObject[key].description
151
+ ? "No description"
152
+ : configObject[key].description;
153
+ display(`${key} - ${description}`, "info");
154
+ } else {
155
+ display(`${key}`, "info");
156
+ }
157
+ });
158
+ };
159
+
160
+ export const getPackageDescription = async (packageName: string) => {
161
+ const configPath = getConfigPath();
162
+
163
+ //read config file content
164
+ let configContent = "";
165
+ try {
166
+ configContent = await fs.readFile(configPath as string, "utf8");
167
+ } catch (error) {
168
+ display(
169
+ `File not found ${error} Try updating the config file path`,
170
+ "error",
171
+ );
172
+ }
173
+
174
+ const configObject = JSON.parse(configContent);
175
+ let keys = Object.keys(configObject);
176
+
177
+ keys.forEach((key) => {
178
+ if (key === packageName) {
179
+ const description = !configObject[key].description
180
+ ? "No description"
181
+ : configObject[key].description;
182
+ display(`${packageName} - ${description}`, "info");
183
+ }
184
+ });
185
+ };
package/src/display.ts CHANGED
@@ -3,17 +3,11 @@ import chalk from "chalk";
3
3
 
4
4
  type DisplayType = "error" | "success" | "warning" | "info" | "loading" | "";
5
5
 
6
- export const stopSpinner = (text: string, code: number = 0) => {
7
- const s = spinner();
8
- if (!s || typeof s.stop !== "function") return;
9
- s.stop(code === 0 ? chalk.green(text) : chalk.red(text));
10
- };
11
-
12
6
  export const display = (text: string, type: DisplayType) => {
13
7
  switch (type) {
14
8
  case "error":
15
9
  log.error(chalk.red(text));
16
- process.exit(1);
10
+ process.exit(0);
17
11
 
18
12
  case "success":
19
13
  log.success(chalk.green(text)); // Use log.success instead
package/src/index.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { Command } from "commander";
4
- import { saveConfigPath } from "./config_path.js";
4
+ import { getConfigPath, saveConfigPath } from "./config_path.js";
5
5
  import { intro } from "@clack/prompts";
6
6
  import { orchestrator } from "./orchestrator.js";
7
7
  import chalk from "chalk";
8
+ import { getConfigKeys, getPackageDescription } from "./config_reader.js";
9
+ import { display } from "./display.js";
8
10
 
9
11
  intro(chalk.inverse(" pm-auto "));
10
12
 
@@ -12,7 +14,7 @@ const program = new Command();
12
14
 
13
15
  program
14
16
  .name("pm-auto")
15
- .version("1.0.1")
17
+ .version("1.0.5")
16
18
  .description(
17
19
  "A CLI tool to define and install your tech stack presets with one command.",
18
20
  );
@@ -57,4 +59,33 @@ program
57
59
  orchestrator("uninstall", packages, options);
58
60
  });
59
61
 
62
+ //Listing config packages
63
+ program
64
+ .command("list")
65
+ .alias("ls")
66
+ .description("List all packages from the config file")
67
+ .option("-D, --desc", "Display packages description", false)
68
+ .action((options) => {
69
+ getConfigKeys(options);
70
+ });
71
+
72
+ //Displaying config details
73
+ program
74
+ .command("describe <package>")
75
+ .alias("desc")
76
+ .description("Display description of the package")
77
+ .action((packages) => {
78
+ getPackageDescription(packages);
79
+ });
80
+
81
+ //get config path
82
+ program
83
+ .command("config-path")
84
+ .alias("cp")
85
+ .description("Display the path to the configuration file")
86
+ .action(() => {
87
+ const path = getConfigPath();
88
+ display(`Config Path: ${path}`, "info");
89
+ });
90
+
60
91
  program.parse();
package/src/install.ts CHANGED
@@ -1,14 +1,12 @@
1
1
  import { execa } from "execa";
2
2
  import type { CommandResult } from "./types/index.js";
3
- import { display, stopSpinner } from "./display.js";
3
+ import { display } from "./display.js";
4
4
 
5
5
  async function runCommand(command: string, interactive: boolean = false) {
6
6
  try {
7
7
  const [commandName, ...args] = command.split(" ");
8
8
 
9
9
  if (interactive) {
10
- // Stop spinner before interactive command
11
- stopSpinner("Starting interactive command...", 0);
12
10
  await execa(commandName as string, args, {
13
11
  stdio: "inherit",
14
12
  });
@@ -26,7 +24,7 @@ async function runCommand(command: string, interactive: boolean = false) {
26
24
  }
27
25
 
28
26
  /**
29
- * Takes the interactive and non interactive command from each item in the CommandResult Array
27
+ * Install all commands
30
28
  */
31
29
  export async function install(commands: CommandResult[]) {
32
30
  try {
@@ -40,7 +38,7 @@ export async function install(commands: CommandResult[]) {
40
38
  }
41
39
 
42
40
  // Then run non-interactive
43
- if (command.nonInteractive) {
41
+ if (command.nonInteractive.length > 0) {
44
42
  // For non-interactive, we show a spinner
45
43
  display(`Running command: ${command.nonInteractive[0]}`, "loading");
46
44
  await runCommand(command.nonInteractive[0] as string, false);
@@ -1,6 +1,6 @@
1
1
  import { buildCommands, buildUninstallCommands } from "./build_command.js";
2
2
  import { getConfigObject } from "./config_reader.js";
3
- import { display, stopSpinner } from "./display.js";
3
+ import { display } from "./display.js";
4
4
  import { install } from "./install.js";
5
5
  import type { ConfigType } from "./types/index.js";
6
6
  import { outro } from "@clack/prompts";
@@ -38,14 +38,13 @@ export const orchestrator = (
38
38
 
39
39
  if (isConfigTypeArray(config)) {
40
40
  const commands = buildCommands(config);
41
+
41
42
  await install(commands);
42
- stopSpinner("Packages installed successfully");
43
- process.stdout.write("\x07");
43
+ display("Packages installed successfully", "success");
44
44
  outro("Done!");
45
45
  } else {
46
46
  await install(config);
47
-
48
- stopSpinner("Packages from package.json installed successfully");
47
+ display("Packages from package.json installed successfully", "success");
49
48
  outro("Done!");
50
49
  }
51
50
  });
@@ -64,7 +63,7 @@ export const orchestrator = (
64
63
  if (isConfigTypeArray(config)) {
65
64
  const commands = buildUninstallCommands(config);
66
65
  await install(commands);
67
- stopSpinner("Packages uninstalled successfully");
66
+ display("Packages uninstalled successfully", "success");
68
67
  outro("Done!");
69
68
  }
70
69
  });
@@ -1,16 +1,17 @@
1
- export interface ConfigType {
2
- name: string;
3
- packageManager: string;
4
- packages: { command: string; interactive: boolean }[];
5
- }
6
-
7
- export interface PackageType {
8
- command: string;
9
- interactive: boolean;
10
- }
11
-
12
- export interface CommandResult {
13
- name: string;
14
- interactive: string[];
15
- nonInteractive: string[];
16
- }
1
+ export interface ConfigType {
2
+ name: string;
3
+ description?: string;
4
+ packageManager: string;
5
+ packages: { command: string; interactive: boolean }[];
6
+ }
7
+
8
+ export interface PackageType {
9
+ command: string;
10
+ interactive: boolean;
11
+ }
12
+
13
+ export interface CommandResult {
14
+ name: string;
15
+ interactive: string[];
16
+ nonInteractive: string[];
17
+ }