unity-hub-cli 0.16.0 → 0.18.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.
Files changed (3) hide show
  1. package/README.md +62 -58
  2. package/dist/index.js +234 -32
  3. package/package.json +33 -20
package/README.md CHANGED
@@ -4,104 +4,108 @@
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="スクリーンショット 2025-10-27 23 44 40" src="https://github.com/user-attachments/assets/db3cc995-820e-490b-a43b-393893197ab4" />
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
- ## Usage
19
-
20
- ### Development
14
+ ## Installation & Run
21
15
 
22
16
  ```bash
23
- npm install
24
- npm run dev
17
+ npx unity-hub-cli
25
18
  ```
26
19
 
27
- ### Build
20
+ Or install globally to use the `unity-hub-cli` command directly:
28
21
 
29
22
  ```bash
30
- npm run build
23
+ npm install -g unity-hub-cli
24
+ unity-hub-cli
31
25
  ```
32
26
 
33
- ### Run
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
- ```bash
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 Windows, it works from PowerShell and CMD. Git Bash is supported when running inside a ConPTY-based terminal (Windows Terminal or VS Code/Cursor integrated terminal). 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:
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
- See `https://github.com/vadimdemedes/ink/#israwmodesupported`.
37
+ </details>
50
38
 
51
- By default, the project list uses the Git repository root folder name when available.
39
+ ## Controls
52
40
 
53
- ### CLI Options
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 |
54
53
 
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.
54
+ In settings panels, use `j`/`k` to navigate, `Space` to toggle, and `Esc` to close.
58
55
 
59
- ## Release Automation
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.
60
57
 
61
- Version and release management is automated using release-please and GitHub Actions.
58
+ ## CLI Options
62
59
 
63
- - `.github/workflows/release-please.yml` runs on push to `main` or manual trigger
64
- - The action references `release-please-config.json` and `.release-please-manifest.json` to create release PRs and tags
65
- - When a PR is merged, GitHub Releases and changelog are automatically updated
66
- - **npm publish is automated with provenance** for supply chain security
60
+ - `--no-git-root-name`: Display Unity project titles instead of Git repository root folder names.
61
+ - `--shell-init`: Install shell function for automatic `cd` integration (with confirmation prompt).
62
+ - `--shell-init --dry-run`: Preview the shell function without installing.
67
63
 
68
- ### Initial Setup Notes
64
+ ## Shell Integration
69
65
 
70
- - If existing releases are present, set the latest release commit in `bootstrap-sha` of `release-please-config.json`
71
- - The workflow uses GitHub's `GITHUB_TOKEN` and operates with `contents`/`pull-requests` permissions
66
+ You can add a shell function to automatically `cd` to the project directory after opening Unity.
72
67
 
73
- ### Manual Execution
68
+ ### Setup
74
69
 
75
- You can manually trigger the `release-please` workflow from the Actions tab by selecting `Run workflow`
70
+ 1. Install globally:
71
+ ```bash
72
+ npm install -g unity-hub-cli
73
+ ```
76
74
 
77
- ## Security
75
+ 2. Run the shell init command (auto-detects your shell):
76
+ ```bash
77
+ unity-hub-cli --shell-init
78
+ ```
78
79
 
79
- This package implements multiple security measures to protect against supply chain attacks:
80
+ This automatically adds the `unity-hub` function to your shell config file (`.zshrc`, `.bashrc`, `config.fish`, or PowerShell profile).
80
81
 
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`
82
+ 3. Reload your shell:
83
+ ```bash
84
+ source ~/.zshrc # or restart your terminal
85
+ ```
85
86
 
86
- ### Verifying Package Authenticity
87
+ ### Usage
87
88
 
88
- You can verify the authenticity of published packages:
89
+ Now you can use `unity-hub` to:
90
+ 1. Browse and select Unity projects
91
+ 2. Press `o` to launch Unity
92
+ 3. Your terminal automatically `cd`s to the project directory
89
93
 
90
- ```bash
91
- # Check provenance information
92
- npm view unity-hub-cli --json | jq .dist.attestations
94
+ ### Notes
93
95
 
94
- # Verify package integrity
95
- npm audit signatures
96
- ```
96
+ - Running `--shell-init` multiple times is safe - it updates the existing function using marker comments
97
+ - The function uses absolute paths detected from your environment
98
+ - **Windows**: Shell integration supports PowerShell only. CMD is not supported because it lacks shell functions required for automatic `cd` after launching Unity
97
99
 
98
- ## Controls
100
+ ## Security
99
101
 
100
- - Arrow keys / `j` / `k`: Navigate selection
101
- - `o`: Launch selected project in Unity
102
- - Ctrl + C (twice): Exit
102
+ This project implements supply chain attack prevention measures:
103
103
 
104
- The display includes Git branch (if present), Unity version, project path, and last modified time (`lastModified`).
104
+ - **ignore-scripts**: Disables automatic script execution during `npm install`
105
+ - **@lavamoat/allow-scripts**: Explicitly controls which packages can run install scripts
106
+ - **Dependabot**: Automated weekly security updates
107
+ - **Security audit CI**: Runs `npm audit`, `lockfile-lint`, and OSV-Scanner on every PR
108
+ - **Pinned versions**: All dependencies use exact versions (no `^` or `~`)
105
109
 
106
110
  ## License
107
111
 
package/dist/index.js CHANGED
@@ -1,7 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.tsx
4
+ import { execSync } from "child_process";
5
+ import { existsSync as existsSync3, mkdirSync, readFileSync, writeFileSync } from "fs";
6
+ import { homedir } from "os";
7
+ import { dirname as dirname2, join as join9 } from "path";
4
8
  import process3 from "process";
9
+ import { createInterface as createInterface2 } from "readline";
10
+ import chalk from "chalk";
5
11
  import { render } from "ink";
6
12
 
7
13
  // src/application/usecases.ts
@@ -1332,7 +1338,7 @@ var WinUnityProcessTerminator = class {
1332
1338
  ],
1333
1339
  { env: getMsysDisabledEnv() }
1334
1340
  );
1335
- } catch (error) {
1341
+ } catch {
1336
1342
  if (!ensureProcessAlive2(unityProcess.pid)) {
1337
1343
  return { terminated: true, stage: "sigterm" };
1338
1344
  }
@@ -1358,7 +1364,7 @@ var WinUnityProcessTerminator = class {
1358
1364
  ],
1359
1365
  { env: getMsysDisabledEnv() }
1360
1366
  );
1361
- } catch (error) {
1367
+ } catch {
1362
1368
  if (!ensureProcessAlive2(unityProcess.pid)) {
1363
1369
  return { terminated: true, stage: "sigkill" };
1364
1370
  }
@@ -1999,7 +2005,9 @@ var App = ({
1999
2005
  onLaunchEditorOnly,
2000
2006
  onTerminate,
2001
2007
  onRefresh,
2002
- useGitRootName = true
2008
+ useGitRootName = true,
2009
+ outputPathOnExit = false,
2010
+ onSetExitPath
2003
2011
  }) => {
2004
2012
  const { exit } = useApp();
2005
2013
  const { stdout } = useStdout2();
@@ -2196,20 +2204,14 @@ var App = ({
2196
2204
  return;
2197
2205
  }
2198
2206
  const { project } = projectView;
2199
- try {
2200
- const cdTarget = getCopyTargetPath(projectView);
2201
- const command = buildCdCommand(cdTarget);
2202
- clipboard.writeSync(command);
2203
- } catch (error) {
2204
- const message = error instanceof Error ? error.message : String(error);
2205
- setHint(`Failed to copy: ${message}`);
2206
- setTimeout(() => {
2207
- setHint(defaultHintMessage);
2208
- }, 3e3);
2209
- return;
2210
- }
2207
+ const cdTarget = getCopyTargetPath(projectView);
2211
2208
  try {
2212
2209
  await onLaunch(project);
2210
+ if (outputPathOnExit) {
2211
+ onSetExitPath?.(cdTarget);
2212
+ exit();
2213
+ return;
2214
+ }
2213
2215
  setLaunchedProjects((previous) => {
2214
2216
  const next = new Set(previous);
2215
2217
  next.add(project.id);
@@ -2229,6 +2231,11 @@ var App = ({
2229
2231
  }, 3e3);
2230
2232
  } catch (error) {
2231
2233
  if (error instanceof LaunchCancelledError) {
2234
+ if (outputPathOnExit) {
2235
+ onSetExitPath?.(cdTarget);
2236
+ exit();
2237
+ return;
2238
+ }
2232
2239
  setHint("Launch cancelled");
2233
2240
  setTimeout(() => {
2234
2241
  setHint(defaultHintMessage);
@@ -2241,7 +2248,7 @@ var App = ({
2241
2248
  setHint(defaultHintMessage);
2242
2249
  }, 3e3);
2243
2250
  }
2244
- }, [index, onLaunch, sortedProjects]);
2251
+ }, [exit, index, onLaunch, onSetExitPath, outputPathOnExit, sortedProjects]);
2245
2252
  const launchSelectedWithEditor = useCallback(async () => {
2246
2253
  if (!onLaunchWithEditor) {
2247
2254
  setHint("Launch with editor not available");
@@ -2259,20 +2266,14 @@ var App = ({
2259
2266
  return;
2260
2267
  }
2261
2268
  const { project } = projectView;
2262
- try {
2263
- const cdTarget = getCopyTargetPath(projectView);
2264
- const command = buildCdCommand(cdTarget);
2265
- clipboard.writeSync(command);
2266
- } catch (error) {
2267
- const message = error instanceof Error ? error.message : String(error);
2268
- setHint(`Failed to copy: ${message}`);
2269
- setTimeout(() => {
2270
- setHint(defaultHintMessage);
2271
- }, 3e3);
2272
- return;
2273
- }
2269
+ const cdTarget = getCopyTargetPath(projectView);
2274
2270
  try {
2275
2271
  const result = await onLaunchWithEditor(project);
2272
+ if (outputPathOnExit) {
2273
+ onSetExitPath?.(cdTarget);
2274
+ exit();
2275
+ return;
2276
+ }
2276
2277
  setLaunchedProjects((previous) => {
2277
2278
  const next = new Set(previous);
2278
2279
  next.add(project.id);
@@ -2292,6 +2293,11 @@ var App = ({
2292
2293
  }, 3e3);
2293
2294
  } catch (error) {
2294
2295
  if (error instanceof LaunchCancelledError) {
2296
+ if (outputPathOnExit) {
2297
+ onSetExitPath?.(cdTarget);
2298
+ exit();
2299
+ return;
2300
+ }
2295
2301
  setHint("Launch cancelled");
2296
2302
  setTimeout(() => {
2297
2303
  setHint(defaultHintMessage);
@@ -2304,7 +2310,7 @@ var App = ({
2304
2310
  setHint(defaultHintMessage);
2305
2311
  }, 3e3);
2306
2312
  }
2307
- }, [index, onLaunchWithEditor, sortedProjects]);
2313
+ }, [exit, index, onLaunchWithEditor, onSetExitPath, outputPathOnExit, sortedProjects]);
2308
2314
  const launchEditorOnly = useCallback(async () => {
2309
2315
  if (!onLaunchEditorOnly) {
2310
2316
  setHint("Launch editor only not available");
@@ -2634,7 +2640,186 @@ var App = ({
2634
2640
 
2635
2641
  // src/index.tsx
2636
2642
  import { jsx as jsx7 } from "react/jsx-runtime";
2643
+ var SHELL_INIT_MARKER_START = "# >>> unity-hub-cli >>>";
2644
+ var SHELL_INIT_MARKER_END = "# <<< unity-hub-cli <<<";
2645
+ var getShellConfigPath = () => {
2646
+ const shell = process3.env["SHELL"] ?? "";
2647
+ const home = homedir();
2648
+ if (shell.includes("zsh")) {
2649
+ return join9(home, ".zshrc");
2650
+ }
2651
+ if (shell.includes("bash")) {
2652
+ const bashrcPath = join9(home, ".bashrc");
2653
+ const profilePath = join9(home, ".bash_profile");
2654
+ return existsSync3(bashrcPath) ? bashrcPath : profilePath;
2655
+ }
2656
+ if (shell.includes("fish")) {
2657
+ return join9(home, ".config", "fish", "config.fish");
2658
+ }
2659
+ if (process3.platform === "win32") {
2660
+ return join9(home, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
2661
+ }
2662
+ return void 0;
2663
+ };
2664
+ var getShellInitScriptWithMarkers = () => {
2665
+ const script = getShellInitScript();
2666
+ return `${SHELL_INIT_MARKER_START}
2667
+ ${script}
2668
+ ${SHELL_INIT_MARKER_END}`;
2669
+ };
2670
+ var askConfirmation = (question) => {
2671
+ const rl = createInterface2({
2672
+ input: process3.stdin,
2673
+ output: process3.stdout
2674
+ });
2675
+ return new Promise((resolve4) => {
2676
+ rl.question(question, (answer) => {
2677
+ rl.close();
2678
+ resolve4(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
2679
+ });
2680
+ });
2681
+ };
2682
+ var previewShellInit = () => {
2683
+ const configPath = getShellConfigPath();
2684
+ console.log("=== Shell Integration Preview ===\n");
2685
+ console.log(`Target file: ${configPath ?? "Unknown (unsupported shell)"}
2686
+ `);
2687
+ console.log("Content to be added:\n");
2688
+ console.log(getShellInitScriptWithMarkers());
2689
+ };
2690
+ var installShellInit = () => {
2691
+ const configPath = getShellConfigPath();
2692
+ if (!configPath) {
2693
+ return { success: false, message: "Unsupported shell. Please copy the function from the README into your shell config manually." };
2694
+ }
2695
+ const scriptWithMarkers = getShellInitScriptWithMarkers();
2696
+ const markerPattern = new RegExp(
2697
+ `${SHELL_INIT_MARKER_START}[\\s\\S]*?${SHELL_INIT_MARKER_END}`,
2698
+ "g"
2699
+ );
2700
+ let content = "";
2701
+ if (existsSync3(configPath)) {
2702
+ content = readFileSync(configPath, "utf-8");
2703
+ }
2704
+ const existingMatch = content.match(markerPattern);
2705
+ if (existingMatch && existingMatch[0] === scriptWithMarkers) {
2706
+ return { success: true, message: `Shell integration is already up to date in ${configPath}` };
2707
+ }
2708
+ let newContent;
2709
+ let action;
2710
+ if (existingMatch) {
2711
+ newContent = content.replace(markerPattern, scriptWithMarkers);
2712
+ action = "updated";
2713
+ } else {
2714
+ newContent = content.trimEnd() + "\n\n" + scriptWithMarkers + "\n";
2715
+ action = "installed";
2716
+ }
2717
+ mkdirSync(dirname2(configPath), { recursive: true });
2718
+ writeFileSync(configPath, newContent, "utf-8");
2719
+ return { success: true, message: `Shell integration ${action} in ${configPath}` };
2720
+ };
2721
+ var getNodePath = () => {
2722
+ const isWindows = process3.platform === "win32";
2723
+ const command = isWindows ? "where node" : "which node";
2724
+ try {
2725
+ const result = execSync(command, { encoding: "utf-8" }).trim().split("\n")[0];
2726
+ if (result && existsSync3(result)) {
2727
+ return result;
2728
+ }
2729
+ } catch {
2730
+ }
2731
+ return "node";
2732
+ };
2733
+ var getUnityHubCliPath = () => {
2734
+ const isWindows = process3.platform === "win32";
2735
+ try {
2736
+ const prefix = execSync("npm config get prefix", { encoding: "utf-8" }).trim();
2737
+ const binDir = isWindows ? prefix : `${prefix}/bin`;
2738
+ const cliPath = isWindows ? `${binDir}/unity-hub-cli.cmd` : `${binDir}/unity-hub-cli`;
2739
+ if (existsSync3(cliPath)) {
2740
+ return cliPath;
2741
+ }
2742
+ } catch {
2743
+ }
2744
+ return "unity-hub-cli";
2745
+ };
2746
+ var getShellInitScript = () => {
2747
+ const shell = process3.env["SHELL"] ?? "";
2748
+ const isWindows = process3.platform === "win32";
2749
+ const nodePath = getNodePath();
2750
+ const cliPath = getUnityHubCliPath();
2751
+ if (shell.includes("fish")) {
2752
+ return `function unity-hub
2753
+ set -l tmpfile (mktemp)
2754
+ ${nodePath} ${cliPath} --output-path-on-exit > $tmpfile
2755
+ set -l dir (cat $tmpfile)
2756
+ rm -f $tmpfile
2757
+ if test -n "$dir"
2758
+ cd $dir
2759
+ end
2760
+ end`;
2761
+ }
2762
+ if (shell.includes("bash") || shell.includes("zsh")) {
2763
+ return `unity-hub() {
2764
+ local tmpfile=$(mktemp)
2765
+ ${nodePath} ${cliPath} --output-path-on-exit >| "$tmpfile"
2766
+ local dir=$(cat "$tmpfile")
2767
+ rm -f "$tmpfile"
2768
+ if [ -n "$dir" ]; then
2769
+ cd "$dir"
2770
+ fi
2771
+ }`;
2772
+ }
2773
+ if (isWindows) {
2774
+ return `function unity-hub {
2775
+ $tmpfile = [System.IO.Path]::GetTempFileName()
2776
+ & "${cliPath}" --output-path-on-exit > $tmpfile
2777
+ $dir = Get-Content $tmpfile
2778
+ Remove-Item $tmpfile
2779
+ if ($dir) {
2780
+ Set-Location $dir
2781
+ }
2782
+ }`;
2783
+ }
2784
+ return `unity-hub() {
2785
+ local tmpfile=$(mktemp)
2786
+ ${nodePath} ${cliPath} --output-path-on-exit >| "$tmpfile"
2787
+ local dir=$(cat "$tmpfile")
2788
+ rm -f "$tmpfile"
2789
+ if [ -n "$dir" ]; then
2790
+ cd "$dir"
2791
+ fi
2792
+ }`;
2793
+ };
2637
2794
  var bootstrap = async () => {
2795
+ const args = process3.argv.slice(2);
2796
+ if (args.includes("--shell-init")) {
2797
+ const isDryRun = args.includes("--dry-run");
2798
+ if (isDryRun) {
2799
+ previewShellInit();
2800
+ return;
2801
+ }
2802
+ const configPath = getShellConfigPath();
2803
+ if (!configPath) {
2804
+ console.log("Unsupported shell. Please copy the function from the README into your shell config manually.");
2805
+ process3.exitCode = 1;
2806
+ return;
2807
+ }
2808
+ console.log(`This will install the unity-hub function to: ${configPath}
2809
+ `);
2810
+ previewShellInit();
2811
+ console.log("");
2812
+ const confirmed = await askConfirmation("Proceed with installation? (y/n): ");
2813
+ if (!confirmed) {
2814
+ console.log("Installation cancelled.");
2815
+ return;
2816
+ }
2817
+ const result = installShellInit();
2818
+ console.log(result.message);
2819
+ process3.exitCode = result.success ? 0 : 1;
2820
+ return;
2821
+ }
2822
+ const outputPathOnExit = args.includes("--output-path-on-exit");
2638
2823
  const isWindows = process3.platform === "win32";
2639
2824
  const unityHubReader = isWindows ? new WinUnityHubProjectsReader() : new MacUnityHubProjectsReader();
2640
2825
  const gitRepositoryInfoReader = new GitRepositoryInfoReader();
@@ -2694,8 +2879,13 @@ var bootstrap = async () => {
2694
2879
  process3.exitCode = 1;
2695
2880
  return;
2696
2881
  }
2882
+ if (outputPathOnExit && process3.stderr.isTTY) {
2883
+ chalk.level = 3;
2884
+ }
2697
2885
  const theme = await detectTerminalTheme();
2886
+ let lastOpenedPath;
2698
2887
  const projects = await listProjectsUseCase.execute();
2888
+ const renderOptions = outputPathOnExit ? { stdout: process3.stderr, stdin: process3.stdin } : void 0;
2699
2889
  const { waitUntilExit } = render(
2700
2890
  /* @__PURE__ */ jsx7(ThemeProvider, { theme, children: /* @__PURE__ */ jsx7(
2701
2891
  App,
@@ -2706,12 +2896,24 @@ var bootstrap = async () => {
2706
2896
  onLaunchEditorOnly: (project) => launchEditorOnlyUseCase.execute(project),
2707
2897
  onTerminate: (project) => terminateProjectUseCase.execute(project),
2708
2898
  onRefresh: () => listProjectsUseCase.execute(),
2709
- useGitRootName
2899
+ useGitRootName,
2900
+ outputPathOnExit,
2901
+ onSetExitPath: (path) => {
2902
+ lastOpenedPath = path;
2903
+ }
2710
2904
  }
2711
- ) })
2905
+ ) }),
2906
+ renderOptions
2712
2907
  );
2713
2908
  await waitUntilExit();
2714
- process3.stdout.write("\x1B[2J\x1B[3J\x1B[H");
2909
+ if (outputPathOnExit) {
2910
+ process3.stderr.write("\x1B[2J\x1B[3J\x1B[H");
2911
+ if (lastOpenedPath) {
2912
+ process3.stdout.write(lastOpenedPath);
2913
+ }
2914
+ } else {
2915
+ process3.stdout.write("\x1B[2J\x1B[3J\x1B[H");
2916
+ }
2715
2917
  } catch (error) {
2716
2918
  const message = error instanceof Error ? error.message : String(error);
2717
2919
  console.error(message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unity-hub-cli",
3
- "version": "0.16.0",
3
+ "version": "0.18.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": {
@@ -8,10 +8,11 @@
8
8
  "dev": "tsx src/index.ts",
9
9
  "build": "tsup",
10
10
  "start": "node dist/index.js",
11
- "lint": "eslint . --ext .ts,.tsx",
12
- "lint:fix": "eslint . --ext .ts,.tsx --fix",
11
+ "lint": "eslint .",
12
+ "lint:fix": "eslint . --fix",
13
13
  "format": "prettier --write .",
14
- "typecheck": "tsc -noEmit"
14
+ "typecheck": "tsc -noEmit",
15
+ "allow-scripts": "allow-scripts"
15
16
  },
16
17
  "repository": {
17
18
  "type": "git",
@@ -36,26 +37,38 @@
36
37
  "dist"
37
38
  ],
38
39
  "dependencies": {
39
- "clipboardy": "^4.0.0",
40
- "ink": "^4.4.1",
41
- "react": "^18.3.1"
40
+ "chalk": "5.6.2",
41
+ "clipboardy": "5.0.1",
42
+ "ink": "6.5.1",
43
+ "react": "19.2.1"
42
44
  },
43
45
  "engines": {
44
46
  "node": ">=18"
45
47
  },
48
+ "lavamoat": {
49
+ "allowScripts": {
50
+ "eslint-import-resolver-typescript>unrs-resolver": false,
51
+ "tsup>bundle-require>esbuild": false,
52
+ "tsup>esbuild": false,
53
+ "tsx>esbuild": false
54
+ }
55
+ },
46
56
  "devDependencies": {
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"
57
+ "@eslint/js": "^9.39.1",
58
+ "@lavamoat/allow-scripts": "3.4.1",
59
+ "@types/node": "24.10.1",
60
+ "@types/react": "19.2.7",
61
+ "@typescript-eslint/eslint-plugin": "8.48.1",
62
+ "@typescript-eslint/parser": "8.48.1",
63
+ "eslint": "9.39.1",
64
+ "eslint-config-prettier": "10.1.8",
65
+ "eslint-import-resolver-typescript": "4.4.4",
66
+ "eslint-plugin-import": "2.32.0",
67
+ "prettier": "3.7.3",
68
+ "tsup": "8.5.1",
69
+ "tsx": "4.21.0",
70
+ "typescript": "5.9.3",
71
+ "typescript-eslint": "^8.48.1",
72
+ "vitest": "4.0.15"
60
73
  }
61
74
  }