unity-hub-cli 0.15.0 → 0.17.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/README.md +33 -68
- package/dist/index.js +132 -74
- package/package.json +18 -17
package/README.md
CHANGED
|
@@ -4,104 +4,69 @@
|
|
|
4
4
|
|
|
5
5
|
A CLI tool that displays the same content as Unity Hub in an Ink-based TUI, allows navigation with arrow keys/`j`/`k`, and launches Unity Editor by pressing `o`.
|
|
6
6
|
|
|
7
|
-
<img width="1678" height="1460" alt="
|
|
7
|
+
<img width="1678" height="1460" alt="Screenshot 2025-10-27 23 44 40" src="https://github.com/user-attachments/assets/db3cc995-820e-490b-a43b-393893197ab4" />
|
|
8
8
|
|
|
9
9
|
## Requirements
|
|
10
10
|
|
|
11
11
|
- macOS or Windows 10/11
|
|
12
12
|
- Node.js 20+
|
|
13
|
-
- Unity Hub
|
|
14
|
-
- macOS: `~/Library/Application Support/UnityHub/projects-v1.json`
|
|
15
|
-
- Windows: `%APPDATA%\UnityHub\projects-v1.json`
|
|
16
|
-
- Windows Editor path (default): `C:\\Program Files\\Unity\\Hub\\Editor\\<version>\\Editor\\Unity.exe`
|
|
17
13
|
|
|
18
|
-
##
|
|
19
|
-
|
|
20
|
-
### Development
|
|
14
|
+
## Installation & Run
|
|
21
15
|
|
|
22
16
|
```bash
|
|
23
|
-
|
|
24
|
-
npm run dev
|
|
17
|
+
npx unity-hub-cli
|
|
25
18
|
```
|
|
26
19
|
|
|
27
|
-
|
|
20
|
+
Or install globally to use the `unity-hub-cli` command directly:
|
|
28
21
|
|
|
29
22
|
```bash
|
|
30
|
-
npm
|
|
23
|
+
npm install -g unity-hub-cli
|
|
24
|
+
unity-hub-cli
|
|
31
25
|
```
|
|
32
26
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
After building, `dist/index.js` will be generated. You can also run it directly via npx.
|
|
27
|
+
<details>
|
|
28
|
+
<summary>Notes for Windows</summary>
|
|
36
29
|
|
|
37
|
-
|
|
38
|
-
npx unity-hub-cli
|
|
39
|
-
# or
|
|
40
|
-
node dist/index.js
|
|
41
|
-
```
|
|
30
|
+
Works from PowerShell and CMD. Git Bash is supported when running inside a ConPTY-based terminal (Windows Terminal or VS Code/Cursor integrated terminal).
|
|
42
31
|
|
|
43
|
-
On
|
|
32
|
+
On standalone Git Bash (MinTTY), raw mode is not supported; use PowerShell/CMD/Windows Terminal. If you must use MinTTY Git Bash, run one of the following:
|
|
44
33
|
|
|
45
34
|
- `winpty cmd.exe /c npx unity-hub-cli`
|
|
46
35
|
- `winpty powershell.exe -NoProfile -Command npx unity-hub-cli`
|
|
47
|
-
- If already built: `npm run build && winpty node dist/index.js`
|
|
48
36
|
|
|
49
|
-
|
|
37
|
+
</details>
|
|
50
38
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
### CLI Options
|
|
54
|
-
|
|
55
|
-
- `--no-git-root-name`: Display Unity project titles instead of Git repository root folder names.
|
|
56
|
-
- `--hide-branch`: Hide the Git branch column.
|
|
57
|
-
- `--hide-path`: Hide the project path column.
|
|
58
|
-
|
|
59
|
-
## Release Automation
|
|
60
|
-
|
|
61
|
-
Version and release management is automated using release-please and GitHub Actions.
|
|
39
|
+
## Controls
|
|
62
40
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
41
|
+
| Key | Action |
|
|
42
|
+
|-----|--------|
|
|
43
|
+
| `↑` / `↓` / `j` / `k` | Navigate selection |
|
|
44
|
+
| `o` | Launch selected project in Unity |
|
|
45
|
+
| `O` (Shift+O) | Launch Unity + external editor (e.g., Rider) |
|
|
46
|
+
| `i` | Launch external editor only |
|
|
47
|
+
| `q` | Quit Unity for selected project |
|
|
48
|
+
| `r` | Refresh project list |
|
|
49
|
+
| `c` | Copy project path to clipboard |
|
|
50
|
+
| `s` | Open sort settings panel |
|
|
51
|
+
| `v` | Open visibility settings panel |
|
|
52
|
+
| `Ctrl + C` | Exit |
|
|
67
53
|
|
|
68
|
-
|
|
54
|
+
In settings panels, use `j`/`k` to navigate, `Space` to toggle, and `Esc` to close.
|
|
69
55
|
|
|
70
|
-
|
|
71
|
-
- The workflow uses GitHub's `GITHUB_TOKEN` and operates with `contents`/`pull-requests` permissions
|
|
56
|
+
The display includes Git branch (if present), Unity version, project path, and last modified time. By default, the project list uses the Git repository root folder name when available.
|
|
72
57
|
|
|
73
|
-
|
|
58
|
+
## CLI Options
|
|
74
59
|
|
|
75
|
-
|
|
60
|
+
- `--no-git-root-name`: Display Unity project titles instead of Git repository root folder names.
|
|
76
61
|
|
|
77
62
|
## Security
|
|
78
63
|
|
|
79
|
-
This
|
|
80
|
-
|
|
81
|
-
1. **Automated Publishing with Provenance**: All npm releases are published via GitHub Actions with `--provenance` flag, providing cryptographic proof of the build environment
|
|
82
|
-
2. **Minimal Dependencies**: Only 2 runtime dependencies (`ink` and `react`), both from highly trusted sources
|
|
83
|
-
3. **Locked Dependencies**: `package-lock.json` is committed to ensure reproducible builds
|
|
84
|
-
4. **Regular Security Audits**: Dependencies are regularly checked with `npm audit`
|
|
85
|
-
|
|
86
|
-
### Verifying Package Authenticity
|
|
87
|
-
|
|
88
|
-
You can verify the authenticity of published packages:
|
|
89
|
-
|
|
90
|
-
```bash
|
|
91
|
-
# Check provenance information
|
|
92
|
-
npm view unity-hub-cli --json | jq .dist.attestations
|
|
93
|
-
|
|
94
|
-
# Verify package integrity
|
|
95
|
-
npm audit signatures
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## Controls
|
|
99
|
-
|
|
100
|
-
- Arrow keys / `j` / `k`: Navigate selection
|
|
101
|
-
- `o`: Launch selected project in Unity
|
|
102
|
-
- Ctrl + C (twice): Exit
|
|
64
|
+
This project implements supply chain attack prevention measures:
|
|
103
65
|
|
|
104
|
-
|
|
66
|
+
- **ignore-scripts**: Disables automatic script execution during `npm install`
|
|
67
|
+
- **Dependabot**: Automated weekly security updates
|
|
68
|
+
- **Security audit CI**: Runs `npm audit` and `lockfile-lint` on every PR
|
|
69
|
+
- **Pinned versions**: All dependencies use exact versions (no `^` or `~`)
|
|
105
70
|
|
|
106
71
|
## License
|
|
107
72
|
|
package/dist/index.js
CHANGED
|
@@ -294,18 +294,28 @@ var MacExternalEditorPathReader = class {
|
|
|
294
294
|
return { status: "found", path: configuredPath, name };
|
|
295
295
|
}
|
|
296
296
|
};
|
|
297
|
+
var slnPreferringEditors = ["rider", "visual studio"];
|
|
298
|
+
var prefersSlnFile = (editorPath) => {
|
|
299
|
+
const editorName = basename(editorPath, ".app").toLowerCase();
|
|
300
|
+
return slnPreferringEditors.some((name) => editorName.includes(name));
|
|
301
|
+
};
|
|
297
302
|
var MacExternalEditorLauncher = class {
|
|
298
303
|
/**
|
|
299
304
|
* Launches the external editor with the specified project root.
|
|
300
|
-
*
|
|
301
|
-
*
|
|
305
|
+
* For Rider/Visual Studio: opens .sln file directly if it exists.
|
|
306
|
+
* For VS Code/Cursor and others: opens the project folder.
|
|
302
307
|
* @param editorPath - The path to the editor application.
|
|
303
308
|
* @param projectRoot - The project root directory to open.
|
|
304
309
|
*/
|
|
305
310
|
async launch(editorPath, projectRoot) {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
311
|
+
let targetPath = projectRoot;
|
|
312
|
+
if (prefersSlnFile(editorPath)) {
|
|
313
|
+
const projectName = basename(projectRoot);
|
|
314
|
+
const slnFilePath = join3(projectRoot, `${projectName}.sln`);
|
|
315
|
+
if (existsSync(slnFilePath)) {
|
|
316
|
+
targetPath = slnFilePath;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
309
319
|
await execFileAsync("open", ["-a", editorPath, targetPath]);
|
|
310
320
|
}
|
|
311
321
|
};
|
|
@@ -316,14 +326,77 @@ import { constants as constants4, existsSync as existsSync2 } from "fs";
|
|
|
316
326
|
import { access as access4 } from "fs/promises";
|
|
317
327
|
import { basename as basename2, join as join4 } from "path";
|
|
318
328
|
import { promisify as promisify2 } from "util";
|
|
329
|
+
|
|
330
|
+
// src/presentation/utils/path.ts
|
|
331
|
+
var homeDirectory = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
332
|
+
var normalizedHomeDirectory = homeDirectory.replace(/\\/g, "/");
|
|
333
|
+
var homePrefix = normalizedHomeDirectory ? `${normalizedHomeDirectory}/` : "";
|
|
334
|
+
var isGitBashEnvironment = () => {
|
|
335
|
+
if (process.platform !== "win32") {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
return Boolean(process.env.MSYSTEM);
|
|
339
|
+
};
|
|
340
|
+
var getMsysDisabledEnv = () => {
|
|
341
|
+
if (!isGitBashEnvironment()) {
|
|
342
|
+
return process.env;
|
|
343
|
+
}
|
|
344
|
+
return {
|
|
345
|
+
...process.env,
|
|
346
|
+
MSYS_NO_PATHCONV: "1",
|
|
347
|
+
MSYS2_ARG_CONV_EXCL: "*"
|
|
348
|
+
};
|
|
349
|
+
};
|
|
350
|
+
var shortenHomePath = (targetPath) => {
|
|
351
|
+
if (!normalizedHomeDirectory) {
|
|
352
|
+
return targetPath;
|
|
353
|
+
}
|
|
354
|
+
const normalizedTarget = targetPath.replace(/\\/g, "/");
|
|
355
|
+
if (normalizedTarget === normalizedHomeDirectory) {
|
|
356
|
+
return "~";
|
|
357
|
+
}
|
|
358
|
+
if (homePrefix && normalizedTarget.startsWith(homePrefix)) {
|
|
359
|
+
return `~/${normalizedTarget.slice(homePrefix.length)}`;
|
|
360
|
+
}
|
|
361
|
+
return targetPath;
|
|
362
|
+
};
|
|
363
|
+
var buildCdCommand = (targetPath) => {
|
|
364
|
+
if (process.platform === "win32") {
|
|
365
|
+
if (isGitBashEnvironment()) {
|
|
366
|
+
const msysPath = targetPath.replace(/^([A-Za-z]):[\\/]/, (_, drive) => `/${drive.toLowerCase()}/`).replace(/\\/g, "/");
|
|
367
|
+
const escapedForPosix2 = msysPath.replace(/'/g, "'\\''");
|
|
368
|
+
return `cd '${escapedForPosix2}'`;
|
|
369
|
+
}
|
|
370
|
+
const escapedForWindows = targetPath.replace(/"/g, '""');
|
|
371
|
+
return `cd "${escapedForWindows}"`;
|
|
372
|
+
}
|
|
373
|
+
const escapedForPosix = targetPath.replace(/'/g, "'\\''");
|
|
374
|
+
return `cd '${escapedForPosix}'`;
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
// src/infrastructure/externalEditor.win.ts
|
|
319
378
|
var execFileAsync2 = promisify2(execFile2);
|
|
320
379
|
var REGISTRY_PATH = "HKEY_CURRENT_USER\\Software\\Unity Technologies\\Unity Editor 5.x";
|
|
380
|
+
var decodeRegBinary = (hex) => {
|
|
381
|
+
const bytes = [];
|
|
382
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
383
|
+
const byte = parseInt(hex.slice(i, i + 2), 16);
|
|
384
|
+
if (byte !== 0) {
|
|
385
|
+
bytes.push(byte);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return Buffer.from(bytes).toString("utf8");
|
|
389
|
+
};
|
|
321
390
|
var parseRegistryOutput = (stdout) => {
|
|
322
391
|
const lines = stdout.split("\n");
|
|
323
392
|
for (const line of lines) {
|
|
324
|
-
const
|
|
325
|
-
if (
|
|
326
|
-
return
|
|
393
|
+
const szMatch = line.match(/kScriptsDefaultApp[^\s]*\s+REG_SZ\s+(.+)/i);
|
|
394
|
+
if (szMatch?.[1]) {
|
|
395
|
+
return szMatch[1].trim();
|
|
396
|
+
}
|
|
397
|
+
const binaryMatch = line.match(/kScriptsDefaultApp[^\s]*\s+REG_BINARY\s+([0-9A-Fa-f]+)/i);
|
|
398
|
+
if (binaryMatch?.[1]) {
|
|
399
|
+
return decodeRegBinary(binaryMatch[1]);
|
|
327
400
|
}
|
|
328
401
|
}
|
|
329
402
|
return void 0;
|
|
@@ -336,12 +409,11 @@ var WinExternalEditorPathReader = class {
|
|
|
336
409
|
async read() {
|
|
337
410
|
let configuredPath;
|
|
338
411
|
try {
|
|
339
|
-
const result = await execFileAsync2(
|
|
340
|
-
"
|
|
341
|
-
REGISTRY_PATH,
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
]);
|
|
412
|
+
const result = await execFileAsync2(
|
|
413
|
+
"reg",
|
|
414
|
+
["query", REGISTRY_PATH],
|
|
415
|
+
{ env: getMsysDisabledEnv() }
|
|
416
|
+
);
|
|
345
417
|
configuredPath = parseRegistryOutput(result.stdout);
|
|
346
418
|
} catch {
|
|
347
419
|
return { status: "not_configured" };
|
|
@@ -358,22 +430,33 @@ var WinExternalEditorPathReader = class {
|
|
|
358
430
|
return { status: "found", path: configuredPath, name };
|
|
359
431
|
}
|
|
360
432
|
};
|
|
433
|
+
var slnPreferringEditors2 = ["rider", "devenv", "visualstudio"];
|
|
434
|
+
var prefersSlnFile2 = (editorPath) => {
|
|
435
|
+
const editorName = basename2(editorPath, ".exe").toLowerCase();
|
|
436
|
+
return slnPreferringEditors2.some((name) => editorName.includes(name));
|
|
437
|
+
};
|
|
361
438
|
var WinExternalEditorLauncher = class {
|
|
362
439
|
/**
|
|
363
440
|
* Launches the external editor with the specified project root.
|
|
364
|
-
*
|
|
365
|
-
*
|
|
441
|
+
* For Rider/Visual Studio: opens .sln file directly if it exists.
|
|
442
|
+
* For VS Code/Cursor and others: opens the project folder.
|
|
366
443
|
* @param editorPath - The path to the editor executable.
|
|
367
444
|
* @param projectRoot - The project root directory to open.
|
|
368
445
|
*/
|
|
369
446
|
async launch(editorPath, projectRoot) {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
447
|
+
let targetPath = projectRoot;
|
|
448
|
+
if (prefersSlnFile2(editorPath)) {
|
|
449
|
+
const projectName = basename2(projectRoot);
|
|
450
|
+
const slnFilePath = join4(projectRoot, `${projectName}.sln`);
|
|
451
|
+
if (existsSync2(slnFilePath)) {
|
|
452
|
+
targetPath = slnFilePath;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
373
455
|
await new Promise((resolve4, reject) => {
|
|
374
456
|
const child = spawn(editorPath, [targetPath], {
|
|
375
457
|
detached: true,
|
|
376
|
-
stdio: "ignore"
|
|
458
|
+
stdio: "ignore",
|
|
459
|
+
env: getMsysDisabledEnv()
|
|
377
460
|
});
|
|
378
461
|
const handleError = (error) => {
|
|
379
462
|
child.off("spawn", handleSpawn);
|
|
@@ -478,7 +561,8 @@ var NodeProcessLauncher = class {
|
|
|
478
561
|
await new Promise((resolve4, reject) => {
|
|
479
562
|
const child = spawn2(command, args, {
|
|
480
563
|
detached,
|
|
481
|
-
stdio: "ignore"
|
|
564
|
+
stdio: "ignore",
|
|
565
|
+
env: getMsysDisabledEnv()
|
|
482
566
|
});
|
|
483
567
|
const handleError = (error) => {
|
|
484
568
|
child.off("spawn", handleSpawn);
|
|
@@ -1209,7 +1293,7 @@ var WinUnityProcessReader = class {
|
|
|
1209
1293
|
"-Command",
|
|
1210
1294
|
psCommand
|
|
1211
1295
|
],
|
|
1212
|
-
{ encoding: "utf8" }
|
|
1296
|
+
{ encoding: "utf8", env: getMsysDisabledEnv() }
|
|
1213
1297
|
);
|
|
1214
1298
|
stdout = (result.stdout ?? "").trim();
|
|
1215
1299
|
} catch (error) {
|
|
@@ -1236,14 +1320,18 @@ var WinUnityProcessReader = class {
|
|
|
1236
1320
|
var WinUnityProcessTerminator = class {
|
|
1237
1321
|
async terminate(unityProcess) {
|
|
1238
1322
|
try {
|
|
1239
|
-
await execFileAsync5(
|
|
1240
|
-
"
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1323
|
+
await execFileAsync5(
|
|
1324
|
+
"powershell.exe",
|
|
1325
|
+
[
|
|
1326
|
+
"-NoProfile",
|
|
1327
|
+
"-NonInteractive",
|
|
1328
|
+
"-ExecutionPolicy",
|
|
1329
|
+
"Bypass",
|
|
1330
|
+
"-Command",
|
|
1331
|
+
`Stop-Process -Id ${unityProcess.pid}`
|
|
1332
|
+
],
|
|
1333
|
+
{ env: getMsysDisabledEnv() }
|
|
1334
|
+
);
|
|
1247
1335
|
} catch (error) {
|
|
1248
1336
|
if (!ensureProcessAlive2(unityProcess.pid)) {
|
|
1249
1337
|
return { terminated: true, stage: "sigterm" };
|
|
@@ -1258,14 +1346,18 @@ var WinUnityProcessTerminator = class {
|
|
|
1258
1346
|
}
|
|
1259
1347
|
}
|
|
1260
1348
|
try {
|
|
1261
|
-
await execFileAsync5(
|
|
1262
|
-
"
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1349
|
+
await execFileAsync5(
|
|
1350
|
+
"powershell.exe",
|
|
1351
|
+
[
|
|
1352
|
+
"-NoProfile",
|
|
1353
|
+
"-NonInteractive",
|
|
1354
|
+
"-ExecutionPolicy",
|
|
1355
|
+
"Bypass",
|
|
1356
|
+
"-Command",
|
|
1357
|
+
`Stop-Process -Id ${unityProcess.pid} -Force`
|
|
1358
|
+
],
|
|
1359
|
+
{ env: getMsysDisabledEnv() }
|
|
1360
|
+
);
|
|
1269
1361
|
} catch (error) {
|
|
1270
1362
|
if (!ensureProcessAlive2(unityProcess.pid)) {
|
|
1271
1363
|
return { terminated: true, stage: "sigkill" };
|
|
@@ -1395,39 +1487,6 @@ var ThemeProvider = ({ theme, children }) => {
|
|
|
1395
1487
|
return createElement(ThemeContext.Provider, { value }, children);
|
|
1396
1488
|
};
|
|
1397
1489
|
|
|
1398
|
-
// src/presentation/utils/path.ts
|
|
1399
|
-
var homeDirectory = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
1400
|
-
var normalizedHomeDirectory = homeDirectory.replace(/\\/g, "/");
|
|
1401
|
-
var homePrefix = normalizedHomeDirectory ? `${normalizedHomeDirectory}/` : "";
|
|
1402
|
-
var shortenHomePath = (targetPath) => {
|
|
1403
|
-
if (!normalizedHomeDirectory) {
|
|
1404
|
-
return targetPath;
|
|
1405
|
-
}
|
|
1406
|
-
const normalizedTarget = targetPath.replace(/\\/g, "/");
|
|
1407
|
-
if (normalizedTarget === normalizedHomeDirectory) {
|
|
1408
|
-
return "~";
|
|
1409
|
-
}
|
|
1410
|
-
if (homePrefix && normalizedTarget.startsWith(homePrefix)) {
|
|
1411
|
-
return `~/${normalizedTarget.slice(homePrefix.length)}`;
|
|
1412
|
-
}
|
|
1413
|
-
return targetPath;
|
|
1414
|
-
};
|
|
1415
|
-
var buildCdCommand = (targetPath) => {
|
|
1416
|
-
if (process.platform === "win32") {
|
|
1417
|
-
const isGitBash = Boolean(process.env.MSYSTEM) || /bash/i.test(process.env.SHELL ?? "");
|
|
1418
|
-
if (isGitBash) {
|
|
1419
|
-
const windowsPath = targetPath;
|
|
1420
|
-
const msysPath = windowsPath.replace(/^([A-Za-z]):[\\/]/, (_, drive) => `/${drive.toLowerCase()}/`).replace(/\\/g, "/");
|
|
1421
|
-
const escapedForPosix2 = msysPath.replace(/'/g, "'\\''");
|
|
1422
|
-
return `cd '${escapedForPosix2}'`;
|
|
1423
|
-
}
|
|
1424
|
-
const escapedForWindows = targetPath.replace(/"/g, '""');
|
|
1425
|
-
return `cd "${escapedForWindows}"`;
|
|
1426
|
-
}
|
|
1427
|
-
const escapedForPosix = targetPath.replace(/'/g, "'\\''");
|
|
1428
|
-
return `cd '${escapedForPosix}'`;
|
|
1429
|
-
};
|
|
1430
|
-
|
|
1431
1490
|
// src/presentation/components/ProjectRow.tsx
|
|
1432
1491
|
import { Box as Box2, Text, useStdout } from "ink";
|
|
1433
1492
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
@@ -1928,8 +1987,7 @@ var extractRootFolder2 = (repository) => {
|
|
|
1928
1987
|
return base || void 0;
|
|
1929
1988
|
};
|
|
1930
1989
|
var minimumVisibleProjectCount = 4;
|
|
1931
|
-
var
|
|
1932
|
-
var defaultHintMessage = `j/k Select \xB7 [o]pen [O]+Editor [${editorOnlyKey}]Editor [q]uit [r]efresh [c]opy [s]ort [v]isibility \xB7 ^C Exit`;
|
|
1990
|
+
var defaultHintMessage = `j/k Select \xB7 [o]pen [O]+Editor [i]de [q]uit [r]efresh [c]opy [s]ort [v]isibility \xB7 ^C Exit`;
|
|
1933
1991
|
var getCopyTargetPath = (view) => {
|
|
1934
1992
|
const root = view.repository?.root;
|
|
1935
1993
|
return root && root.length > 0 ? root : view.project.path;
|
|
@@ -2481,7 +2539,7 @@ var App = ({
|
|
|
2481
2539
|
void terminateSelected();
|
|
2482
2540
|
return;
|
|
2483
2541
|
}
|
|
2484
|
-
if (input === "
|
|
2542
|
+
if (input === "i") {
|
|
2485
2543
|
void launchEditorOnly();
|
|
2486
2544
|
return;
|
|
2487
2545
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "unity-hub-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "A CLI tool that reads Unity Hub's projects and launches Unity Editor with an interactive TUI",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "
|
|
7
|
+
"test": "vitest run",
|
|
8
8
|
"dev": "tsx src/index.ts",
|
|
9
9
|
"build": "tsup",
|
|
10
10
|
"start": "node dist/index.js",
|
|
@@ -36,25 +36,26 @@
|
|
|
36
36
|
"dist"
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"clipboardy": "
|
|
40
|
-
"ink": "
|
|
41
|
-
"react": "
|
|
39
|
+
"clipboardy": "4.0.0",
|
|
40
|
+
"ink": "4.4.1",
|
|
41
|
+
"react": "18.3.1"
|
|
42
42
|
},
|
|
43
43
|
"engines": {
|
|
44
44
|
"node": ">=18"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@types/node": "
|
|
48
|
-
"@types/react": "
|
|
49
|
-
"@typescript-eslint/eslint-plugin": "
|
|
50
|
-
"@typescript-eslint/parser": "
|
|
51
|
-
"eslint": "
|
|
52
|
-
"eslint-config-prettier": "
|
|
53
|
-
"eslint-import-resolver-typescript": "
|
|
54
|
-
"eslint-plugin-import": "
|
|
55
|
-
"prettier": "
|
|
56
|
-
"tsup": "
|
|
57
|
-
"tsx": "
|
|
58
|
-
"typescript": "
|
|
47
|
+
"@types/node": "20.19.20",
|
|
48
|
+
"@types/react": "18.3.26",
|
|
49
|
+
"@typescript-eslint/eslint-plugin": "7.18.0",
|
|
50
|
+
"@typescript-eslint/parser": "7.18.0",
|
|
51
|
+
"eslint": "8.57.0",
|
|
52
|
+
"eslint-config-prettier": "9.1.2",
|
|
53
|
+
"eslint-import-resolver-typescript": "3.10.1",
|
|
54
|
+
"eslint-plugin-import": "2.32.0",
|
|
55
|
+
"prettier": "3.6.2",
|
|
56
|
+
"tsup": "8.5.0",
|
|
57
|
+
"tsx": "4.20.6",
|
|
58
|
+
"typescript": "5.9.3",
|
|
59
|
+
"vitest": "4.0.14"
|
|
59
60
|
}
|
|
60
61
|
}
|