uloop-cli 0.59.1 → 0.61.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.
@@ -5763,7 +5763,7 @@ var import_path3 = require("path");
5763
5763
 
5764
5764
  // src/default-tools.json
5765
5765
  var default_tools_default = {
5766
- version: "0.59.1",
5766
+ version: "0.61.0",
5767
5767
  tools: [
5768
5768
  {
5769
5769
  name: "compile",
@@ -5849,10 +5849,6 @@ var default_tools_default = {
5849
5849
  FilterValue: {
5850
5850
  type: "string",
5851
5851
  description: "Filter value"
5852
- },
5853
- SaveXml: {
5854
- type: "boolean",
5855
- description: "Save test results as XML"
5856
5852
  }
5857
5853
  }
5858
5854
  }
@@ -6084,10 +6080,6 @@ var default_tools_default = {
6084
6080
  CompileOnly: {
6085
6081
  type: "boolean",
6086
6082
  description: "Compile only without execution"
6087
- },
6088
- AutoQualifyUnityTypesOnce: {
6089
- type: "boolean",
6090
- description: "Auto-qualify Unity types"
6091
6083
  }
6092
6084
  }
6093
6085
  }
@@ -6215,7 +6207,7 @@ function getCachedServerVersion() {
6215
6207
  }
6216
6208
 
6217
6209
  // src/version.ts
6218
- var VERSION = "0.59.1";
6210
+ var VERSION = "0.61.0";
6219
6211
 
6220
6212
  // src/spinner.ts
6221
6213
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
@@ -7472,6 +7464,24 @@ var parseCliArgs = (cliArgsString) => {
7472
7464
  }
7473
7465
  return tokens;
7474
7466
  };
7467
+ var groupCliArgs = (args) => {
7468
+ const groups = [];
7469
+ let current = "";
7470
+ for (const arg of args) {
7471
+ if (arg.startsWith("-") && current.length > 0) {
7472
+ groups.push(current);
7473
+ current = arg;
7474
+ } else if (current.length === 0) {
7475
+ current = arg;
7476
+ } else {
7477
+ current += ` ${arg}`;
7478
+ }
7479
+ }
7480
+ if (current.length > 0) {
7481
+ groups.push(current);
7482
+ }
7483
+ return groups;
7484
+ };
7475
7485
  var getProjectCliArgs = async (projectPath) => {
7476
7486
  (0, import_node_assert.default)(projectPath !== null && projectPath !== void 0, "projectPath must not be null");
7477
7487
  const infoFilePath = resolveUnityHubProjectsInfoFile();
@@ -7777,9 +7787,11 @@ async function handleStaleLockfile(projectPath) {
7777
7787
  const message = error instanceof Error ? error.message : String(error);
7778
7788
  console.warn(`Failed to delete UnityLockfile: ${message}`);
7779
7789
  }
7790
+ console.log();
7780
7791
  }
7781
7792
  var KILL_POLL_INTERVAL_MS = 100;
7782
7793
  var KILL_TIMEOUT_MS = 1e4;
7794
+ var GRACEFUL_QUIT_TIMEOUT_MS = 1e4;
7783
7795
  function isProcessAlive(pid) {
7784
7796
  try {
7785
7797
  process.kill(pid, 0);
@@ -7794,9 +7806,9 @@ function killProcess(pid) {
7794
7806
  } catch {
7795
7807
  }
7796
7808
  }
7797
- async function waitForProcessExit(pid) {
7809
+ async function waitForProcessExit(pid, timeoutMs) {
7798
7810
  const start = Date.now();
7799
- while (Date.now() - start < KILL_TIMEOUT_MS) {
7811
+ while (Date.now() - start < timeoutMs) {
7800
7812
  if (!isProcessAlive(pid)) {
7801
7813
  return true;
7802
7814
  }
@@ -7808,16 +7820,73 @@ async function killRunningUnity(projectPath) {
7808
7820
  const processInfo = await findRunningUnityProcess(projectPath);
7809
7821
  if (!processInfo) {
7810
7822
  console.log("No running Unity process found for this project.");
7823
+ console.log();
7811
7824
  return;
7812
7825
  }
7813
7826
  const pid = processInfo.pid;
7814
7827
  console.log(`Killing Unity (PID: ${pid})...`);
7815
7828
  killProcess(pid);
7816
- const exited = await waitForProcessExit(pid);
7829
+ const exited = await waitForProcessExit(pid, KILL_TIMEOUT_MS);
7817
7830
  if (!exited) {
7818
7831
  throw new Error(`Failed to kill Unity (PID: ${pid}) within ${KILL_TIMEOUT_MS / 1e3}s.`);
7819
7832
  }
7820
7833
  console.log("Unity killed.");
7834
+ console.log();
7835
+ }
7836
+ async function sendGracefulQuitMac(pid) {
7837
+ const script = [
7838
+ 'tell application "System Events"',
7839
+ ` set frontmost of (first process whose unix id is ${pid}) to true`,
7840
+ ' keystroke "q" using {command down}',
7841
+ "end tell"
7842
+ ].join("\n");
7843
+ try {
7844
+ await execFileAsync("osascript", ["-e", script]);
7845
+ } catch {
7846
+ }
7847
+ }
7848
+ async function sendGracefulQuitWindows(pid) {
7849
+ const scriptLines = [
7850
+ "$ErrorActionPreference = 'Stop'",
7851
+ `try { $proc = Get-Process -Id ${pid} -ErrorAction Stop; $proc.CloseMainWindow() | Out-Null } catch { }`
7852
+ ];
7853
+ try {
7854
+ await execFileAsync(WINDOWS_POWERSHELL, ["-NoProfile", "-Command", scriptLines.join("\n")]);
7855
+ } catch {
7856
+ }
7857
+ }
7858
+ async function sendGracefulQuit(pid) {
7859
+ if (process.platform === "darwin") {
7860
+ await sendGracefulQuitMac(pid);
7861
+ return;
7862
+ }
7863
+ if (process.platform === "win32") {
7864
+ await sendGracefulQuitWindows(pid);
7865
+ return;
7866
+ }
7867
+ }
7868
+ async function quitRunningUnity(projectPath) {
7869
+ const processInfo = await findRunningUnityProcess(projectPath);
7870
+ if (!processInfo) {
7871
+ console.log("No running Unity process found for this project.");
7872
+ return;
7873
+ }
7874
+ const pid = processInfo.pid;
7875
+ console.log(`Quitting Unity (PID: ${pid})...`);
7876
+ await sendGracefulQuit(pid);
7877
+ console.log(`Sent graceful quit signal. Waiting up to ${GRACEFUL_QUIT_TIMEOUT_MS / 1e3}s...`);
7878
+ const exitedGracefully = await waitForProcessExit(pid, GRACEFUL_QUIT_TIMEOUT_MS);
7879
+ if (exitedGracefully) {
7880
+ console.log("Unity quit gracefully.");
7881
+ return;
7882
+ }
7883
+ console.log("Unity did not respond to graceful quit. Force killing...");
7884
+ killProcess(pid);
7885
+ const exitedAfterKill = await waitForProcessExit(pid, KILL_TIMEOUT_MS);
7886
+ if (!exitedAfterKill) {
7887
+ throw new Error(`Failed to kill Unity (PID: ${pid}) within ${KILL_TIMEOUT_MS / 1e3}s.`);
7888
+ }
7889
+ console.log("Unity force killed.");
7821
7890
  }
7822
7891
  function hasBuildTargetArg(unityArgs) {
7823
7892
  for (const arg of unityArgs) {
@@ -7908,12 +7977,12 @@ function findUnityProjectBfs(rootDir, maxDepth) {
7908
7977
  async function launch(opts) {
7909
7978
  const { projectPath, platform, unityArgs, unityVersion } = opts;
7910
7979
  const unityPath = getUnityPath(unityVersion);
7911
- console.log(`Detected Unity version: ${unityVersion}`);
7912
7980
  if (!(0, import_node_fs2.existsSync)(unityPath)) {
7913
7981
  throw new Error(`Unity ${unityVersion} not found at ${unityPath}. Please install Unity through Unity Hub.`);
7914
7982
  }
7915
7983
  console.log("Opening Unity...");
7916
7984
  console.log(`Project Path: ${projectPath}`);
7985
+ console.log(`Detected Unity version: ${unityVersion}`);
7917
7986
  const args = ["-projectPath", projectPath];
7918
7987
  const unityArgsContainBuildTarget = hasBuildTargetArg(unityArgs);
7919
7988
  if (platform && platform.length > 0 && !unityArgsContainBuildTarget) {
@@ -7921,86 +7990,133 @@ async function launch(opts) {
7921
7990
  }
7922
7991
  const hubCliArgs = await getProjectCliArgs(projectPath);
7923
7992
  if (hubCliArgs.length > 0) {
7993
+ console.log("Unity Hub launch options:");
7994
+ for (const line of groupCliArgs(hubCliArgs)) {
7995
+ console.log(` ${line}`);
7996
+ }
7924
7997
  args.push(...hubCliArgs);
7998
+ } else {
7999
+ console.log("Unity Hub launch options: none");
7925
8000
  }
7926
8001
  if (unityArgs.length > 0) {
7927
8002
  args.push(...unityArgs);
7928
8003
  }
7929
- const child = (0, import_node_child_process.spawn)(unityPath, args, { stdio: "ignore", detached: true });
7930
- child.unref();
7931
- }
7932
-
7933
- // src/commands/launch.ts
7934
- function registerLaunchCommand(program3) {
7935
- program3.command("launch").description("Launch Unity project with matching Editor version").argument("[project-path]", "Path to Unity project").option("-r, --restart", "Kill running Unity and restart").option("-p, --platform <platform>", "Build target (e.g., Android, iOS)").option("--max-depth <n>", "Search depth when project-path is omitted", "3").option("-a, --add-unity-hub", "Add to Unity Hub (does not launch)").option("-f, --favorite", "Add to Unity Hub as favorite (does not launch)").action(async (projectPath, options) => {
7936
- await runLaunchCommand(projectPath, options);
8004
+ return new Promise((resolve5, reject) => {
8005
+ const child = (0, import_node_child_process.spawn)(unityPath, args, {
8006
+ stdio: "ignore",
8007
+ detached: true,
8008
+ // Git Bash (MSYS) がWindows パスをUnix 形式に自動変換するのを防ぐ
8009
+ env: {
8010
+ ...process.env,
8011
+ MSYS_NO_PATHCONV: "1"
8012
+ }
8013
+ });
8014
+ const handleError = (error) => {
8015
+ child.removeListener("spawn", handleSpawn);
8016
+ reject(new Error(`Failed to launch Unity: ${error.message}`));
8017
+ };
8018
+ const handleSpawn = () => {
8019
+ child.removeListener("error", handleError);
8020
+ child.unref();
8021
+ resolve5();
8022
+ };
8023
+ child.once("error", handleError);
8024
+ child.once("spawn", handleSpawn);
7937
8025
  });
7938
8026
  }
7939
- function parseMaxDepth(value) {
7940
- if (value === void 0) {
7941
- return 3;
8027
+ async function orchestrateLaunch(options) {
8028
+ if (options.quit && options.restart) {
8029
+ throw new Error("--quit and --restart cannot be used together.");
7942
8030
  }
7943
- const parsed = parseInt(value, 10);
7944
- if (Number.isNaN(parsed)) {
7945
- console.error(`Error: Invalid --max-depth value: "${value}". Must be an integer.`);
7946
- process.exit(1);
7947
- }
7948
- return parsed;
7949
- }
7950
- async function runLaunchCommand(projectPath, options) {
7951
- const maxDepth = parseMaxDepth(options.maxDepth);
7952
- let resolvedProjectPath = projectPath ? (0, import_path6.resolve)(projectPath) : void 0;
8031
+ let resolvedProjectPath = options.projectPath;
7953
8032
  if (!resolvedProjectPath) {
7954
- const searchRoot = process.cwd();
7955
- const depthInfo = maxDepth === -1 ? "unlimited" : String(maxDepth);
7956
- console.log(
7957
- `No project-path provided. Searching under ${searchRoot} (max-depth: ${depthInfo})...`
7958
- );
7959
- const found = findUnityProjectBfs(searchRoot, maxDepth);
8033
+ const depthInfo = options.searchMaxDepth === -1 ? "unlimited" : String(options.searchMaxDepth);
8034
+ console.log(`Searching for Unity project under ${options.searchRoot} (max-depth: ${depthInfo})...`);
8035
+ const found = findUnityProjectBfs(options.searchRoot, options.searchMaxDepth);
7960
8036
  if (!found) {
7961
- console.error(`Error: Unity project not found under ${searchRoot}.`);
7962
- process.exit(1);
8037
+ throw new Error(`Unity project not found under ${options.searchRoot}.`);
7963
8038
  }
7964
- console.log(`Selected project: ${found}`);
8039
+ console.log();
7965
8040
  resolvedProjectPath = found;
7966
8041
  }
8042
+ if (!(0, import_node_fs2.existsSync)(resolvedProjectPath)) {
8043
+ throw new Error(`Project directory not found: ${resolvedProjectPath}`);
8044
+ }
7967
8045
  const unityVersion = getUnityVersion(resolvedProjectPath);
7968
- const unityHubOnlyMode = options.addUnityHub === true || options.favorite === true;
7969
- if (unityHubOnlyMode) {
8046
+ if (options.addUnityHub || options.favoriteUnityHub) {
7970
8047
  console.log(`Detected Unity version: ${unityVersion}`);
7971
8048
  console.log(`Project Path: ${resolvedProjectPath}`);
7972
8049
  const now2 = /* @__PURE__ */ new Date();
7973
- await ensureProjectEntryAndUpdate(
7974
- resolvedProjectPath,
7975
- unityVersion,
7976
- now2,
7977
- options.favorite === true
7978
- );
8050
+ await ensureProjectEntryAndUpdate(resolvedProjectPath, unityVersion, now2, options.favoriteUnityHub);
7979
8051
  console.log("Unity Hub entry updated.");
7980
- return;
8052
+ return { action: "hub-updated", projectPath: resolvedProjectPath, unityVersion };
7981
8053
  }
7982
- if (options.restart === true) {
8054
+ if (options.quit) {
8055
+ await quitRunningUnity(resolvedProjectPath);
8056
+ return { action: "quit", projectPath: resolvedProjectPath };
8057
+ }
8058
+ const isRestart = options.restart;
8059
+ if (isRestart) {
7983
8060
  await killRunningUnity(resolvedProjectPath);
7984
8061
  } else {
7985
8062
  const runningProcess = await findRunningUnityProcess(resolvedProjectPath);
7986
8063
  if (runningProcess) {
7987
- console.log(
7988
- `Unity process already running for project: ${resolvedProjectPath} (PID: ${runningProcess.pid})`
7989
- );
8064
+ console.log(`Unity process already running for project: ${resolvedProjectPath} (PID: ${runningProcess.pid})`);
7990
8065
  await focusUnityProcess(runningProcess.pid);
7991
- return;
8066
+ return { action: "focused", projectPath: resolvedProjectPath, pid: runningProcess.pid };
7992
8067
  }
7993
8068
  }
7994
8069
  await handleStaleLockfile(resolvedProjectPath);
7995
8070
  const resolved = {
7996
8071
  projectPath: resolvedProjectPath,
7997
8072
  platform: options.platform,
7998
- unityArgs: [],
8073
+ unityArgs: options.unityArgs,
7999
8074
  unityVersion
8000
8075
  };
8001
8076
  await launch(resolved);
8002
8077
  const now = /* @__PURE__ */ new Date();
8003
- await updateLastModifiedIfExists(resolvedProjectPath, now);
8078
+ try {
8079
+ await updateLastModifiedIfExists(resolvedProjectPath, now);
8080
+ } catch (error) {
8081
+ const message = error instanceof Error ? error.message : String(error);
8082
+ console.warn(`Failed to update Unity Hub lastModified: ${message}`);
8083
+ }
8084
+ const action = isRestart ? "killed-and-launched" : "launched";
8085
+ return { action, projectPath: resolvedProjectPath, unityVersion };
8086
+ }
8087
+
8088
+ // src/commands/launch.ts
8089
+ function registerLaunchCommand(program3) {
8090
+ program3.command("launch").description(
8091
+ "Open a Unity project with the matching Editor version installed by Unity Hub.\nAuto-detects project path and Unity version from ProjectSettings/ProjectVersion.txt.\nRun 'uloop launch -h' for all options. Details: https://github.com/hatayama/LaunchUnityCommand"
8092
+ ).argument("[project-path]", "Path to Unity project").option("-r, --restart", "Kill running Unity and restart").option("-q, --quit", "Gracefully quit running Unity").option("-p, --platform <platform>", "Build target (e.g., Android, iOS)").option("--max-depth <n>", "Search depth when project-path is omitted", "3").option("-a, --add-unity-hub", "Add to Unity Hub (does not launch)").option("-f, --favorite", "Add to Unity Hub as favorite (does not launch)").action(async (projectPath, options) => {
8093
+ await runLaunchCommand(projectPath, options);
8094
+ });
8095
+ }
8096
+ function parseMaxDepth(value) {
8097
+ if (value === void 0) {
8098
+ return 3;
8099
+ }
8100
+ const parsed = parseInt(value, 10);
8101
+ if (Number.isNaN(parsed)) {
8102
+ console.error(`Error: Invalid --max-depth value: "${value}". Must be an integer.`);
8103
+ process.exit(1);
8104
+ }
8105
+ return parsed;
8106
+ }
8107
+ async function runLaunchCommand(projectPath, options) {
8108
+ const maxDepth = parseMaxDepth(options.maxDepth);
8109
+ await orchestrateLaunch({
8110
+ projectPath: projectPath ? (0, import_path6.resolve)(projectPath) : void 0,
8111
+ searchRoot: process.cwd(),
8112
+ searchMaxDepth: maxDepth,
8113
+ platform: options.platform,
8114
+ unityArgs: [],
8115
+ restart: options.restart === true,
8116
+ quit: options.quit === true,
8117
+ addUnityHub: options.addUnityHub === true,
8118
+ favoriteUnityHub: options.favorite === true
8119
+ });
8004
8120
  }
8005
8121
 
8006
8122
  // src/commands/focus-window.ts