at-builder 1.2.8 → 1.3.3

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.
@@ -0,0 +1,236 @@
1
+ /* eslint-disable no-undef */
2
+ /* eslint-env node */
3
+ 'use strict';
4
+
5
+ /**
6
+ * Shared install-environment validation for at-builder.
7
+ *
8
+ * Used by both:
9
+ * - lib/postinstall.js — runs once on `npm i -g at-builder`
10
+ * - src/services/doctor.ts — surfaces the same problems via `atb doctor`
11
+ * for users who installed with `--ignore-scripts` or who skipped the
12
+ * postinstall warnings.
13
+ *
14
+ * checkInstallEnvironment() returns pure data — no console I/O — so the
15
+ * caller decides how to present results. The one side effect is an attempt
16
+ * to chmod 755 the shim / local bin script on POSIX when fixPermissions is
17
+ * true (the default), since that's a fix, not output.
18
+ */
19
+
20
+ const fs = require('fs');
21
+ const path = require('path');
22
+ const { execFileSync } = require('child_process');
23
+
24
+ function isLikelyGlobalInstall() {
25
+ if (String(process.env.npm_config_global || '').toLowerCase() === 'true') return true;
26
+ try {
27
+ const argv = JSON.parse(process.env.npm_config_argv || '{}');
28
+ const cooked = Array.isArray(argv.cooked) ? argv.cooked : [];
29
+ return cooked.includes('-g') || cooked.includes('--global');
30
+ } catch {
31
+ return false;
32
+ }
33
+ }
34
+
35
+ function getPathEntries() {
36
+ const isWin = process.platform === 'win32';
37
+ const sep = isWin ? ';' : ':';
38
+ return (process.env.PATH || process.env.Path || '')
39
+ .split(sep)
40
+ .map((p) => p.trim())
41
+ .filter(Boolean);
42
+ }
43
+
44
+ function normalizeForCompare(pth) {
45
+ const isWin = process.platform === 'win32';
46
+ let n = path.normalize(pth || '');
47
+ if (isWin) n = n.toLowerCase();
48
+ return n.replace(/[\\/]+$/, '');
49
+ }
50
+
51
+ // `npm bin -g` was removed in npm 9. Use `npm config get prefix` instead.
52
+ // execFileSync (not execSync) — argv is hardcoded but execFile avoids a shell
53
+ // entirely on POSIX. On Windows we set shell:true so npm.cmd is found.
54
+ function npmPrefixBin() {
55
+ try {
56
+ const out = execFileSync('npm', ['config', 'get', 'prefix'], {
57
+ stdio: ['ignore', 'pipe', 'ignore'],
58
+ timeout: 2500,
59
+ shell: process.platform === 'win32'
60
+ }).toString().trim();
61
+ if (!out) return '';
62
+ const isWin = process.platform === 'win32';
63
+ return isWin ? path.join(out, 'npm') : path.join(out, 'bin');
64
+ } catch {
65
+ return '';
66
+ }
67
+ }
68
+
69
+ function windowsDefaultNpmBin() {
70
+ const appData = process.env.APPDATA;
71
+ if (!appData) return '';
72
+ return path.join(appData, 'npm');
73
+ }
74
+
75
+ function dedupe(arr, keyFn = (v) => v) {
76
+ const seen = new Set();
77
+ const out = [];
78
+ for (const v of arr) {
79
+ const k = keyFn(v);
80
+ if (!seen.has(k)) {
81
+ seen.add(k);
82
+ out.push(v);
83
+ }
84
+ }
85
+ return out;
86
+ }
87
+
88
+ function detectGlobalBinCandidates() {
89
+ const candidates = [];
90
+
91
+ const pref = npmPrefixBin();
92
+ if (pref) candidates.push(pref);
93
+
94
+ if (process.platform === 'win32') {
95
+ const appBin = windowsDefaultNpmBin();
96
+ if (appBin) candidates.push(appBin);
97
+ }
98
+
99
+ if (process.env.npm_config_prefix) {
100
+ const isWin = process.platform === 'win32';
101
+ candidates.push(path.join(process.env.npm_config_prefix, isWin ? 'npm' : 'bin'));
102
+ }
103
+
104
+ return dedupe(candidates.filter(Boolean), (p) => normalizeForCompare(p));
105
+ }
106
+
107
+ function findExistingDir(dirs) {
108
+ for (const d of dirs) {
109
+ try {
110
+ if (fs.existsSync(d) && fs.statSync(d).isDirectory()) return d;
111
+ } catch {
112
+ // ignore
113
+ }
114
+ }
115
+ return '';
116
+ }
117
+
118
+ function isExecutable(filePath) {
119
+ if (!fs.existsSync(filePath)) return false;
120
+ if (process.platform === 'win32') return true;
121
+ try {
122
+ fs.accessSync(filePath, fs.constants.X_OK);
123
+ return true;
124
+ } catch {
125
+ return false;
126
+ }
127
+ }
128
+
129
+ function ensureExecutable(filePath) {
130
+ if (process.platform === 'win32') return true;
131
+ try {
132
+ if (!fs.existsSync(filePath)) return false;
133
+ const st = fs.statSync(filePath);
134
+ if ((st.mode & 0o111) === 0) {
135
+ fs.chmodSync(filePath, 0o755);
136
+ }
137
+ return isExecutable(filePath);
138
+ } catch {
139
+ return false;
140
+ }
141
+ }
142
+
143
+ /**
144
+ * @param {object} [opts]
145
+ * @param {string} [opts.localBinScript] absolute path to this package's bin/index.js;
146
+ * used to verify/repair its POSIX exec bit. Defaults to bin/index.js relative to this file.
147
+ * @param {boolean} [opts.fixPermissions=true] auto-chmod 755 on POSIX when missing exec bit.
148
+ * @returns {{
149
+ * ok: boolean,
150
+ * problems: string[],
151
+ * globalBin: string,
152
+ * shimPath: string,
153
+ * shimExecutable: boolean,
154
+ * isWin: boolean,
155
+ * isGlobalInstall: boolean,
156
+ * nodeMajor: number
157
+ * }}
158
+ */
159
+ function checkInstallEnvironment(opts = {}) {
160
+ const isWin = process.platform === 'win32';
161
+ const localBinScript = opts.localBinScript || path.resolve(__dirname, '..', 'bin', 'index.js');
162
+ const fixPermissions = opts.fixPermissions !== false;
163
+ const isGlobalInstall = isLikelyGlobalInstall();
164
+
165
+ const problems = [];
166
+ let globalBin = '';
167
+ let shimPath = '';
168
+ let shimExecutable = false;
169
+
170
+ // Node version check (soft)
171
+ const nodeVer = process.versions.node || '';
172
+ const minNodeMajor = 16;
173
+ const major = parseInt(nodeVer.split('.')[0] || '0', 10);
174
+ const nodeMajor = Number.isFinite(major) ? major : 0;
175
+ if (nodeMajor && nodeMajor < minNodeMajor) {
176
+ problems.push(`Node.js version too low (${nodeVer}). Please upgrade to >= ${minNodeMajor}.x`);
177
+ }
178
+
179
+ // Local bin script exec bit (POSIX only) — useful for npm link / local dev too.
180
+ if (!isWin && fixPermissions) {
181
+ if (fs.existsSync(localBinScript) && !ensureExecutable(localBinScript)) {
182
+ problems.push(`Local bin script not executable: ${localBinScript}`);
183
+ }
184
+ }
185
+
186
+ // Global bin discovery + shim verification
187
+ const pathEntries = getPathEntries().map(normalizeForCompare);
188
+ const candidates = detectGlobalBinCandidates();
189
+ globalBin = findExistingDir(candidates);
190
+
191
+ if (!globalBin) {
192
+ problems.push('Could not determine global npm bin directory.');
193
+ } else {
194
+ const globalBinNorm = normalizeForCompare(globalBin);
195
+ if (!pathEntries.includes(globalBinNorm)) {
196
+ problems.push(`Global npm bin is not on PATH: ${globalBin}`);
197
+ }
198
+
199
+ const atbUnix = path.join(globalBin, 'atb');
200
+ const atbCmd = path.join(globalBin, 'atb.cmd');
201
+ const atbPs1 = path.join(globalBin, 'atb.ps1');
202
+ const shims = [atbUnix, atbCmd, atbPs1].filter((p) => fs.existsSync(p));
203
+
204
+ if (shims.length === 0) {
205
+ problems.push(`"atb" binary not found in global npm bin: ${globalBin}`);
206
+ } else {
207
+ const preferred = isWin ? [atbCmd, atbPs1] : [atbUnix];
208
+ shimPath = preferred.find((p) => fs.existsSync(p)) || shims[0];
209
+
210
+ if (!isExecutable(shimPath)) {
211
+ if (fixPermissions) ensureExecutable(shimPath);
212
+ if (!isExecutable(shimPath)) {
213
+ problems.push(`"atb" shim exists but is not executable: ${shimPath}`);
214
+ }
215
+ }
216
+ shimExecutable = isExecutable(shimPath);
217
+ }
218
+ }
219
+
220
+ return {
221
+ ok: problems.length === 0,
222
+ problems,
223
+ globalBin,
224
+ shimPath,
225
+ shimExecutable,
226
+ isWin,
227
+ isGlobalInstall,
228
+ nodeMajor
229
+ };
230
+ }
231
+
232
+ module.exports = {
233
+ checkInstallEnvironment,
234
+ isExecutable,
235
+ ensureExecutable
236
+ };
@@ -0,0 +1,90 @@
1
+ /* eslint-disable no-undef, no-console */
2
+ /* eslint-env node */
3
+ 'use strict';
4
+
5
+ /**
6
+ * Cross-platform postinstall validator for at-builder.
7
+ *
8
+ * Runs once on `npm i -g at-builder`. Verifies that the global npm bin is
9
+ * on PATH and that the `atb` shim exists + is executable. Auto-chmods the
10
+ * shim on POSIX when possible. Emits OS-specific guidance otherwise.
11
+ *
12
+ * Never fails the install: any unexpected error is caught, and the script
13
+ * always exits 0. Worst case, the user sees a warning instead of a blocked
14
+ * install. The same checks are mirrored in `atb doctor` for users who skip
15
+ * scripts.
16
+ */
17
+
18
+ const path = require('path');
19
+ const { checkInstallEnvironment } = require('./install-checks');
20
+
21
+ function c(code, text) { return `\u001b[${code}m${text}\u001b[0m`; }
22
+ const red = (t) => c('31', t);
23
+ const yellow = (t) => c('33', t);
24
+ const green = (t) => c('32', t);
25
+ const bold = (t) => c('1', t);
26
+
27
+ (function run() {
28
+ try {
29
+ const result = checkInstallEnvironment({
30
+ localBinScript: path.resolve(__dirname, '..', 'bin', 'index.js')
31
+ });
32
+
33
+ // For local installs (e.g. someone adding at-builder as a project dep
34
+ // — not a documented use case but possible), stay silent. The chmod
35
+ // side effect inside checkInstallEnvironment already ran.
36
+ if (!result.isGlobalInstall) return;
37
+
38
+ if (result.ok) {
39
+ console.log(green('✔ at-builder postinstall checks passed.'));
40
+ if (result.globalBin) console.log(`Detected global npm bin: ${bold(result.globalBin)}`);
41
+ if (result.shimPath) {
42
+ console.log(`Using shim: ${bold(result.shimPath)}${!result.isWin ? ' (POSIX exec verified)' : ''}`);
43
+ }
44
+ return;
45
+ }
46
+
47
+ console.error(red('✖ at-builder postinstall detected configuration issues:'));
48
+ for (const p of result.problems) console.error(red(`- ${p}`));
49
+
50
+ if (result.isWin) {
51
+ console.error(yellow('\nSuggested fixes (Windows):'));
52
+ if (result.globalBin) {
53
+ console.error(bold('PowerShell (current user):'));
54
+ console.error(` ${bold(`[Environment]::SetEnvironmentVariable("Path", "$env:Path;${result.globalBin}", "User")`)}`);
55
+ console.error(bold('Then restart your terminal.'));
56
+ console.error(bold('\nCMD (current user):'));
57
+ console.error(` ${bold(`setx PATH "%PATH%;${result.globalBin}"`)}`);
58
+ console.error(bold('Then restart your terminal.'));
59
+ } else {
60
+ console.error(bold('Find your npm global bin via: npm config get prefix'));
61
+ console.error(bold('Then add it to PATH using PowerShell or setx as shown above.'));
62
+ }
63
+ console.error(bold('\nReinstall the CLI after fixing PATH:'));
64
+ console.error(bold(' npm uninstall -g at-builder && npm install -g at-builder'));
65
+ } else {
66
+ console.error(yellow('\nSuggested fixes (macOS/Linux):'));
67
+ if (result.globalBin) {
68
+ console.error(bold('# Ensure the shim is executable'));
69
+ console.error(` ${bold(`chmod +x "${path.join(result.globalBin, 'atb')}"`)}`);
70
+ console.error(bold('# Ensure global npm bin is on PATH'));
71
+ console.error(` ${bold(`echo 'export PATH="$PATH:${result.globalBin}"' >> ~/.zshrc && source ~/.zshrc`)}`);
72
+ console.error(bold('# Refresh shell command cache'));
73
+ console.error(` ${bold('hash -r || true')}`);
74
+ } else {
75
+ console.error(bold(`prefix="$(npm config get prefix)"`));
76
+ console.error(bold(`echo 'export PATH="$PATH:'"$prefix"'/bin"' >> ~/.zshrc && source ~/.zshrc`));
77
+ }
78
+ console.error(bold('\nThen reinstall the CLI:'));
79
+ console.error(bold(' npm uninstall -g at-builder && npm install -g at-builder'));
80
+ }
81
+
82
+ console.error(yellow('\nThis is a warning — install is complete. Run "atb doctor" later to re-check.'));
83
+ } catch (err) {
84
+ // Belt-and-suspenders: a bug here must NEVER fail the install.
85
+ console.error(`[at-builder postinstall] unexpected error (install will continue): ${err && err.message ? err.message : err}`);
86
+ } finally {
87
+ // Always succeed — see file header.
88
+ process.exit(0);
89
+ }
90
+ })();
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "at-builder",
3
+ "version": "1.3.0",
4
+ "main": "bin/index.js",
5
+ "bin": {
6
+ "atb": "bin/index.js"
7
+ },
8
+ "scripts": {
9
+ "build:atb": "tsc",
10
+ "build:atb:dev": "tsc -w",
11
+ "atb:build:prod": "cross-env NODE_ENV=production webpack",
12
+ "atb:build:dev": "webpack -- -w",
13
+ "atb:build:dev:puppeteer": "webpack -- -w & npm run atb:puppeteer",
14
+ "atb:puppeteer": "node puppeteer.js $b",
15
+ "atb:plop:new:activity": "plop page",
16
+ "atb:build:deploy": "node lib/at-deploy.js",
17
+ "atb:build:sync": "node lib/at-sync.js"
18
+ },
19
+ "author": "Upendra Sengar <upendrasengar456@gmail.com>",
20
+ "license": "MIT",
21
+ "dependencies": {
22
+ "@babel/core": "^7.26.9",
23
+ "@babel/eslint-parser": "^7.26.8",
24
+ "@babel/plugin-proposal-class-properties": "^7.18.6",
25
+ "@babel/plugin-syntax-dynamic-import": "^7.8.3",
26
+ "@babel/plugin-transform-runtime": "^7.18.9",
27
+ "@babel/preset-env": "^7.18.9",
28
+ "@babel/preset-react": "^7.18.6",
29
+ "@eslint/js": "^9.20.0",
30
+ "@types/node": "^22.13.2",
31
+ "async": "^3.2.3",
32
+ "axios": "^1.12.2",
33
+ "babel-loader": "^9.2.1",
34
+ "babel-plugin-transform-async-to-generator": "^6.24.1",
35
+ "build": "^0.1.4",
36
+ "chokidar": "^4.0.3",
37
+ "cli-color": "^2.0.3",
38
+ "commander": "^13.1.0",
39
+ "cross-env": "^7.0.3",
40
+ "css-loader": "^7.1.2",
41
+ "dotenv": "16.4.5",
42
+ "eslint": "^9.20.1",
43
+ "eslint-webpack-plugin": "^4.2.0",
44
+ "globals": "^15.15.0",
45
+ "inquirer": "^12.4.1",
46
+ "kleur": "^4.1.5",
47
+ "plop": "^4.0.1",
48
+ "postcss": "^8.4.12",
49
+ "postcss-loader": "^8.1.1",
50
+ "postcss-preset-env": "^10.1.4",
51
+ "puppeteer": "^24.2.0",
52
+ "querystring": "^0.2.1",
53
+ "readline": "^1.3.0",
54
+ "sass": "^1.53.0",
55
+ "sass-loader": "^16.0.4",
56
+ "style-loader": "^4.0.0",
57
+ "terser-webpack-plugin": "^5.3.3",
58
+ "ts-loader": "^9.3.1",
59
+ "typescript": "^5.7.3",
60
+ "typescript-eslint": "^8.24.1",
61
+ "webpack": "^5.72.0",
62
+ "webpack-cli": "^6.0.1",
63
+ "wrapper-webpack-plugin": "^2.1.0"
64
+ },
65
+ "description": "[![npm version](https://badge.fury.io/js/at-builder.svg)](https://www.npmjs.com/package/at-builder) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)",
66
+ "directories": {
67
+ "lib": "lib",
68
+ "test": "test"
69
+ },
70
+ "devDependencies": {
71
+ "@babel/runtime": "^7.29.2"
72
+ },
73
+ "repository": {
74
+ "type": "git",
75
+ "url": "git+https://github.com/upesenga/at-builder.git"
76
+ },
77
+ "keywords": [],
78
+ "bugs": {
79
+ "url": "https://github.com/upesenga/at-builder/issues"
80
+ },
81
+ "homepage": "https://github.com/upesenga/at-builder#readme",
82
+ "engines": {
83
+ "node": ">=16.0.0"
84
+ },
85
+ "packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"
86
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "at-builder",
3
- "version": "1.2.8",
3
+ "version": "1.3.3",
4
4
  "main": "bin/index.js",
5
5
  "bin": {
6
6
  "atb": "bin/index.js"
@@ -13,7 +13,9 @@
13
13
  "atb:build:dev:puppeteer": "webpack -- -w & npm run atb:puppeteer",
14
14
  "atb:puppeteer": "node puppeteer.js $b",
15
15
  "atb:plop:new:activity": "plop page",
16
- "atb:build:deploy": "node lib/at-deploy.js"
16
+ "atb:build:deploy": "node lib/at-deploy.js",
17
+ "atb:build:sync": "node lib/at-sync.js",
18
+ "postinstall": "node lib/postinstall.js"
17
19
  },
18
20
  "author": "Upendra Sengar <upendrasengar456@gmail.com>",
19
21
  "license": "MIT",
@@ -25,6 +27,7 @@
25
27
  "@babel/plugin-transform-runtime": "^7.18.9",
26
28
  "@babel/preset-env": "^7.18.9",
27
29
  "@babel/preset-react": "^7.18.6",
30
+ "@eslint/js": "^9.20.0",
28
31
  "@types/node": "^22.13.2",
29
32
  "async": "^3.2.3",
30
33
  "axios": "^1.12.2",
@@ -36,10 +39,12 @@
36
39
  "commander": "^13.1.0",
37
40
  "cross-env": "^7.0.3",
38
41
  "css-loader": "^7.1.2",
39
- "dotenv": "^16.0.0",
42
+ "dotenv": "16.4.5",
40
43
  "eslint": "^9.20.1",
41
44
  "eslint-webpack-plugin": "^4.2.0",
45
+ "globals": "^15.15.0",
42
46
  "inquirer": "^12.4.1",
47
+ "kleur": "^4.1.5",
43
48
  "plop": "^4.0.1",
44
49
  "postcss": "^8.4.12",
45
50
  "postcss-loader": "^8.1.1",
@@ -53,21 +58,19 @@
53
58
  "terser-webpack-plugin": "^5.3.3",
54
59
  "ts-loader": "^9.3.1",
55
60
  "typescript": "^5.7.3",
61
+ "typescript-eslint": "^8.24.1",
56
62
  "webpack": "^5.72.0",
57
63
  "webpack-cli": "^6.0.1",
58
- "wrapper-webpack-plugin": "^2.1.0",
59
- "@babel/runtime": "^7.28.3",
60
- "@eslint/js": "^9.20.0",
61
- "globals": "^15.15.0",
62
- "kleur": "^4.1.5",
63
- "typescript-eslint": "^8.24.1"
64
+ "wrapper-webpack-plugin": "^2.1.0"
64
65
  },
65
66
  "description": "[![npm version](https://badge.fury.io/js/at-builder.svg)](https://www.npmjs.com/package/at-builder) [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)",
66
67
  "directories": {
67
68
  "lib": "lib",
68
69
  "test": "test"
69
70
  },
70
- "devDependencies": {},
71
+ "devDependencies": {
72
+ "@babel/runtime": "^7.29.2"
73
+ },
71
74
  "repository": {
72
75
  "type": "git",
73
76
  "url": "git+https://github.com/upesenga/at-builder.git"
@@ -76,5 +79,9 @@
76
79
  "bugs": {
77
80
  "url": "https://github.com/upesenga/at-builder/issues"
78
81
  },
79
- "homepage": "https://github.com/upesenga/at-builder#readme"
82
+ "homepage": "https://github.com/upesenga/at-builder#readme",
83
+ "engines": {
84
+ "node": ">=16.0.0"
85
+ },
86
+ "packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"
80
87
  }