pixelstart 1.0.0 → 1.2.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.2.0';
9
9
  async function main() {
10
10
  const args = process.argv.slice(2);
11
11
  const command = args[0];
@@ -47,7 +47,7 @@ async function main() {
47
47
  async function retryPull() {
48
48
  section('Pull Docker Image');
49
49
  const inquirer = await import('inquirer');
50
- const { validateLicense, exchangeDownloadToken } = await import('./modules/license.js');
50
+ const { validateLicense, exchangeDownloadToken, buildDockerCommands } = await import('./modules/license.js');
51
51
  const { key } = await inquirer.default.prompt([
52
52
  {
53
53
  type: 'input',
@@ -71,14 +71,18 @@ async function retryPull() {
71
71
  info('Pulling Docker image...');
72
72
  const { execSync } = await import('child_process');
73
73
  try {
74
- execSync(downloadResult.dockerCommand, { stdio: 'inherit' });
74
+ const { login, pull } = buildDockerCommands(downloadResult);
75
+ execSync(login, { stdio: 'inherit' });
76
+ execSync(pull, { stdio: 'inherit' });
75
77
  console.log('');
76
78
  success(`Docker image ${chalk.bold(downloadResult.image)} pulled successfully!`);
77
79
  }
78
80
  catch {
79
81
  error('Docker pull failed. You can retry manually:');
80
82
  console.log('');
81
- console.log(chalk.white(` ${downloadResult.dockerCommand}`));
83
+ const { login, pull } = buildDockerCommands(downloadResult);
84
+ console.log(chalk.white(` ${login}`));
85
+ console.log(chalk.white(` ${pull}`));
82
86
  }
83
87
  }
84
88
  function printHelp() {
@@ -4,7 +4,7 @@ import path from 'path';
4
4
  import inquirer from 'inquirer';
5
5
  import chalk from 'chalk';
6
6
  import { section, success, error, info } from './ui.js';
7
- import { validateLicense, exchangeDownloadToken } from './license.js';
7
+ import { validateLicense, exchangeDownloadToken, buildDockerCommands } from './license.js';
8
8
  export async function initProject() {
9
9
  section('Project Setup');
10
10
  const config = await inquirer.prompt([
@@ -103,14 +103,18 @@ data/
103
103
  info('Pulling Docker image...');
104
104
  console.log('');
105
105
  try {
106
- execSync(downloadResult.dockerCommand, { stdio: 'inherit' });
106
+ const { login, pull } = buildDockerCommands(downloadResult);
107
+ execSync(login, { stdio: 'inherit' });
108
+ execSync(pull, { stdio: 'inherit' });
107
109
  console.log('');
108
110
  success(`Docker image ${chalk.bold(downloadResult.image)} pulled successfully!`);
109
111
  }
110
112
  catch (err) {
111
113
  error('Docker pull failed. You can retry manually:');
112
114
  console.log('');
113
- console.log(chalk.white(` ${downloadResult.dockerCommand}`));
115
+ const { login, pull } = buildDockerCommands(downloadResult);
116
+ console.log(chalk.white(` ${login}`));
117
+ console.log(chalk.white(` ${pull}`));
114
118
  }
115
119
  console.log('');
116
120
  success(`Project "${chalk.bold(config.name)}" created!`);
@@ -7,12 +7,19 @@ export interface LicenseValidation {
7
7
  }
8
8
  export interface DownloadResult {
9
9
  success: boolean;
10
- dockerCommand: string;
10
+ token: string;
11
11
  image: string;
12
+ owner: string;
13
+ imageName: string;
12
14
  tag: string;
15
+ registry: string;
13
16
  }
14
17
  export declare function validateLicense(licenseKey: string, imageTag: string): Promise<LicenseValidation | null>;
15
18
  export declare function exchangeDownloadToken(token: string): Promise<DownloadResult | null>;
19
+ export declare function buildDockerCommands(result: DownloadResult): {
20
+ login: string;
21
+ pull: string;
22
+ };
16
23
  export declare function showLicense(): Promise<{
17
24
  key: string;
18
25
  imageTag: string;
@@ -1,5 +1,5 @@
1
1
  import chalk from 'chalk';
2
- import { section, success, error, info } from './ui.js';
2
+ import { success, error, info, section } from './ui.js';
3
3
  const SUPABASE_URL = 'https://qnuzhgozszftvvxsnaos.supabase.co';
4
4
  const ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InFudXpoZ296c3pmdHZ2eHNuYW9zIiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODM0MjEwODMsImV4cCI6MjA5ODk5NzA4M30.q3mgpAS8nm1OtvnlKuOgTEi_vLmb46bV0sf3bS-fSCg';
5
5
  const EDGE_FUNCTION = `${SUPABASE_URL}/functions/v1/proxy-package`;
@@ -51,6 +51,11 @@ export async function exchangeDownloadToken(token) {
51
51
  return null;
52
52
  }
53
53
  }
54
+ export function buildDockerCommands(result) {
55
+ const login = `echo ${result.token} | docker login ${result.registry} -u ${result.owner} --password-stdin`;
56
+ const pull = `docker pull ${result.image}`;
57
+ return { login, pull };
58
+ }
54
59
  export async function showLicense() {
55
60
  section('License');
56
61
  console.log(chalk.white(' Enter your PixelStack license key to download the image.'));
@@ -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.2.0",
4
4
  "description": "PixelStack Lite CLI — scaffold, license, and deploy PixelStack projects",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",