pixelstart 1.0.0 → 1.1.0

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.js CHANGED
@@ -5,7 +5,7 @@ import { banner, section, success, error, info } from './modules/ui.js';
5
5
  import { checkRequirements } from './modules/requirements.js';
6
6
  import { showNDA } from './modules/nda.js';
7
7
  import { initProject } from './modules/init.js';
8
- const VERSION = '1.0.0';
8
+ const VERSION = '1.1.0';
9
9
  async function main() {
10
10
  const args = process.argv.slice(2);
11
11
  const command = args[0];
@@ -1,77 +1,232 @@
1
1
  import { execSync } from 'child_process';
2
+ import inquirer from 'inquirer';
2
3
  import chalk from 'chalk';
3
4
  import { success, error, warn, info, section } from './ui.js';
5
+ const P = '#7C3AED';
6
+ const R = '#EF4444';
7
+ const G = '#22C55E';
8
+ const Y = '#EAB308';
9
+ const C = '#06B6D4';
10
+ function c(hex, text) {
11
+ return String(chalk.hex(hex)(text));
12
+ }
13
+ function cb(hex, text) {
14
+ return String(chalk.hex(hex).bold(text));
15
+ }
16
+ function getPlatform() {
17
+ return process.platform;
18
+ }
19
+ function isRoot() {
20
+ if (getPlatform() === 'win32')
21
+ return true;
22
+ try {
23
+ execSync('id -u', { stdio: 'pipe' });
24
+ return execSync('id -u', { encoding: 'utf-8', stdio: 'pipe' }).trim() === '0';
25
+ }
26
+ catch {
27
+ return false;
28
+ }
29
+ }
30
+ function run(cmd, opts = {}) {
31
+ try {
32
+ const full = opts.sudo && !isRoot() ? `sudo ${cmd}` : cmd;
33
+ execSync(full, { stdio: 'pipe', timeout: 120000 });
34
+ return true;
35
+ }
36
+ catch {
37
+ return false;
38
+ }
39
+ }
40
+ function parseVersion(output) {
41
+ return output.replace(/^[^\d]*/, '').split('+')[0].trim();
42
+ }
43
+ function compareVersions(a, b) {
44
+ const pa = a.split('.').map(Number);
45
+ const pb = b.split('.').map(Number);
46
+ for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
47
+ const na = pa[i] || 0;
48
+ const nb = pb[i] || 0;
49
+ if (na > nb)
50
+ return 1;
51
+ if (na < nb)
52
+ return -1;
53
+ }
54
+ return 0;
55
+ }
56
+ // ── Install functions per platform ──────────────────────────────────────────
57
+ function getNodeInstallCmd(platform) {
58
+ switch (platform) {
59
+ case 'linux':
60
+ return [
61
+ 'curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -',
62
+ 'sudo apt-get install -y nodejs',
63
+ ];
64
+ case 'darwin':
65
+ return ['brew install node@22'];
66
+ case 'win32':
67
+ return ['winget install OpenJS.NodeJS.LTS --accept-package-agreements --accept-source-agreements'];
68
+ }
69
+ }
70
+ function getDockerInstallCmd(platform) {
71
+ switch (platform) {
72
+ case 'linux':
73
+ return [
74
+ 'curl -fsSL https://get.docker.com | sudo sh',
75
+ 'sudo usermod -aG docker $USER',
76
+ ];
77
+ case 'darwin':
78
+ return ['brew install --cask docker'];
79
+ case 'win32':
80
+ return ['winget install Docker.DockerDesktop --accept-package-agreements --accept-source-agreements'];
81
+ }
82
+ }
83
+ function getPnpmInstallCmd() {
84
+ return ['npm install -g pnpm@9'];
85
+ }
4
86
  const REQUIREMENTS = [
5
87
  {
6
88
  name: 'Node.js',
7
89
  command: 'node --version',
8
90
  minVersion: '22.0.0',
9
91
  required: true,
10
- installHint: 'Install Node.js 22+: https://nodejs.org/',
92
+ getInstallCmd: getNodeInstallCmd,
93
+ installHint: 'https://nodejs.org/',
11
94
  },
12
95
  {
13
96
  name: 'Docker',
14
97
  command: 'docker --version',
15
98
  required: true,
16
- installHint: 'Install Docker: https://docs.docker.com/get-docker/',
99
+ getInstallCmd: getDockerInstallCmd,
100
+ installHint: 'https://docs.docker.com/get-docker/',
17
101
  },
18
102
  {
19
103
  name: 'Docker Compose',
20
104
  command: 'docker compose version',
21
105
  required: true,
22
- installHint: 'Install Docker Compose: https://docs.docker.com/compose/install/',
106
+ getInstallCmd: () => [],
107
+ installHint: 'Included with Docker Desktop',
23
108
  },
24
109
  {
25
110
  name: 'pnpm',
26
111
  command: 'pnpm --version',
27
112
  minVersion: '9.0.0',
28
113
  required: false,
29
- installHint: 'Install pnpm: npm install -g pnpm@9',
114
+ getInstallCmd: getPnpmInstallCmd,
115
+ installHint: 'npm install -g pnpm@9',
30
116
  },
31
117
  ];
32
- function parseVersion(output) {
33
- return output.replace(/^[^\d]*/, '').split('+')[0].trim();
34
- }
35
- function compareVersions(a, b) {
36
- const pa = a.split('.').map(Number);
37
- const pb = b.split('.').map(Number);
38
- for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
39
- const na = pa[i] || 0;
40
- const nb = pb[i] || 0;
41
- if (na > nb)
42
- return 1;
43
- if (na < nb)
44
- return -1;
45
- }
46
- return 0;
47
- }
48
- function checkRequirement(req) {
118
+ function checkRequirement(req, platform) {
49
119
  try {
50
120
  const output = execSync(req.command, { encoding: 'utf-8', stdio: 'pipe' }).trim();
51
121
  const version = parseVersion(output);
52
122
  const meetsMin = req.minVersion ? compareVersions(version, req.minVersion) >= 0 : true;
53
- return { name: req.name, installed: true, version, meetsMin, required: req.required, minVersion: req.minVersion, installHint: req.installHint };
123
+ return {
124
+ name: req.name, installed: true, version, meetsMin,
125
+ required: req.required, minVersion: req.minVersion,
126
+ installCmds: req.getInstallCmd(platform), installHint: req.installHint,
127
+ };
54
128
  }
55
129
  catch {
56
- return { name: req.name, installed: false, required: req.required, installHint: req.installHint };
130
+ return {
131
+ name: req.name, installed: false,
132
+ required: req.required, minVersion: req.minVersion,
133
+ installCmds: req.getInstallCmd(platform), installHint: req.installHint,
134
+ };
57
135
  }
58
136
  }
137
+ async function autoInstall(name, cmds) {
138
+ console.log('');
139
+ info(c(C, `Installing ${name}...`));
140
+ console.log('');
141
+ for (const cmd of cmds) {
142
+ console.log(c(P, ` $ ${cmd}`));
143
+ const sudo = cmd.startsWith('sudo');
144
+ const ok = run(cmd, { sudo });
145
+ if (!ok) {
146
+ error(c(R, `Failed to install ${name}.`));
147
+ info('You may need to run this command manually or check your internet connection.');
148
+ return false;
149
+ }
150
+ }
151
+ console.log('');
152
+ success(c(G, `${name} installed successfully!`));
153
+ return true;
154
+ }
59
155
  export async function checkRequirements() {
60
156
  section('System Requirements');
61
- const results = REQUIREMENTS.map(checkRequirement);
157
+ const platform = getPlatform();
158
+ const platformNames = { linux: 'Linux', darwin: 'macOS', win32: 'Windows' };
159
+ info(c(C, `Detected platform: ${platformNames[platform]}`));
160
+ if (!isRoot() && platform !== 'win32') {
161
+ info(c(Y, 'Some operations may require sudo (password may be prompted)'));
162
+ }
163
+ console.log('');
164
+ const results = REQUIREMENTS.map(r => checkRequirement(r, platform));
62
165
  let allPassed = true;
63
166
  for (const r of results) {
64
167
  if (!r.installed) {
65
- error(`${chalk.bold(r.name)} not found`);
66
- info(r.installHint);
67
- if (r.required)
68
- allPassed = false;
168
+ if (r.installCmds.length > 0) {
169
+ const { wantInstall } = await inquirer.prompt([{
170
+ type: 'confirm',
171
+ name: 'wantInstall',
172
+ message: cb(R, ` ${r.name} is not installed. Install it now?`),
173
+ default: true,
174
+ }]);
175
+ if (wantInstall) {
176
+ const ok = await autoInstall(r.name, r.installCmds);
177
+ if (!ok) {
178
+ if (r.required)
179
+ allPassed = false;
180
+ }
181
+ else {
182
+ // Re-check after install
183
+ const recheck = checkRequirement(REQUIREMENTS.find(x => x.name === r.name), platform);
184
+ if (recheck.installed && recheck.meetsMin !== false) {
185
+ success(cb(G, `${r.name} ${recheck.version || ''}`));
186
+ }
187
+ else if (r.required) {
188
+ allPassed = false;
189
+ }
190
+ }
191
+ }
192
+ else {
193
+ error(`${chalk.bold(r.name)} is required but not installed.`);
194
+ info(r.installHint);
195
+ if (r.required)
196
+ allPassed = false;
197
+ }
198
+ }
199
+ else {
200
+ error(`${chalk.bold(r.name)} not found`);
201
+ info(r.installHint);
202
+ if (r.required)
203
+ allPassed = false;
204
+ }
69
205
  }
70
206
  else if (r.meetsMin === false) {
71
- warn(`${chalk.bold(r.name)} ${r.version} requires ${r.minVersion}+`);
72
- info(r.installHint);
73
- if (r.required)
74
- allPassed = false;
207
+ if (r.installCmds.length > 0) {
208
+ const { wantUpgrade } = await inquirer.prompt([{
209
+ type: 'confirm',
210
+ name: 'wantUpgrade',
211
+ message: cb(Y, ` ${r.name} ${r.version} is too old (need ${r.minVersion}+). Upgrade?`),
212
+ default: true,
213
+ }]);
214
+ if (wantUpgrade) {
215
+ const ok = await autoInstall(r.name, r.installCmds);
216
+ if (!ok && r.required)
217
+ allPassed = false;
218
+ }
219
+ else {
220
+ if (r.required)
221
+ allPassed = false;
222
+ }
223
+ }
224
+ else {
225
+ warn(`${chalk.bold(r.name)} ${r.version} — requires ${r.minVersion}+`);
226
+ info(r.installHint);
227
+ if (r.required)
228
+ allPassed = false;
229
+ }
75
230
  }
76
231
  else {
77
232
  success(`${chalk.bold(r.name)} ${chalk.gray(r.version || '')}`);
@@ -79,7 +234,8 @@ export async function checkRequirements() {
79
234
  }
80
235
  console.log('');
81
236
  if (!allPassed) {
82
- error('Missing required dependencies. Please install them and try again.');
237
+ error('Some required dependencies could not be installed.');
238
+ info('Please install them manually and try again.');
83
239
  return false;
84
240
  }
85
241
  return true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pixelstart",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "PixelStack Lite CLI — scaffold, license, and deploy PixelStack projects",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",