squad-station 0.8.16 → 0.8.18
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/bin/run.js +138 -24
- package/package.json +1 -1
package/bin/run.js
CHANGED
|
@@ -11,6 +11,8 @@ const subcommand = process.argv[2];
|
|
|
11
11
|
|
|
12
12
|
if (subcommand === 'install') {
|
|
13
13
|
install();
|
|
14
|
+
} else if (subcommand === 'uninstall') {
|
|
15
|
+
uninstall();
|
|
14
16
|
} else {
|
|
15
17
|
proxyToBinary();
|
|
16
18
|
}
|
|
@@ -43,7 +45,7 @@ function install() {
|
|
|
43
45
|
|
|
44
46
|
function installBinary() {
|
|
45
47
|
// Binary version — may differ from npm package version
|
|
46
|
-
var VERSION = '0.8.
|
|
48
|
+
var VERSION = '0.8.18';
|
|
47
49
|
var REPO = 'thientranhung/squad-station';
|
|
48
50
|
|
|
49
51
|
var isWindows = process.platform === 'win32';
|
|
@@ -73,6 +75,7 @@ function installBinary() {
|
|
|
73
75
|
var result = spawnSync(destPath, ['--version'], { encoding: 'utf8' });
|
|
74
76
|
if (result.stdout && result.stdout.includes(VERSION)) {
|
|
75
77
|
console.log(' \x1b[32m✓\x1b[0m squad-station v' + VERSION + ' already installed at ' + destPath);
|
|
78
|
+
checkDuplicateBinary(destPath);
|
|
76
79
|
return;
|
|
77
80
|
}
|
|
78
81
|
} catch (_) {
|
|
@@ -116,6 +119,9 @@ function installBinary() {
|
|
|
116
119
|
|
|
117
120
|
// Verify the binary is actually callable via PATH
|
|
118
121
|
verifyInPath(destPath, installDir);
|
|
122
|
+
|
|
123
|
+
// Check for duplicate binaries at other locations
|
|
124
|
+
checkDuplicateBinary(destPath);
|
|
119
125
|
}
|
|
120
126
|
|
|
121
127
|
// Find the best install directory that is already in the user's PATH.
|
|
@@ -126,29 +132,34 @@ function findBestInstallDir() {
|
|
|
126
132
|
var pathSep = isWindows ? ';' : ':';
|
|
127
133
|
var pathDirs = (process.env.PATH || '').split(pathSep).filter(Boolean);
|
|
128
134
|
|
|
129
|
-
//
|
|
135
|
+
// Primary: ~/.squad/bin — our own directory, does not need to be on PATH
|
|
136
|
+
var squadBin = path.join(home, '.squad', 'bin');
|
|
137
|
+
try {
|
|
138
|
+
fs.mkdirSync(squadBin, { recursive: true });
|
|
139
|
+
fs.accessSync(squadBin, fs.constants.W_OK);
|
|
140
|
+
return squadBin;
|
|
141
|
+
} catch (_) {
|
|
142
|
+
// Fall through to other candidates
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Secondary candidates — must be on PATH and writable
|
|
130
146
|
var candidates = isWindows
|
|
131
147
|
? [
|
|
132
148
|
path.join(home, '.local', 'bin'),
|
|
133
149
|
path.join(home, 'AppData', 'Local', 'Microsoft', 'WindowsApps'),
|
|
134
150
|
]
|
|
135
151
|
: [
|
|
136
|
-
'/usr/local/bin',
|
|
137
152
|
path.join(home, '.local', 'bin'),
|
|
138
|
-
|
|
139
|
-
'/opt/homebrew/bin',
|
|
153
|
+
'/usr/local/bin',
|
|
140
154
|
];
|
|
141
155
|
|
|
142
|
-
// Pick the first candidate that is already in PATH and is writable
|
|
143
156
|
for (var i = 0; i < candidates.length; i++) {
|
|
144
157
|
var dir = candidates[i];
|
|
145
|
-
// Check if this directory is in PATH
|
|
146
158
|
var inPath = pathDirs.some(function(p) {
|
|
147
159
|
return path.resolve(p) === path.resolve(dir);
|
|
148
160
|
});
|
|
149
161
|
if (!inPath) continue;
|
|
150
162
|
|
|
151
|
-
// Check if writable (create if needed)
|
|
152
163
|
try {
|
|
153
164
|
fs.mkdirSync(dir, { recursive: true });
|
|
154
165
|
fs.accessSync(dir, fs.constants.W_OK);
|
|
@@ -158,10 +169,9 @@ function findBestInstallDir() {
|
|
|
158
169
|
}
|
|
159
170
|
}
|
|
160
171
|
|
|
161
|
-
// Fallback: ~/.
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
return fallback;
|
|
172
|
+
// Fallback: ~/.squad/bin (already created above if writable)
|
|
173
|
+
fs.mkdirSync(squadBin, { recursive: true });
|
|
174
|
+
return squadBin;
|
|
165
175
|
}
|
|
166
176
|
|
|
167
177
|
// Verify the installed binary is callable. If not, print PATH instructions.
|
|
@@ -175,33 +185,137 @@ function verifyInPath(destPath, installDir) {
|
|
|
175
185
|
return;
|
|
176
186
|
}
|
|
177
187
|
|
|
178
|
-
// Not in PATH — print
|
|
188
|
+
// Not in PATH — print instructions
|
|
179
189
|
console.log('');
|
|
180
190
|
console.log(' \x1b[33m⚠ squad-station is not in your PATH\x1b[0m');
|
|
181
191
|
console.log(' The binary was installed to: \x1b[36m' + installDir + '\x1b[0m');
|
|
182
192
|
console.log('');
|
|
183
|
-
console.log(' Add it to your PATH:');
|
|
184
|
-
console.log('');
|
|
185
193
|
|
|
186
|
-
if (
|
|
187
|
-
console.log('
|
|
188
|
-
console.log(' \x1b[36mexport PATH="' + installDir + ':$PATH"\x1b[0m');
|
|
194
|
+
if (isWindows) {
|
|
195
|
+
console.log(' Add to your PATH:');
|
|
189
196
|
console.log('');
|
|
190
|
-
console.log(' Then reload: \x1b[36msource ~/.zshrc\x1b[0m');
|
|
191
|
-
} else if (isWindows) {
|
|
192
197
|
console.log(' \x1b[2m# Windows (PowerShell) — run as Administrator:\x1b[0m');
|
|
193
198
|
console.log(' \x1b[36m[Environment]::SetEnvironmentVariable("Path",\x1b[0m');
|
|
194
199
|
console.log(' \x1b[36m [Environment]::GetEnvironmentVariable("Path", "User") + ";' + installDir + '", "User")\x1b[0m');
|
|
195
200
|
console.log('');
|
|
196
201
|
console.log(' Then restart your terminal.');
|
|
197
202
|
} else {
|
|
198
|
-
|
|
199
|
-
console.log('
|
|
200
|
-
console.log(' \x1b[
|
|
203
|
+
var shellProfile = process.platform === 'darwin' ? '~/.zshrc' : '~/.bashrc';
|
|
204
|
+
console.log(' Add to your shell profile: \x1b[36mexport PATH="$HOME/.squad/bin:$PATH"\x1b[0m');
|
|
205
|
+
console.log(' Then restart your terminal or run: \x1b[36msource ' + shellProfile + '\x1b[0m');
|
|
206
|
+
}
|
|
207
|
+
console.log('');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Check if another squad-station binary exists at a different path than where we installed.
|
|
211
|
+
function checkDuplicateBinary(installedPath) {
|
|
212
|
+
var isWindows = process.platform === 'win32';
|
|
213
|
+
var checkCmd = isWindows ? 'where' : 'which';
|
|
214
|
+
var result = spawnSync(checkCmd, ['squad-station'], { encoding: 'utf8' });
|
|
215
|
+
|
|
216
|
+
if (result.status !== 0 || !result.stdout || !result.stdout.trim()) {
|
|
217
|
+
return; // not in PATH at all — verifyInPath already warned
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
var resolvedWhich = fs.realpathSync(result.stdout.trim());
|
|
221
|
+
var resolvedInstalled = fs.realpathSync(installedPath);
|
|
222
|
+
|
|
223
|
+
if (resolvedWhich !== resolvedInstalled) {
|
|
224
|
+
console.log('');
|
|
225
|
+
console.log(' \x1b[33m⚠ Another squad-station found at: ' + result.stdout.trim() + '\x1b[0m');
|
|
226
|
+
console.log(' This version will be used instead of the one just installed.');
|
|
227
|
+
console.log(' Remove it to avoid conflicts: \x1b[36mrm ' + result.stdout.trim() + '\x1b[0m');
|
|
201
228
|
console.log('');
|
|
202
|
-
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ── Uninstall ───────────────────────────────────────────────────────
|
|
233
|
+
// Find and remove all squad-station binaries from known locations.
|
|
234
|
+
|
|
235
|
+
function uninstall() {
|
|
236
|
+
var home = process.env.HOME || process.env.USERPROFILE || '';
|
|
237
|
+
var isWindows = process.platform === 'win32';
|
|
238
|
+
var binaryName = isWindows ? 'squad-station.exe' : 'squad-station';
|
|
239
|
+
|
|
240
|
+
// Search directories: current install locations + legacy locations
|
|
241
|
+
var searchDirs = isWindows
|
|
242
|
+
? [
|
|
243
|
+
path.join(home, '.squad', 'bin'),
|
|
244
|
+
path.join(home, '.local', 'bin'),
|
|
245
|
+
path.join(home, 'AppData', 'Local', 'Microsoft', 'WindowsApps'),
|
|
246
|
+
]
|
|
247
|
+
: [
|
|
248
|
+
path.join(home, '.squad', 'bin'),
|
|
249
|
+
path.join(home, '.local', 'bin'),
|
|
250
|
+
'/usr/local/bin',
|
|
251
|
+
path.join(home, '.cargo', 'bin'),
|
|
252
|
+
'/opt/homebrew/bin',
|
|
253
|
+
];
|
|
254
|
+
|
|
255
|
+
console.log('\n\x1b[32m══════════════════════════════════\x1b[0m');
|
|
256
|
+
console.log(' \x1b[1mSquad Station Uninstall\x1b[0m');
|
|
257
|
+
console.log('\x1b[32m══════════════════════════════════\x1b[0m\n');
|
|
258
|
+
|
|
259
|
+
// Find all existing binaries
|
|
260
|
+
var found = [];
|
|
261
|
+
for (var i = 0; i < searchDirs.length; i++) {
|
|
262
|
+
var binPath = path.join(searchDirs[i], binaryName);
|
|
263
|
+
if (fs.existsSync(binPath)) {
|
|
264
|
+
var version = '(unknown version)';
|
|
265
|
+
try {
|
|
266
|
+
var result = spawnSync(binPath, ['--version'], { encoding: 'utf8', timeout: 5000 });
|
|
267
|
+
if (result.stdout && result.stdout.trim()) {
|
|
268
|
+
version = result.stdout.trim();
|
|
269
|
+
}
|
|
270
|
+
} catch (_) {}
|
|
271
|
+
found.push({ path: binPath, version: version });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (found.length === 0) {
|
|
276
|
+
console.log(' No squad-station binaries found.\n');
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
console.log(' Found ' + found.length + ' binary(ies):\n');
|
|
281
|
+
for (var j = 0; j < found.length; j++) {
|
|
282
|
+
console.log(' \x1b[36m' + found[j].path + '\x1b[0m ' + found[j].version);
|
|
203
283
|
}
|
|
204
284
|
console.log('');
|
|
285
|
+
|
|
286
|
+
// Ask for confirmation (read single line from stdin)
|
|
287
|
+
process.stdout.write(' Remove these binaries? [y/N] ');
|
|
288
|
+
var buf = Buffer.alloc(128);
|
|
289
|
+
var bytesRead = 0;
|
|
290
|
+
try {
|
|
291
|
+
bytesRead = fs.readSync(0, buf, 0, buf.length);
|
|
292
|
+
} catch (_) {
|
|
293
|
+
console.log('\n Aborted.\n');
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
var answer = buf.toString('utf8', 0, bytesRead).trim().toLowerCase();
|
|
297
|
+
|
|
298
|
+
if (answer !== 'y' && answer !== 'yes') {
|
|
299
|
+
console.log(' Aborted.\n');
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Delete each binary
|
|
304
|
+
var removed = 0;
|
|
305
|
+
for (var k = 0; k < found.length; k++) {
|
|
306
|
+
try {
|
|
307
|
+
fs.unlinkSync(found[k].path);
|
|
308
|
+
console.log(' \x1b[32m✓\x1b[0m Removed ' + found[k].path);
|
|
309
|
+
removed++;
|
|
310
|
+
} catch (e) {
|
|
311
|
+
console.log(' \x1b[31m✗\x1b[0m Failed to remove ' + found[k].path + ': ' + e.message);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
console.log('');
|
|
316
|
+
if (removed > 0) {
|
|
317
|
+
console.log(' Uninstalled. You can also remove ~/.squad/bin from your PATH if no longer needed.\n');
|
|
318
|
+
}
|
|
205
319
|
}
|
|
206
320
|
|
|
207
321
|
function scaffoldProject(force) {
|