unity-hub-cli 0.13.2 → 0.15.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 (2) hide show
  1. package/dist/index.js +572 -72
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.tsx
4
- import process2 from "process";
4
+ import process3 from "process";
5
5
  import { render } from "ink";
6
6
 
7
7
  // src/application/usecases.ts
@@ -105,6 +105,108 @@ var TerminateProjectUseCase = class {
105
105
  };
106
106
  }
107
107
  };
108
+ var LaunchWithEditorUseCase = class {
109
+ constructor(launchProjectUseCase, externalEditorPathReader, externalEditorLauncher) {
110
+ this.launchProjectUseCase = launchProjectUseCase;
111
+ this.externalEditorPathReader = externalEditorPathReader;
112
+ this.externalEditorLauncher = externalEditorLauncher;
113
+ }
114
+ /**
115
+ * Launches the Unity project and attempts to open the external editor.
116
+ * @param project - The Unity project to launch.
117
+ * @returns The result of the launch operation.
118
+ */
119
+ async execute(project) {
120
+ const editorResult = await this.externalEditorPathReader.read();
121
+ let editorLaunched = false;
122
+ let editorMessage = "";
123
+ if (editorResult.status === "found") {
124
+ editorLaunched = await this.tryLaunchEditor(editorResult, project.path);
125
+ editorMessage = editorLaunched ? ` + ${editorResult.name}` : " (Editor launch failed)";
126
+ } else {
127
+ editorMessage = this.buildEditorStatusMessage(editorResult);
128
+ }
129
+ await this.launchProjectUseCase.execute(project);
130
+ return {
131
+ unityLaunched: true,
132
+ editorLaunched,
133
+ message: `Launched: ${project.title}${editorMessage}`
134
+ };
135
+ }
136
+ /**
137
+ * Attempts to launch the external editor.
138
+ * @param editorResult - The found external editor result.
139
+ * @param projectPath - The path to the project root.
140
+ * @returns Whether the editor was successfully launched.
141
+ */
142
+ async tryLaunchEditor(editorResult, projectPath) {
143
+ try {
144
+ await this.externalEditorLauncher.launch(editorResult.path, projectPath);
145
+ return true;
146
+ } catch {
147
+ return false;
148
+ }
149
+ }
150
+ /**
151
+ * Builds a status message for non-found editor results.
152
+ * @param editorResult - The external editor result.
153
+ * @returns The status message.
154
+ */
155
+ buildEditorStatusMessage(editorResult) {
156
+ if (editorResult.status === "not_configured") {
157
+ return " (Editor not configured)";
158
+ }
159
+ if (editorResult.status === "not_found") {
160
+ return ` (Editor not found: ${editorResult.configuredPath})`;
161
+ }
162
+ return "";
163
+ }
164
+ };
165
+ var LaunchEditorOnlyUseCase = class {
166
+ constructor(externalEditorPathReader, externalEditorLauncher) {
167
+ this.externalEditorPathReader = externalEditorPathReader;
168
+ this.externalEditorLauncher = externalEditorLauncher;
169
+ }
170
+ /**
171
+ * Launches only the external editor for the specified project.
172
+ * @param project - The Unity project to open in the editor.
173
+ * @returns The result of the launch operation.
174
+ */
175
+ async execute(project) {
176
+ const editorResult = await this.externalEditorPathReader.read();
177
+ if (editorResult.status === "not_configured") {
178
+ return {
179
+ editorLaunched: false,
180
+ message: "Editor not configured in Unity preferences"
181
+ };
182
+ }
183
+ if (editorResult.status === "not_found") {
184
+ return {
185
+ editorLaunched: false,
186
+ message: `Editor not found: ${editorResult.configuredPath}`
187
+ };
188
+ }
189
+ const launched = await this.tryLaunchEditor(editorResult, project.path);
190
+ return {
191
+ editorLaunched: launched,
192
+ message: launched ? `Launched: ${editorResult.name}` : `Failed to launch ${editorResult.name}`
193
+ };
194
+ }
195
+ /**
196
+ * Attempts to launch the external editor.
197
+ * @param editorResult - The found external editor result.
198
+ * @param projectPath - The path to the project root.
199
+ * @returns Whether the editor was successfully launched.
200
+ */
201
+ async tryLaunchEditor(editorResult, projectPath) {
202
+ try {
203
+ await this.externalEditorLauncher.launch(editorResult.path, projectPath);
204
+ return true;
205
+ } catch {
206
+ return false;
207
+ }
208
+ }
209
+ };
108
210
 
109
211
  // src/infrastructure/editor.ts
110
212
  import { constants } from "fs";
@@ -158,9 +260,139 @@ var WinEditorPathResolver = class {
158
260
  }
159
261
  };
160
262
 
263
+ // src/infrastructure/externalEditor.ts
264
+ import { execFile } from "child_process";
265
+ import { constants as constants3, existsSync } from "fs";
266
+ import { access as access3 } from "fs/promises";
267
+ import { basename, join as join3 } from "path";
268
+ import { promisify } from "util";
269
+ var execFileAsync = promisify(execFile);
270
+ var PLIST_DOMAIN = "com.unity3d.UnityEditor5.x";
271
+ var PLIST_KEY = "kScriptsDefaultApp";
272
+ var MacExternalEditorPathReader = class {
273
+ /**
274
+ * Reads the external editor configuration from Unity preferences.
275
+ * @returns The external editor result with status and path information.
276
+ */
277
+ async read() {
278
+ let configuredPath;
279
+ try {
280
+ const result = await execFileAsync("defaults", ["read", PLIST_DOMAIN, PLIST_KEY]);
281
+ configuredPath = result.stdout.trim();
282
+ } catch {
283
+ return { status: "not_configured" };
284
+ }
285
+ if (!configuredPath) {
286
+ return { status: "not_configured" };
287
+ }
288
+ try {
289
+ await access3(configuredPath, constants3.F_OK);
290
+ } catch {
291
+ return { status: "not_found", configuredPath };
292
+ }
293
+ const name = basename(configuredPath, ".app");
294
+ return { status: "found", path: configuredPath, name };
295
+ }
296
+ };
297
+ var MacExternalEditorLauncher = class {
298
+ /**
299
+ * Launches the external editor with the specified project root.
300
+ * If a .sln file exists with the project name, it will be opened directly.
301
+ * This allows Rider to open the solution without showing a selection dialog.
302
+ * @param editorPath - The path to the editor application.
303
+ * @param projectRoot - The project root directory to open.
304
+ */
305
+ async launch(editorPath, projectRoot) {
306
+ const projectName = basename(projectRoot);
307
+ const slnFilePath = join3(projectRoot, `${projectName}.sln`);
308
+ const targetPath = existsSync(slnFilePath) ? slnFilePath : projectRoot;
309
+ await execFileAsync("open", ["-a", editorPath, targetPath]);
310
+ }
311
+ };
312
+
313
+ // src/infrastructure/externalEditor.win.ts
314
+ import { execFile as execFile2, spawn } from "child_process";
315
+ import { constants as constants4, existsSync as existsSync2 } from "fs";
316
+ import { access as access4 } from "fs/promises";
317
+ import { basename as basename2, join as join4 } from "path";
318
+ import { promisify as promisify2 } from "util";
319
+ var execFileAsync2 = promisify2(execFile2);
320
+ var REGISTRY_PATH = "HKEY_CURRENT_USER\\Software\\Unity Technologies\\Unity Editor 5.x";
321
+ var parseRegistryOutput = (stdout) => {
322
+ const lines = stdout.split("\n");
323
+ for (const line of lines) {
324
+ const match = line.match(/kScriptsDefaultApp[^\s]*\s+REG_SZ\s+(.+)/i);
325
+ if (match?.[1]) {
326
+ return match[1].trim();
327
+ }
328
+ }
329
+ return void 0;
330
+ };
331
+ var WinExternalEditorPathReader = class {
332
+ /**
333
+ * Reads the external editor configuration from Unity preferences.
334
+ * @returns The external editor result with status and path information.
335
+ */
336
+ async read() {
337
+ let configuredPath;
338
+ try {
339
+ const result = await execFileAsync2("reg", [
340
+ "query",
341
+ REGISTRY_PATH,
342
+ "/v",
343
+ "kScriptsDefaultApp"
344
+ ]);
345
+ configuredPath = parseRegistryOutput(result.stdout);
346
+ } catch {
347
+ return { status: "not_configured" };
348
+ }
349
+ if (!configuredPath) {
350
+ return { status: "not_configured" };
351
+ }
352
+ try {
353
+ await access4(configuredPath, constants4.F_OK);
354
+ } catch {
355
+ return { status: "not_found", configuredPath };
356
+ }
357
+ const name = basename2(configuredPath, ".exe");
358
+ return { status: "found", path: configuredPath, name };
359
+ }
360
+ };
361
+ var WinExternalEditorLauncher = class {
362
+ /**
363
+ * Launches the external editor with the specified project root.
364
+ * If a .sln file exists with the project name, it will be opened directly.
365
+ * This allows Rider to open the solution without showing a selection dialog.
366
+ * @param editorPath - The path to the editor executable.
367
+ * @param projectRoot - The project root directory to open.
368
+ */
369
+ async launch(editorPath, projectRoot) {
370
+ const projectName = basename2(projectRoot);
371
+ const slnFilePath = join4(projectRoot, `${projectName}.sln`);
372
+ const targetPath = existsSync2(slnFilePath) ? slnFilePath : projectRoot;
373
+ await new Promise((resolve4, reject) => {
374
+ const child = spawn(editorPath, [targetPath], {
375
+ detached: true,
376
+ stdio: "ignore"
377
+ });
378
+ const handleError = (error) => {
379
+ child.off("spawn", handleSpawn);
380
+ reject(error);
381
+ };
382
+ const handleSpawn = () => {
383
+ child.off("error", handleError);
384
+ child.unref();
385
+ resolve4();
386
+ };
387
+ child.once("error", handleError);
388
+ child.once("spawn", handleSpawn);
389
+ });
390
+ }
391
+ };
392
+
161
393
  // src/infrastructure/git.ts
162
394
  import { readFile, stat } from "fs/promises";
163
- import { dirname, join as join3, resolve } from "path";
395
+ import { dirname, join as join5, resolve } from "path";
164
396
  var HEAD_FILE = "HEAD";
165
397
  var GIT_DIR = ".git";
166
398
  var MAX_ASCENT = 50;
@@ -183,7 +415,7 @@ var isFile = async (path) => {
183
415
  var findGitDir = async (start) => {
184
416
  let current = resolve(start);
185
417
  for (let depth = 0; depth < MAX_ASCENT; depth += 1) {
186
- const candidate = join3(current, GIT_DIR);
418
+ const candidate = join5(current, GIT_DIR);
187
419
  if (await isDirectory(candidate)) {
188
420
  return candidate;
189
421
  }
@@ -227,7 +459,7 @@ var GitRepositoryInfoReader = class {
227
459
  return void 0;
228
460
  }
229
461
  try {
230
- const headPath = join3(gitDir, HEAD_FILE);
462
+ const headPath = join5(gitDir, HEAD_FILE);
231
463
  const content = await readFile(headPath, "utf8");
232
464
  const branch = parseHead(content);
233
465
  const root = dirname(gitDir);
@@ -239,12 +471,12 @@ var GitRepositoryInfoReader = class {
239
471
  };
240
472
 
241
473
  // src/infrastructure/process.ts
242
- import { spawn } from "child_process";
474
+ import { spawn as spawn2 } from "child_process";
243
475
  var NodeProcessLauncher = class {
244
476
  async launch(command, args, options) {
245
477
  const detached = options?.detached ?? false;
246
478
  await new Promise((resolve4, reject) => {
247
- const child = spawn(command, args, {
479
+ const child = spawn2(command, args, {
248
480
  detached,
249
481
  stdio: "ignore"
250
482
  });
@@ -263,9 +495,104 @@ var NodeProcessLauncher = class {
263
495
  }
264
496
  };
265
497
 
498
+ // src/infrastructure/terminalTheme.ts
499
+ import { createInterface } from "readline";
500
+ var parseOsc11Response = (response) => {
501
+ const rgbMatch = response.match(/rgb:([0-9a-fA-F]+)\/([0-9a-fA-F]+)\/([0-9a-fA-F]+)/);
502
+ if (!rgbMatch) {
503
+ return void 0;
504
+ }
505
+ const [, rHex, gHex, bHex] = rgbMatch;
506
+ if (!rHex || !gHex || !bHex) {
507
+ return void 0;
508
+ }
509
+ const normalizeColorValue = (hex) => {
510
+ const value = parseInt(hex, 16);
511
+ if (hex.length === 4) {
512
+ return Math.floor(value / 256);
513
+ }
514
+ return value;
515
+ };
516
+ return {
517
+ r: normalizeColorValue(rHex),
518
+ g: normalizeColorValue(gHex),
519
+ b: normalizeColorValue(bHex)
520
+ };
521
+ };
522
+ var calculateRelativeLuminance = (color) => {
523
+ const toLinear = (value) => {
524
+ const normalized = value / 255;
525
+ if (normalized <= 0.03928) {
526
+ return normalized / 12.92;
527
+ }
528
+ return Math.pow((normalized + 0.055) / 1.055, 2.4);
529
+ };
530
+ const rLinear = toLinear(color.r);
531
+ const gLinear = toLinear(color.g);
532
+ const bLinear = toLinear(color.b);
533
+ return 0.2126 * rLinear + 0.7152 * gLinear + 0.0722 * bLinear;
534
+ };
535
+ var determineThemeFromLuminance = (luminance) => {
536
+ const darkThreshold = 0.5;
537
+ return luminance < darkThreshold ? "dark" : "light";
538
+ };
539
+ var queryTerminalBackgroundColor = async (timeoutMs) => {
540
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
541
+ return void 0;
542
+ }
543
+ return new Promise((resolve4) => {
544
+ let responseBuffer = "";
545
+ let resolved = false;
546
+ if (process.stdin.isTTY) {
547
+ process.stdin.setRawMode(true);
548
+ }
549
+ const rl = createInterface({
550
+ input: process.stdin,
551
+ escapeCodeTimeout: timeoutMs
552
+ });
553
+ let timeoutId;
554
+ const onData = (chunk) => {
555
+ responseBuffer += chunk.toString();
556
+ if (responseBuffer.includes("\x07") || responseBuffer.includes("\x1B\\")) {
557
+ if (!resolved) {
558
+ resolved = true;
559
+ const color = parseOsc11Response(responseBuffer);
560
+ cleanup();
561
+ resolve4(color);
562
+ }
563
+ }
564
+ };
565
+ const cleanup = () => {
566
+ clearTimeout(timeoutId);
567
+ rl.close();
568
+ process.stdin.off("data", onData);
569
+ if (process.stdin.isTTY && process.stdin.isRaw) {
570
+ process.stdin.setRawMode(false);
571
+ }
572
+ };
573
+ timeoutId = setTimeout(() => {
574
+ if (!resolved) {
575
+ resolved = true;
576
+ cleanup();
577
+ resolve4(void 0);
578
+ }
579
+ }, timeoutMs);
580
+ process.stdin.on("data", onData);
581
+ process.stdout.write("\x1B]11;?\x07");
582
+ });
583
+ };
584
+ var detectTerminalTheme = async (timeoutMs = 100) => {
585
+ const backgroundColor = await queryTerminalBackgroundColor(timeoutMs);
586
+ if (!backgroundColor) {
587
+ return "dark";
588
+ }
589
+ const luminance = calculateRelativeLuminance(backgroundColor);
590
+ return determineThemeFromLuminance(luminance);
591
+ };
592
+
266
593
  // src/infrastructure/unityhub.ts
267
594
  import { readFile as readFile2, writeFile } from "fs/promises";
268
- import { basename } from "path";
595
+ import { basename as basename3 } from "path";
269
596
  var HUB_PROJECTS_PATH = `${process.env.HOME ?? ""}/Library/Application Support/UnityHub/projects-v1.json`;
270
597
  var schemaVersion = "v1";
271
598
  var toUnityProject = (entry) => {
@@ -280,7 +607,7 @@ var toUnityProject = (entry) => {
280
607
  const lastModified = typeof entry.lastModified === "number" ? new Date(entry.lastModified) : void 0;
281
608
  return {
282
609
  id: safePath,
283
- title: entry.title?.trim() || basename(safePath),
610
+ title: entry.title?.trim() || basename3(safePath),
284
611
  path: safePath,
285
612
  version: { value: version },
286
613
  lastModified,
@@ -395,9 +722,9 @@ var MacUnityHubProjectsReader = class {
395
722
 
396
723
  // src/infrastructure/unityhub.win.ts
397
724
  import { readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
398
- import { basename as basename2, join as join4 } from "path";
399
- var HUB_DIR = join4(process.env.APPDATA ?? "", "UnityHub");
400
- var HUB_PROJECTS_PATH2 = join4(HUB_DIR, "projects-v1.json");
725
+ import { basename as basename4, join as join6 } from "path";
726
+ var HUB_DIR = join6(process.env.APPDATA ?? "", "UnityHub");
727
+ var HUB_PROJECTS_PATH2 = join6(HUB_DIR, "projects-v1.json");
401
728
  var schemaVersion2 = "v1";
402
729
  var toUnityProject2 = (entry) => {
403
730
  const safePath = entry.path;
@@ -411,7 +738,7 @@ var toUnityProject2 = (entry) => {
411
738
  const lastModified = typeof entry.lastModified === "number" ? new Date(entry.lastModified) : void 0;
412
739
  return {
413
740
  id: safePath,
414
- title: entry.title?.trim() || basename2(safePath),
741
+ title: entry.title?.trim() || basename4(safePath),
415
742
  path: safePath,
416
743
  version: { value: version },
417
744
  lastModified,
@@ -499,7 +826,7 @@ var WinUnityHubProjectsReader = class {
499
826
  await writeFile2(HUB_PROJECTS_PATH2, JSON.stringify(json, void 0, 2), "utf8");
500
827
  }
501
828
  async readCliArgs(projectPath) {
502
- const infoPath = join4(HUB_DIR, "projectsInfo.json");
829
+ const infoPath = join6(HUB_DIR, "projectsInfo.json");
503
830
  let content;
504
831
  try {
505
832
  content = await readFile3(infoPath, "utf8");
@@ -525,18 +852,18 @@ var WinUnityHubProjectsReader = class {
525
852
  };
526
853
 
527
854
  // src/infrastructure/unityLock.ts
528
- import { execFile } from "child_process";
529
- import { constants as constants3 } from "fs";
530
- import { access as access3, rm } from "fs/promises";
531
- import { join as join5 } from "path";
532
- import { promisify } from "util";
533
- var execFileAsync = promisify(execFile);
855
+ import { execFile as execFile3 } from "child_process";
856
+ import { constants as constants5 } from "fs";
857
+ import { access as access5, rm } from "fs/promises";
858
+ import { join as join7 } from "path";
859
+ import { promisify as promisify3 } from "util";
860
+ var execFileAsync3 = promisify3(execFile3);
534
861
  var buildBringToFrontScript = (pid) => {
535
862
  return `tell application "System Events" to set frontmost of (first process whose unix id is ${pid}) to true`;
536
863
  };
537
864
  var pathExists = async (target) => {
538
865
  try {
539
- await access3(target, constants3.F_OK);
866
+ await access5(target, constants5.F_OK);
540
867
  return true;
541
868
  } catch {
542
869
  return false;
@@ -556,7 +883,7 @@ var UnityLockChecker = class {
556
883
  await this.bringUnityToFront(activeProcess.pid);
557
884
  return "skip";
558
885
  }
559
- const lockfilePath = join5(projectPath, "Temp", "UnityLockfile");
886
+ const lockfilePath = join7(projectPath, "Temp", "UnityLockfile");
560
887
  const hasLockfile = await pathExists(lockfilePath);
561
888
  if (!hasLockfile) {
562
889
  return "allow";
@@ -585,7 +912,7 @@ var UnityLockChecker = class {
585
912
  }
586
913
  try {
587
914
  const script = buildBringToFrontScript(pid);
588
- await execFileAsync("osascript", ["-e", script]);
915
+ await execFileAsync3("osascript", ["-e", script]);
589
916
  } catch (error) {
590
917
  const message = error instanceof Error ? error.message : String(error);
591
918
  console.error(`Failed to bring Unity to front: ${message}`);
@@ -594,16 +921,16 @@ var UnityLockChecker = class {
594
921
  };
595
922
  var UnityLockStatusReader = class {
596
923
  async isLocked(projectPath) {
597
- const lockfilePath = join5(projectPath, "Temp", "UnityLockfile");
924
+ const lockfilePath = join7(projectPath, "Temp", "UnityLockfile");
598
925
  return await pathExists(lockfilePath);
599
926
  }
600
927
  };
601
928
 
602
929
  // src/infrastructure/unityProcess.ts
603
- import { execFile as execFile2 } from "child_process";
930
+ import { execFile as execFile4 } from "child_process";
604
931
  import { resolve as resolve2 } from "path";
605
- import { promisify as promisify2 } from "util";
606
- var execFileAsync2 = promisify2(execFile2);
932
+ import { promisify as promisify4 } from "util";
933
+ var execFileAsync4 = promisify4(execFile4);
607
934
  var UNITY_EXECUTABLE_PATTERN = /Unity\.app\/Contents\/MacOS\/Unity/i;
608
935
  var PROJECT_PATH_PATTERN = /-(?:projectPath|projectpath)(?:=|\s+)("[^"]+"|'[^']+'|[^\s"']+)/i;
609
936
  var PROCESS_LIST_ARGS = ["-axo", "pid=,command=", "-ww"];
@@ -686,7 +1013,7 @@ var MacUnityProcessReader = class {
686
1013
  async listUnityProcesses() {
687
1014
  let stdout;
688
1015
  try {
689
- const result = await execFileAsync2(PROCESS_LIST_COMMAND, PROCESS_LIST_ARGS);
1016
+ const result = await execFileAsync4(PROCESS_LIST_COMMAND, PROCESS_LIST_ARGS);
690
1017
  stdout = result.stdout;
691
1018
  } catch (error) {
692
1019
  throw new Error(`Failed to retrieve Unity process list: ${error instanceof Error ? error.message : String(error)}`);
@@ -716,7 +1043,7 @@ var MacUnityProcessReader = class {
716
1043
  pid: pidValue,
717
1044
  projectPath: normalizePath(projectArgument)
718
1045
  };
719
- }).filter((process3) => Boolean(process3));
1046
+ }).filter((process4) => Boolean(process4));
720
1047
  }
721
1048
  };
722
1049
  var MacUnityProcessTerminator = class {
@@ -731,7 +1058,7 @@ var MacUnityProcessTerminator = class {
731
1058
  ' keystroke "q" using {command down}',
732
1059
  "end tell"
733
1060
  ].join("\n");
734
- await execFileAsync2("osascript", ["-e", script]);
1061
+ await execFileAsync4("osascript", ["-e", script]);
735
1062
  const deadlineGraceful = Date.now() + GRACEFUL_QUIT_TIMEOUT_MILLIS;
736
1063
  while (Date.now() < deadlineGraceful) {
737
1064
  await delay(GRACEFUL_QUIT_POLL_INTERVAL_MILLIS);
@@ -778,10 +1105,10 @@ var MacUnityProcessTerminator = class {
778
1105
  };
779
1106
 
780
1107
  // src/infrastructure/unityProcess.win.ts
781
- import { execFile as execFile3 } from "child_process";
1108
+ import { execFile as execFile5 } from "child_process";
782
1109
  import { resolve as resolve3 } from "path";
783
- import { promisify as promisify3 } from "util";
784
- var execFileAsync3 = promisify3(execFile3);
1110
+ import { promisify as promisify5 } from "util";
1111
+ var execFileAsync5 = promisify5(execFile5);
785
1112
  var PROJECT_PATH_PATTERN2 = /-(?:projectPath|projectpath)(?:=|\s+)("[^"]+"|'[^']+'|[^\s"']+)/i;
786
1113
  var TERMINATE_TIMEOUT_MILLIS2 = 5e3;
787
1114
  var TERMINATE_POLL_INTERVAL_MILLIS2 = 200;
@@ -872,7 +1199,7 @@ var WinUnityProcessReader = class {
872
1199
  ].join(" ");
873
1200
  let stdout;
874
1201
  try {
875
- const result = await execFileAsync3(
1202
+ const result = await execFileAsync5(
876
1203
  "powershell.exe",
877
1204
  [
878
1205
  "-NoProfile",
@@ -909,7 +1236,7 @@ var WinUnityProcessReader = class {
909
1236
  var WinUnityProcessTerminator = class {
910
1237
  async terminate(unityProcess) {
911
1238
  try {
912
- await execFileAsync3("powershell.exe", [
1239
+ await execFileAsync5("powershell.exe", [
913
1240
  "-NoProfile",
914
1241
  "-NonInteractive",
915
1242
  "-ExecutionPolicy",
@@ -931,7 +1258,7 @@ var WinUnityProcessTerminator = class {
931
1258
  }
932
1259
  }
933
1260
  try {
934
- await execFileAsync3("powershell.exe", [
1261
+ await execFileAsync5("powershell.exe", [
935
1262
  "-NoProfile",
936
1263
  "-NonInteractive",
937
1264
  "-ExecutionPolicy",
@@ -953,11 +1280,11 @@ var WinUnityProcessTerminator = class {
953
1280
 
954
1281
  // src/infrastructure/unityTemp.ts
955
1282
  import { rm as rm2 } from "fs/promises";
956
- import { join as join6 } from "path";
1283
+ import { join as join8 } from "path";
957
1284
  var TEMP_DIRECTORY_NAME = "Temp";
958
1285
  var UnityTempDirectoryCleaner = class {
959
1286
  async clean(projectPath) {
960
- const tempDirectoryPath = join6(projectPath, TEMP_DIRECTORY_NAME);
1287
+ const tempDirectoryPath = join8(projectPath, TEMP_DIRECTORY_NAME);
961
1288
  try {
962
1289
  await rm2(tempDirectoryPath, {
963
1290
  recursive: true,
@@ -969,7 +1296,8 @@ var UnityTempDirectoryCleaner = class {
969
1296
  };
970
1297
 
971
1298
  // src/presentation/App.tsx
972
- import { basename as basename4 } from "path";
1299
+ import { basename as basename6 } from "path";
1300
+ import process2 from "process";
973
1301
  import clipboard from "clipboardy";
974
1302
  import { Box as Box6, Text as Text4, useApp, useInput, useStdout as useStdout2 } from "ink";
975
1303
  import { useCallback, useEffect as useEffect4, useMemo as useMemo2, useState as useState4 } from "react";
@@ -1013,10 +1341,60 @@ var LayoutManager = ({
1013
1341
  };
1014
1342
 
1015
1343
  // src/presentation/components/ProjectList.tsx
1016
- import { basename as basename3 } from "path";
1344
+ import { basename as basename5 } from "path";
1017
1345
  import { Box as Box3 } from "ink";
1018
1346
  import { useMemo } from "react";
1019
1347
 
1348
+ // src/presentation/theme.ts
1349
+ import { createContext, createElement, useContext } from "react";
1350
+ var darkPalette = {
1351
+ projectName: "#abd8e7",
1352
+ // Light cyan
1353
+ branch: "#e3839c",
1354
+ // Pink
1355
+ path: "#719bd8",
1356
+ // Blue
1357
+ border: "green",
1358
+ // Green
1359
+ status: "yellow",
1360
+ // Yellow
1361
+ focus: "green"
1362
+ // Green
1363
+ };
1364
+ var lightPalette = {
1365
+ projectName: "#0044aa",
1366
+ // Deep blue
1367
+ branch: "#991144",
1368
+ // Deep magenta
1369
+ path: "#1a4570",
1370
+ // Deep blue
1371
+ border: "#006400",
1372
+ // Dark green
1373
+ status: "#cc6600",
1374
+ // Dark orange (more visible)
1375
+ focus: "#006400"
1376
+ // Dark green
1377
+ };
1378
+ var getColorPalette = (theme) => {
1379
+ return theme === "dark" ? darkPalette : lightPalette;
1380
+ };
1381
+ var defaultThemeContext = {
1382
+ theme: "dark",
1383
+ colors: darkPalette
1384
+ };
1385
+ var ThemeContext = createContext(defaultThemeContext);
1386
+ var useThemeColors = () => {
1387
+ const context = useContext(ThemeContext);
1388
+ return context.colors;
1389
+ };
1390
+ var ThemeProvider = ({ theme, children }) => {
1391
+ const value = {
1392
+ theme,
1393
+ colors: getColorPalette(theme)
1394
+ };
1395
+ return createElement(ThemeContext.Provider, { value }, children);
1396
+ };
1397
+
1020
1398
  // src/presentation/utils/path.ts
1021
1399
  var homeDirectory = process.env.HOME ?? process.env.USERPROFILE ?? "";
1022
1400
  var normalizedHomeDirectory = homeDirectory.replace(/\\/g, "/");
@@ -1070,13 +1448,14 @@ var ProjectRow = ({
1070
1448
  showSpacer
1071
1449
  }) => {
1072
1450
  const { stdout } = useStdout();
1451
+ const colors = useThemeColors();
1073
1452
  const computedCenterWidth = typeof stdout?.columns === "number" ? Math.max(0, stdout.columns - 6) : void 0;
1074
1453
  const centerWidth = typeof computedCenterWidth === "number" ? Math.max(0, computedCenterWidth - (isSelected ? 1 : 0)) : void 0;
1075
1454
  return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "row", children: [
1076
1455
  /* @__PURE__ */ jsxs2(Box2, { width: 1, flexDirection: "column", alignItems: "center", marginLeft: 0, children: [
1077
- /* @__PURE__ */ jsx2(Text, { color: isSelected ? "green" : void 0, children: selectionBar }),
1078
- showBranch ? /* @__PURE__ */ jsx2(Text, { color: isSelected ? "green" : void 0, children: selectionBar }) : null,
1079
- showPath ? /* @__PURE__ */ jsx2(Text, { color: isSelected ? "green" : void 0, children: selectionBar }) : null
1456
+ /* @__PURE__ */ jsx2(Text, { color: isSelected ? colors.focus : void 0, children: selectionBar }),
1457
+ showBranch ? /* @__PURE__ */ jsx2(Text, { color: isSelected ? colors.focus : void 0, children: selectionBar }) : null,
1458
+ showPath ? /* @__PURE__ */ jsx2(Text, { color: isSelected ? colors.focus : void 0, children: selectionBar }) : null
1080
1459
  ] }),
1081
1460
  /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginLeft: isSelected ? 2 : 1, width: centerWidth, children: [
1082
1461
  /* @__PURE__ */ jsxs2(Text, { wrap: "truncate", children: [
@@ -1088,8 +1467,8 @@ var ProjectRow = ({
1088
1467
  updatedText ? /* @__PURE__ */ jsx2(Text, { children: ` ${updatedText}` }) : null,
1089
1468
  statusLabel && statusColor ? /* @__PURE__ */ jsx2(Text, { color: statusColor, children: ` ${statusLabel}` }) : null
1090
1469
  ] }),
1091
- showBranch ? /* @__PURE__ */ jsx2(Text, { color: "#e3839c", wrap: "truncate", children: branchLine }) : null,
1092
- showPath ? /* @__PURE__ */ jsx2(Text, { color: "#719bd8", wrap: "truncate", children: pathLine }) : null,
1470
+ showBranch ? /* @__PURE__ */ jsx2(Text, { color: colors.branch, wrap: "truncate", children: branchLine }) : null,
1471
+ showPath ? /* @__PURE__ */ jsx2(Text, { color: colors.path, wrap: "truncate", children: pathLine }) : null,
1093
1472
  showSpacer ? /* @__PURE__ */ jsx2(Text, { children: " " }) : null
1094
1473
  ] }),
1095
1474
  /* @__PURE__ */ jsxs2(Box2, { marginLeft: 1, width: 1, flexDirection: "column", alignItems: "center", children: [
@@ -1103,8 +1482,6 @@ var ProjectRow = ({
1103
1482
 
1104
1483
  // src/presentation/components/ProjectList.tsx
1105
1484
  import { jsx as jsx3 } from "react/jsx-runtime";
1106
- var PROJECT_COLOR = "#abd8e7";
1107
- var LOCK_COLOR = "yellow";
1108
1485
  var STATUS_LABELS = {
1109
1486
  idle: "",
1110
1487
  running: "[running]",
@@ -1114,7 +1491,7 @@ var extractRootFolder = (repository) => {
1114
1491
  if (!repository?.root) {
1115
1492
  return void 0;
1116
1493
  }
1117
- const base = basename3(repository.root);
1494
+ const base = basename5(repository.root);
1118
1495
  return base || void 0;
1119
1496
  };
1120
1497
  var formatProjectName = (projectTitle, repository, useGitRootName) => {
@@ -1199,6 +1576,7 @@ var ProjectList = ({
1199
1576
  launchedProjects,
1200
1577
  totalProjects
1201
1578
  }) => {
1579
+ const colors = useThemeColors();
1202
1580
  const scrollbarChars = useMemo(() => {
1203
1581
  const totalLines = totalProjects * linesPerProject;
1204
1582
  const windowProjects = visibleProjects.length;
@@ -1252,14 +1630,14 @@ var ProjectList = ({
1252
1630
  const pathScrollbar = showPath ? scrollbarChars[baseScrollbarIndex + 1 + (showBranch ? 1 : 0)] ?? " " : " ";
1253
1631
  const spacerScrollbar = scrollbarChars[baseScrollbarIndex + linesPerProject - 1] ?? " ";
1254
1632
  const statusLabel = STATUS_LABELS[displayStatus];
1255
- const statusColor = displayStatus === "running" ? LOCK_COLOR : void 0;
1633
+ const statusColor = displayStatus === "running" ? colors.status : void 0;
1256
1634
  return /* @__PURE__ */ jsx3(
1257
1635
  ProjectRow,
1258
1636
  {
1259
1637
  isSelected,
1260
1638
  selectionBar,
1261
1639
  projectName,
1262
- projectColor: PROJECT_COLOR,
1640
+ projectColor: colors.projectName,
1263
1641
  versionLabel,
1264
1642
  updatedText,
1265
1643
  statusLabel,
@@ -1313,10 +1691,11 @@ var SortPanel = ({ sortPreferences, focusedIndex, width }) => {
1313
1691
  const primaryLine = lineForPrimary(sortPreferences.primary);
1314
1692
  const directionLine = lineForDirection(sortPreferences);
1315
1693
  const favoritesLine = lineForFavorites(sortPreferences.favoritesFirst);
1694
+ const colors = useThemeColors();
1316
1695
  const Item = ({ label, selected }) => {
1317
1696
  const prefix = selected ? "> " : " ";
1318
1697
  return /* @__PURE__ */ jsxs3(Text2, { children: [
1319
- selected ? /* @__PURE__ */ jsx4(Text2, { color: "green", children: prefix }) : prefix,
1698
+ selected ? /* @__PURE__ */ jsx4(Text2, { color: colors.focus, children: prefix }) : prefix,
1320
1699
  label
1321
1700
  ] });
1322
1701
  };
@@ -1325,7 +1704,7 @@ var SortPanel = ({ sortPreferences, focusedIndex, width }) => {
1325
1704
  {
1326
1705
  flexDirection: "column",
1327
1706
  borderStyle: "round",
1328
- borderColor: "green",
1707
+ borderColor: colors.border,
1329
1708
  paddingX: 1,
1330
1709
  width,
1331
1710
  children: [
@@ -1345,10 +1724,11 @@ var lineForPath = (on) => `Show path: ${on ? "ON" : "OFF"}`;
1345
1724
  var VisibilityPanel = ({ visibility, focusedIndex, width }) => {
1346
1725
  const branchLine = lineForBranch(visibility.showBranch);
1347
1726
  const pathLine = lineForPath(visibility.showPath);
1727
+ const colors = useThemeColors();
1348
1728
  const Item = ({ label, selected }) => {
1349
1729
  const prefix = selected ? "> " : " ";
1350
1730
  return /* @__PURE__ */ jsxs4(Text3, { children: [
1351
- selected ? /* @__PURE__ */ jsx5(Text3, { color: "green", children: prefix }) : prefix,
1731
+ selected ? /* @__PURE__ */ jsx5(Text3, { color: colors.focus, children: prefix }) : prefix,
1352
1732
  label
1353
1733
  ] });
1354
1734
  };
@@ -1357,7 +1737,7 @@ var VisibilityPanel = ({ visibility, focusedIndex, width }) => {
1357
1737
  {
1358
1738
  flexDirection: "column",
1359
1739
  borderStyle: "round",
1360
- borderColor: "green",
1740
+ borderColor: colors.border,
1361
1741
  paddingX: 1,
1362
1742
  width,
1363
1743
  children: [
@@ -1544,11 +1924,12 @@ var extractRootFolder2 = (repository) => {
1544
1924
  if (!repository?.root) {
1545
1925
  return void 0;
1546
1926
  }
1547
- const base = basename4(repository.root);
1927
+ const base = basename6(repository.root);
1548
1928
  return base || void 0;
1549
1929
  };
1550
1930
  var minimumVisibleProjectCount = 4;
1551
- var defaultHintMessage = "j/k Select \xB7 [o]pen [q]uit [r]efresh [c]opy [s]ort [v]isibility \xB7 ^C Exit";
1931
+ var editorOnlyKey = process2.platform === "darwin" ? "\u2325o" : "Alt+o";
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`;
1552
1933
  var getCopyTargetPath = (view) => {
1553
1934
  const root = view.repository?.root;
1554
1935
  return root && root.length > 0 ? root : view.project.path;
@@ -1556,12 +1937,15 @@ var getCopyTargetPath = (view) => {
1556
1937
  var App = ({
1557
1938
  projects,
1558
1939
  onLaunch,
1940
+ onLaunchWithEditor,
1941
+ onLaunchEditorOnly,
1559
1942
  onTerminate,
1560
1943
  onRefresh,
1561
1944
  useGitRootName = true
1562
1945
  }) => {
1563
1946
  const { exit } = useApp();
1564
1947
  const { stdout } = useStdout2();
1948
+ const colors = useThemeColors();
1565
1949
  const [projectViews, setProjectViews] = useState4(projects);
1566
1950
  const [isSortMenuOpen, setIsSortMenuOpen] = useState4(false);
1567
1951
  const [isVisibilityMenuOpen, setIsVisibilityMenuOpen] = useState4(false);
@@ -1651,9 +2035,9 @@ var App = ({
1651
2035
  const handleSigint = () => {
1652
2036
  exit();
1653
2037
  };
1654
- process.on("SIGINT", handleSigint);
2038
+ process2.on("SIGINT", handleSigint);
1655
2039
  return () => {
1656
- process.off("SIGINT", handleSigint);
2040
+ process2.off("SIGINT", handleSigint);
1657
2041
  };
1658
2042
  }, [exit]);
1659
2043
  const limit = Math.max(1, visibleCount);
@@ -1800,6 +2184,100 @@ var App = ({
1800
2184
  }, 3e3);
1801
2185
  }
1802
2186
  }, [index, onLaunch, sortedProjects]);
2187
+ const launchSelectedWithEditor = useCallback(async () => {
2188
+ if (!onLaunchWithEditor) {
2189
+ setHint("Launch with editor not available");
2190
+ setTimeout(() => {
2191
+ setHint(defaultHintMessage);
2192
+ }, 2e3);
2193
+ return;
2194
+ }
2195
+ const projectView = sortedProjects[index];
2196
+ if (!projectView) {
2197
+ setHint("No project to launch");
2198
+ setTimeout(() => {
2199
+ setHint(defaultHintMessage);
2200
+ }, 2e3);
2201
+ return;
2202
+ }
2203
+ const { project } = projectView;
2204
+ try {
2205
+ const cdTarget = getCopyTargetPath(projectView);
2206
+ const command = buildCdCommand(cdTarget);
2207
+ clipboard.writeSync(command);
2208
+ } catch (error) {
2209
+ const message = error instanceof Error ? error.message : String(error);
2210
+ setHint(`Failed to copy: ${message}`);
2211
+ setTimeout(() => {
2212
+ setHint(defaultHintMessage);
2213
+ }, 3e3);
2214
+ return;
2215
+ }
2216
+ try {
2217
+ const result = await onLaunchWithEditor(project);
2218
+ setLaunchedProjects((previous) => {
2219
+ const next = new Set(previous);
2220
+ next.add(project.id);
2221
+ return next;
2222
+ });
2223
+ setReleasedProjects((previous) => {
2224
+ if (!previous.has(project.id)) {
2225
+ return previous;
2226
+ }
2227
+ const next = new Set(previous);
2228
+ next.delete(project.id);
2229
+ return next;
2230
+ });
2231
+ setHint(result.message);
2232
+ setTimeout(() => {
2233
+ setHint(defaultHintMessage);
2234
+ }, 3e3);
2235
+ } catch (error) {
2236
+ if (error instanceof LaunchCancelledError) {
2237
+ setHint("Launch cancelled");
2238
+ setTimeout(() => {
2239
+ setHint(defaultHintMessage);
2240
+ }, 3e3);
2241
+ return;
2242
+ }
2243
+ const message = error instanceof Error ? error.message : String(error);
2244
+ setHint(`Failed to launch: ${message}`);
2245
+ setTimeout(() => {
2246
+ setHint(defaultHintMessage);
2247
+ }, 3e3);
2248
+ }
2249
+ }, [index, onLaunchWithEditor, sortedProjects]);
2250
+ const launchEditorOnly = useCallback(async () => {
2251
+ if (!onLaunchEditorOnly) {
2252
+ setHint("Launch editor only not available");
2253
+ setTimeout(() => {
2254
+ setHint(defaultHintMessage);
2255
+ }, 2e3);
2256
+ return;
2257
+ }
2258
+ const projectView = sortedProjects[index];
2259
+ if (!projectView) {
2260
+ setHint("No project to open");
2261
+ setTimeout(() => {
2262
+ setHint(defaultHintMessage);
2263
+ }, 2e3);
2264
+ return;
2265
+ }
2266
+ const { project } = projectView;
2267
+ try {
2268
+ const result = await onLaunchEditorOnly(project);
2269
+ setHint(result.message);
2270
+ setTimeout(() => {
2271
+ setHint(defaultHintMessage);
2272
+ }, 3e3);
2273
+ } catch (error) {
2274
+ const message = error instanceof Error ? error.message : String(error);
2275
+ setHint(`Failed to launch editor: ${message}`);
2276
+ setTimeout(() => {
2277
+ setHint(defaultHintMessage);
2278
+ }, 3e3);
2279
+ }
2280
+ }, [index, onLaunchEditorOnly, sortedProjects]);
1803
2281
  const terminateSelected = useCallback(async () => {
1804
2282
  const projectView = sortedProjects[index];
1805
2283
  if (!projectView) {
@@ -2003,10 +2481,18 @@ var App = ({
2003
2481
  void terminateSelected();
2004
2482
  return;
2005
2483
  }
2484
+ if (input === "\xF8" || input === "o" && key.meta) {
2485
+ void launchEditorOnly();
2486
+ return;
2487
+ }
2006
2488
  if (input === "o") {
2007
2489
  void launchSelected();
2008
2490
  return;
2009
2491
  }
2492
+ if (input === "O") {
2493
+ void launchSelectedWithEditor();
2494
+ return;
2495
+ }
2010
2496
  if (input === "r") {
2011
2497
  void refreshProjects();
2012
2498
  return;
@@ -2040,7 +2526,7 @@ var App = ({
2040
2526
  {
2041
2527
  flexDirection: "column",
2042
2528
  borderStyle: "round",
2043
- borderColor: "green",
2529
+ borderColor: colors.border,
2044
2530
  width: typeof stdout?.columns === "number" ? stdout.columns : void 0,
2045
2531
  children: sortedProjects.length === 0 ? /* @__PURE__ */ jsx6(Text4, { children: "No Unity Hub projects were found." }) : /* @__PURE__ */ jsx6(
2046
2532
  ProjectList,
@@ -2091,7 +2577,7 @@ var App = ({
2091
2577
  // src/index.tsx
2092
2578
  import { jsx as jsx7 } from "react/jsx-runtime";
2093
2579
  var bootstrap = async () => {
2094
- const isWindows = process2.platform === "win32";
2580
+ const isWindows = process3.platform === "win32";
2095
2581
  const unityHubReader = isWindows ? new WinUnityHubProjectsReader() : new MacUnityHubProjectsReader();
2096
2582
  const gitRepositoryInfoReader = new GitRepositoryInfoReader();
2097
2583
  const lockStatusReader = new UnityLockStatusReader();
@@ -2120,48 +2606,62 @@ var bootstrap = async () => {
2120
2606
  unityProcessTerminator,
2121
2607
  unityTempDirectoryCleaner
2122
2608
  );
2123
- const useGitRootName = !process2.argv.includes("--no-git-root-name");
2609
+ const externalEditorPathReader = isWindows ? new WinExternalEditorPathReader() : new MacExternalEditorPathReader();
2610
+ const externalEditorLauncher = isWindows ? new WinExternalEditorLauncher() : new MacExternalEditorLauncher();
2611
+ const launchWithEditorUseCase = new LaunchWithEditorUseCase(
2612
+ launchProjectUseCase,
2613
+ externalEditorPathReader,
2614
+ externalEditorLauncher
2615
+ );
2616
+ const launchEditorOnlyUseCase = new LaunchEditorOnlyUseCase(
2617
+ externalEditorPathReader,
2618
+ externalEditorLauncher
2619
+ );
2620
+ const useGitRootName = !process3.argv.includes("--no-git-root-name");
2124
2621
  try {
2125
2622
  const rawModeSupported = Boolean(
2126
- process2.stdin.isTTY && typeof process2.stdin.setRawMode === "function"
2623
+ process3.stdin.isTTY && typeof process3.stdin.setRawMode === "function"
2127
2624
  );
2128
2625
  if (!rawModeSupported) {
2129
2626
  const message = [
2130
- "\u3053\u306E\u7AEF\u672B\u3067\u306F\u5BFE\u8A71\u5165\u529B\uFF08Raw mode\uFF09\u304C\u4F7F\u3048\u307E\u305B\u3093\u3002",
2131
- "PowerShell / cmd.exe \u3067\u5B9F\u884C\u3059\u308B\u304B\u3001ConPTY \u30D9\u30FC\u30B9\u306E\u30BF\u30FC\u30DF\u30CA\u30EB\uFF08Windows Terminal, VS Code/Cursor \u306E\u7D71\u5408\u30BF\u30FC\u30DF\u30CA\u30EB\uFF09\u3067 Git Bash \u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2132
- "MinTTY \u306E Git Bash \u3067\u306F\u6B21\u306E\u3044\u305A\u308C\u304B\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044:",
2627
+ "Interactive input (Raw mode) is not available in this terminal.",
2628
+ "Please run in PowerShell / cmd.exe, or use Git Bash in a ConPTY-based terminal (Windows Terminal, VS Code/Cursor integrated terminal).",
2629
+ "For MinTTY Git Bash, use one of the following:",
2133
2630
  " - winpty cmd.exe /c npx unity-hub-cli",
2134
2631
  " - winpty powershell.exe -NoProfile -Command npx unity-hub-cli",
2135
- "\uFF08\u30D3\u30EB\u30C9\u6E08\u307F\u306E\u5834\u5408\uFF09npm run build && winpty node dist/index.js",
2136
- "\u8A73\u3057\u304F: https://github.com/vadimdemedes/ink/#israwmodesupported"
2632
+ "(If already built) npm run build && winpty node dist/index.js",
2633
+ "Details: https://github.com/vadimdemedes/ink/#israwmodesupported"
2137
2634
  ].join("\n");
2138
2635
  console.error(message);
2139
- process2.exitCode = 1;
2636
+ process3.exitCode = 1;
2140
2637
  return;
2141
2638
  }
2639
+ const theme = await detectTerminalTheme();
2142
2640
  const projects = await listProjectsUseCase.execute();
2143
2641
  const { waitUntilExit } = render(
2144
- /* @__PURE__ */ jsx7(
2642
+ /* @__PURE__ */ jsx7(ThemeProvider, { theme, children: /* @__PURE__ */ jsx7(
2145
2643
  App,
2146
2644
  {
2147
2645
  projects,
2148
2646
  onLaunch: (project) => launchProjectUseCase.execute(project),
2647
+ onLaunchWithEditor: (project) => launchWithEditorUseCase.execute(project),
2648
+ onLaunchEditorOnly: (project) => launchEditorOnlyUseCase.execute(project),
2149
2649
  onTerminate: (project) => terminateProjectUseCase.execute(project),
2150
2650
  onRefresh: () => listProjectsUseCase.execute(),
2151
2651
  useGitRootName
2152
2652
  }
2153
- )
2653
+ ) })
2154
2654
  );
2155
2655
  await waitUntilExit();
2156
- process2.stdout.write("\x1B[2J\x1B[3J\x1B[H");
2656
+ process3.stdout.write("\x1B[2J\x1B[3J\x1B[H");
2157
2657
  } catch (error) {
2158
2658
  const message = error instanceof Error ? error.message : String(error);
2159
2659
  console.error(message);
2160
- process2.exitCode = 1;
2660
+ process3.exitCode = 1;
2161
2661
  }
2162
2662
  };
2163
2663
  void bootstrap().catch((error) => {
2164
2664
  const message = error instanceof Error ? error.message : String(error);
2165
2665
  console.error(message);
2166
- process2.exitCode = 1;
2666
+ process3.exitCode = 1;
2167
2667
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unity-hub-cli",
3
- "version": "0.13.2",
3
+ "version": "0.15.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": {