uloop-cli 1.7.2 → 1.7.3

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.
@@ -5768,6 +5768,13 @@ var UnityNotRunningError = class extends Error {
5768
5768
  }
5769
5769
  projectRoot;
5770
5770
  };
5771
+ var UnityServerNotRunningError = class extends Error {
5772
+ constructor(projectRoot) {
5773
+ super("UNITY_SERVER_NOT_RUNNING");
5774
+ this.projectRoot = projectRoot;
5775
+ }
5776
+ projectRoot;
5777
+ };
5771
5778
  function normalizePort(port) {
5772
5779
  if (typeof port !== "number") {
5773
5780
  return null;
@@ -5847,9 +5854,6 @@ async function readPortFromSettingsOrThrow(projectRoot) {
5847
5854
  continue;
5848
5855
  }
5849
5856
  const settings = parsed;
5850
- if (settings.isServerRunning === false) {
5851
- throw new UnityNotRunningError(projectRoot);
5852
- }
5853
5857
  const port = resolvePortFromUnitySettings(settings);
5854
5858
  if (port !== null) {
5855
5859
  return port;
@@ -5908,7 +5912,7 @@ var import_path4 = require("path");
5908
5912
 
5909
5913
  // src/default-tools.json
5910
5914
  var default_tools_default = {
5911
- version: "1.7.2",
5915
+ version: "1.7.3",
5912
5916
  tools: [
5913
5917
  {
5914
5918
  name: "compile",
@@ -6541,7 +6545,7 @@ function getCachedServerVersion() {
6541
6545
  }
6542
6546
 
6543
6547
  // src/version.ts
6544
- var VERSION = "1.7.2";
6548
+ var VERSION = "1.7.3";
6545
6549
 
6546
6550
  // src/spinner.ts
6547
6551
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
@@ -6575,6 +6579,228 @@ function createSpinner(initialMessage) {
6575
6579
  };
6576
6580
  }
6577
6581
 
6582
+ // src/unity-process.ts
6583
+ var import_node_child_process = require("node:child_process");
6584
+ var import_node_util = require("node:util");
6585
+ var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
6586
+ var WINDOWS_PROCESS_QUERY = `Get-CimInstance Win32_Process -Filter "name = 'Unity.exe'" | Select-Object ProcessId, CommandLine | ConvertTo-Json -Compress`;
6587
+ var defaultDependencies = {
6588
+ platform: process.platform,
6589
+ runCommand: runUnityProcessQuery
6590
+ };
6591
+ function buildUnityProcessCommand(platform) {
6592
+ if (platform === "darwin") {
6593
+ return {
6594
+ command: "ps",
6595
+ args: ["-Ao", "pid=,command="]
6596
+ };
6597
+ }
6598
+ if (platform === "linux") {
6599
+ return {
6600
+ command: "ps",
6601
+ args: ["-eo", "pid=,args="]
6602
+ };
6603
+ }
6604
+ if (platform === "win32") {
6605
+ return {
6606
+ command: "powershell.exe",
6607
+ args: ["-NoProfile", "-NonInteractive", "-Command", WINDOWS_PROCESS_QUERY]
6608
+ };
6609
+ }
6610
+ return null;
6611
+ }
6612
+ function parseUnityProcesses(platform, output) {
6613
+ if (platform === "win32") {
6614
+ return parseWindowsUnityProcesses(output);
6615
+ }
6616
+ return parsePsUnityProcesses(output);
6617
+ }
6618
+ function tokenizeCommandLine(commandLine) {
6619
+ const tokens = [];
6620
+ let current = "";
6621
+ let inQuotes = false;
6622
+ for (let i = 0; i < commandLine.length; i++) {
6623
+ const character = commandLine[i];
6624
+ if (character === '"') {
6625
+ inQuotes = !inQuotes;
6626
+ continue;
6627
+ }
6628
+ if (!inQuotes && /\s/.test(character)) {
6629
+ if (current.length > 0) {
6630
+ tokens.push(current);
6631
+ current = "";
6632
+ }
6633
+ continue;
6634
+ }
6635
+ current += character;
6636
+ }
6637
+ if (current.length > 0) {
6638
+ tokens.push(current);
6639
+ }
6640
+ return tokens;
6641
+ }
6642
+ function extractUnityProjectPath(commandLine) {
6643
+ const tokens = tokenizeCommandLine(commandLine);
6644
+ for (let i = 0; i < tokens.length; i++) {
6645
+ const token = tokens[i].toLowerCase();
6646
+ if (token !== "-projectpath") {
6647
+ continue;
6648
+ }
6649
+ const projectPath = tokens[i + 1];
6650
+ return projectPath ?? null;
6651
+ }
6652
+ return null;
6653
+ }
6654
+ function normalizeUnityProjectPath(projectPath, platform) {
6655
+ const normalizedSeparators = projectPath.replace(/\\/g, "/").replace(/\/+$/, "");
6656
+ if (platform === "win32") {
6657
+ return normalizedSeparators.toLowerCase();
6658
+ }
6659
+ return normalizedSeparators;
6660
+ }
6661
+ function isUnityProcessForProject(commandLine, projectRoot, platform) {
6662
+ if (platform !== "win32") {
6663
+ return commandLineContainsProjectRoot(commandLine, projectRoot, platform);
6664
+ }
6665
+ const extractedProjectPath = extractUnityProjectPath(commandLine);
6666
+ if (extractedProjectPath === null) {
6667
+ return false;
6668
+ }
6669
+ return normalizeUnityProjectPath(extractedProjectPath, platform) === normalizeUnityProjectPath(projectRoot, platform);
6670
+ }
6671
+ function commandLineContainsProjectRoot(commandLine, projectRoot, platform) {
6672
+ const projectPathFlagIndex = commandLine.toLowerCase().indexOf(" -projectpath");
6673
+ if (projectPathFlagIndex === -1) {
6674
+ return false;
6675
+ }
6676
+ const normalizedProjectRoot = normalizeUnityProjectPath(projectRoot, platform);
6677
+ let projectRootIndex = commandLine.indexOf(normalizedProjectRoot, projectPathFlagIndex);
6678
+ while (projectRootIndex !== -1) {
6679
+ const beforeProjectRoot = commandLine[projectRootIndex - 1];
6680
+ const projectPathEndIndex = skipTrailingProjectPathSeparators(
6681
+ commandLine,
6682
+ projectRootIndex + normalizedProjectRoot.length
6683
+ );
6684
+ if (isProjectPathBoundaryCharacter(beforeProjectRoot) && isProjectPathTerminator(commandLine, projectPathEndIndex)) {
6685
+ return true;
6686
+ }
6687
+ projectRootIndex = commandLine.indexOf(normalizedProjectRoot, projectRootIndex + 1);
6688
+ }
6689
+ return false;
6690
+ }
6691
+ function isProjectPathBoundaryCharacter(character) {
6692
+ return character === void 0 || /\s|["']/.test(character);
6693
+ }
6694
+ function skipTrailingProjectPathSeparators(commandLine, startIndex) {
6695
+ let index = startIndex;
6696
+ while (readCharacterAt(commandLine, index) === "/") {
6697
+ index += 1;
6698
+ }
6699
+ return index;
6700
+ }
6701
+ function isProjectPathTerminator(commandLine, projectRootEndIndex) {
6702
+ const character = readCharacterAt(commandLine, projectRootEndIndex);
6703
+ if (character === null) {
6704
+ return true;
6705
+ }
6706
+ if (character === '"' || character === "'") {
6707
+ return true;
6708
+ }
6709
+ if (!/\s/.test(character)) {
6710
+ return false;
6711
+ }
6712
+ for (let i = projectRootEndIndex; i < commandLine.length; i++) {
6713
+ const trailingCharacter = readCharacterAt(commandLine, i);
6714
+ if (trailingCharacter === null) {
6715
+ return true;
6716
+ }
6717
+ if (/\s/.test(trailingCharacter)) {
6718
+ continue;
6719
+ }
6720
+ return trailingCharacter === "-";
6721
+ }
6722
+ return true;
6723
+ }
6724
+ function readCharacterAt(value, index) {
6725
+ const character = value.slice(index, index + 1);
6726
+ if (character.length === 0) {
6727
+ return null;
6728
+ }
6729
+ return character;
6730
+ }
6731
+ function isUnityEditorProcess(commandLine, platform) {
6732
+ const lowerCommandLine = commandLine.toLowerCase();
6733
+ if (lowerCommandLine.length === 0) {
6734
+ return false;
6735
+ }
6736
+ const projectPathFlagIndex = lowerCommandLine.indexOf(" -projectpath");
6737
+ const executableSection = projectPathFlagIndex === -1 ? lowerCommandLine : lowerCommandLine.slice(0, projectPathFlagIndex);
6738
+ if (platform === "win32") {
6739
+ return executableSection.includes("unity.exe");
6740
+ }
6741
+ if (platform === "darwin") {
6742
+ return executableSection.includes("/unity.app/contents/macos/unity");
6743
+ }
6744
+ if (platform === "linux") {
6745
+ return executableSection.endsWith("/unity") || executableSection.endsWith("/unity-editor") || executableSection.includes("/editor/unity");
6746
+ }
6747
+ return false;
6748
+ }
6749
+ async function findRunningUnityProcessForProject(projectRoot, dependencies = defaultDependencies) {
6750
+ const unityProcessCommand = buildUnityProcessCommand(dependencies.platform);
6751
+ if (unityProcessCommand === null) {
6752
+ return null;
6753
+ }
6754
+ const output = await dependencies.runCommand(
6755
+ unityProcessCommand.command,
6756
+ unityProcessCommand.args
6757
+ );
6758
+ const runningProcesses = parseUnityProcesses(dependencies.platform, output);
6759
+ const matchingProcess = runningProcesses.find(
6760
+ (processInfo) => isUnityEditorProcess(processInfo.commandLine, dependencies.platform) && isUnityProcessForProject(processInfo.commandLine, projectRoot, dependencies.platform)
6761
+ );
6762
+ if (matchingProcess === void 0) {
6763
+ return null;
6764
+ }
6765
+ return {
6766
+ pid: matchingProcess.pid
6767
+ };
6768
+ }
6769
+ async function runUnityProcessQuery(command, args) {
6770
+ const { stdout } = await execFileAsync(command, args, {
6771
+ encoding: "utf8",
6772
+ maxBuffer: 1024 * 1024
6773
+ });
6774
+ return stdout;
6775
+ }
6776
+ function parsePsUnityProcesses(output) {
6777
+ return output.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0).map((line) => {
6778
+ const match = line.match(/^(\d+)\s+(.+)$/);
6779
+ if (match === null) {
6780
+ return null;
6781
+ }
6782
+ return {
6783
+ pid: Number.parseInt(match[1], 10),
6784
+ commandLine: match[2]
6785
+ };
6786
+ }).filter((processInfo) => processInfo !== null);
6787
+ }
6788
+ function parseWindowsUnityProcesses(output) {
6789
+ const trimmed = output.trim();
6790
+ if (trimmed.length === 0) {
6791
+ return [];
6792
+ }
6793
+ const parsed = JSON.parse(trimmed);
6794
+ const processArray = Array.isArray(parsed) ? parsed : [parsed];
6795
+ return processArray.filter(isWindowsUnityProcessWithCommandLine).map((processInfo) => ({
6796
+ pid: processInfo.ProcessId,
6797
+ commandLine: processInfo.CommandLine
6798
+ }));
6799
+ }
6800
+ function isWindowsUnityProcessWithCommandLine(processInfo) {
6801
+ return typeof processInfo.ProcessId === "number" && typeof processInfo.CommandLine === "string";
6802
+ }
6803
+
6578
6804
  // src/compile-helpers.ts
6579
6805
  var import_node_assert2 = __toESM(require("node:assert"), 1);
6580
6806
  var import_fs4 = require("fs");
@@ -6810,6 +7036,9 @@ var RETRY_DELAY_MS = 500;
6810
7036
  var MAX_RETRIES = 3;
6811
7037
  var COMPILE_WAIT_TIMEOUT_MS = 9e4;
6812
7038
  var COMPILE_WAIT_POLL_INTERVAL_MS = 100;
7039
+ var defaultConnectionFailureDiagnosisDependencies = {
7040
+ findRunningUnityProcessForProjectFn: findRunningUnityProcessForProject
7041
+ };
6813
7042
  function getCompileExecutionOptions(toolName, params) {
6814
7043
  if (toolName !== "compile") {
6815
7044
  return {
@@ -6826,6 +7055,34 @@ function isRetryableError(error) {
6826
7055
  const message = error.message;
6827
7056
  return message.includes("ECONNREFUSED") || message.includes("EADDRNOTAVAIL") || message === "UNITY_NO_RESPONSE";
6828
7057
  }
7058
+ async function diagnoseRetryableProjectConnectionError(error, projectRoot, shouldDiagnoseProjectState, dependencies = defaultConnectionFailureDiagnosisDependencies) {
7059
+ if (!shouldDiagnoseProjectState || projectRoot === null || !isRetryableError(error)) {
7060
+ return error;
7061
+ }
7062
+ const runningProcess = await dependencies.findRunningUnityProcessForProjectFn(projectRoot).catch(() => void 0);
7063
+ if (runningProcess === void 0) {
7064
+ return error;
7065
+ }
7066
+ if (runningProcess === null) {
7067
+ return new UnityNotRunningError(projectRoot);
7068
+ }
7069
+ return new UnityServerNotRunningError(projectRoot);
7070
+ }
7071
+ async function throwFinalToolError(error, projectRoot, shouldDiagnoseProjectState) {
7072
+ const diagnosedError = await diagnoseRetryableProjectConnectionError(
7073
+ error,
7074
+ projectRoot,
7075
+ shouldDiagnoseProjectState
7076
+ );
7077
+ if (diagnosedError instanceof Error) {
7078
+ throw diagnosedError;
7079
+ }
7080
+ if (typeof diagnosedError === "string") {
7081
+ throw new Error(diagnosedError);
7082
+ }
7083
+ const serializedError = JSON.stringify(diagnosedError);
7084
+ throw new Error(serializedError ?? "Unknown error");
7085
+ }
6829
7086
  function isTransportDisconnectError(error) {
6830
7087
  if (!(error instanceof Error)) {
6831
7088
  return false;
@@ -6952,8 +7209,8 @@ async function executeToolCommand(toolName, params, globalOptions) {
6952
7209
  if (immediateResult === void 0 && !requestDispatched) {
6953
7210
  spinner.stop();
6954
7211
  restoreStdin();
6955
- if (lastError instanceof Error) {
6956
- throw lastError;
7212
+ if (lastError !== void 0) {
7213
+ await throwFinalToolError(lastError, projectRoot, shouldValidateProject);
6957
7214
  }
6958
7215
  throw new Error(
6959
7216
  "Compile request never reached Unity. Check that Unity is running and retry."
@@ -7004,14 +7261,7 @@ async function executeToolCommand(toolName, params, globalOptions) {
7004
7261
  if (lastError === void 0) {
7005
7262
  throw new Error("Tool execution failed without error details.");
7006
7263
  }
7007
- if (lastError instanceof Error) {
7008
- throw lastError;
7009
- }
7010
- if (typeof lastError === "string") {
7011
- throw new Error(lastError);
7012
- }
7013
- const serializedError = JSON.stringify(lastError);
7014
- throw new Error(serializedError ?? "Unknown error");
7264
+ await throwFinalToolError(lastError, projectRoot, shouldValidateProject);
7015
7265
  }
7016
7266
  async function listAvailableTools(globalOptions) {
7017
7267
  let portNumber;
@@ -7062,7 +7312,7 @@ async function listAvailableTools(globalOptions) {
7062
7312
  }
7063
7313
  spinner.stop();
7064
7314
  restoreStdin();
7065
- throw lastError;
7315
+ await throwFinalToolError(lastError, projectRoot, shouldValidateProject);
7066
7316
  }
7067
7317
  function convertProperties(unityProps) {
7068
7318
  const result = {};
@@ -7143,7 +7393,7 @@ async function syncTools(globalOptions) {
7143
7393
  }
7144
7394
  spinner.stop();
7145
7395
  restoreStdin();
7146
- throw lastError;
7396
+ await throwFinalToolError(lastError, projectRoot, shouldValidateProject);
7147
7397
  }
7148
7398
 
7149
7399
  // src/arg-parser.ts
@@ -8023,11 +8273,11 @@ Uninstalling uloop skills (${location})...`);
8023
8273
  var import_path9 = require("path");
8024
8274
 
8025
8275
  // node_modules/launch-unity/dist/lib.js
8026
- var import_node_child_process = require("node:child_process");
8276
+ var import_node_child_process2 = require("node:child_process");
8027
8277
  var import_node_fs2 = require("node:fs");
8028
8278
  var import_promises4 = require("node:fs/promises");
8029
8279
  var import_node_path2 = require("node:path");
8030
- var import_node_util = require("node:util");
8280
+ var import_node_util2 = require("node:util");
8031
8281
 
8032
8282
  // node_modules/launch-unity/dist/unityHub.js
8033
8283
  var import_promises3 = require("node:fs/promises");
@@ -8299,7 +8549,7 @@ var getProjectCliArgs = async (projectPath) => {
8299
8549
  };
8300
8550
 
8301
8551
  // node_modules/launch-unity/dist/lib.js
8302
- var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
8552
+ var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
8303
8553
  var UNITY_EXECUTABLE_PATTERN_MAC = /Unity\.app\/Contents\/MacOS\/Unity/i;
8304
8554
  var UNITY_EXECUTABLE_PATTERN_WINDOWS = /Unity\.exe/i;
8305
8555
  var PROJECT_PATH_PATTERN = /-(?:projectPath|projectpath)(?:=|\s+)("[^"]+"|'[^']+'|.+?)(?=\s+-[a-zA-Z]|$)/i;
@@ -8399,7 +8649,7 @@ var isUnityAuxiliaryProcess = (command) => {
8399
8649
  async function listUnityProcessesMac() {
8400
8650
  let stdout = "";
8401
8651
  try {
8402
- const result = await execFileAsync(PROCESS_LIST_COMMAND_MAC, PROCESS_LIST_ARGS_MAC);
8652
+ const result = await execFileAsync2(PROCESS_LIST_COMMAND_MAC, PROCESS_LIST_ARGS_MAC);
8403
8653
  stdout = result.stdout;
8404
8654
  } catch (error) {
8405
8655
  const message = error instanceof Error ? error.message : String(error);
@@ -8446,7 +8696,7 @@ async function listUnityProcessesWindows() {
8446
8696
  ];
8447
8697
  let stdout = "";
8448
8698
  try {
8449
- const result = await execFileAsync(WINDOWS_POWERSHELL, ["-NoProfile", "-Command", scriptLines.join("\n")]);
8699
+ const result = await execFileAsync2(WINDOWS_POWERSHELL, ["-NoProfile", "-Command", scriptLines.join("\n")]);
8450
8700
  stdout = result.stdout ?? "";
8451
8701
  } catch (error) {
8452
8702
  const message = error instanceof Error ? error.message : String(error);
@@ -8509,7 +8759,7 @@ async function focusUnityProcess(pid) {
8509
8759
  async function focusUnityProcessMac(pid) {
8510
8760
  const script = `tell application "System Events" to set frontmost of (first process whose unix id is ${pid}) to true`;
8511
8761
  try {
8512
- await execFileAsync("osascript", ["-e", script]);
8762
+ await execFileAsync2("osascript", ["-e", script]);
8513
8763
  console.log("Brought existing Unity to the front.");
8514
8764
  } catch (error) {
8515
8765
  const message = error instanceof Error ? error.message : String(error);
@@ -8537,7 +8787,7 @@ async function focusUnityProcessWindows(pid) {
8537
8787
  "[Win32Interop]::SetForegroundWindow($handle) | Out-Null"
8538
8788
  ];
8539
8789
  try {
8540
- await execFileAsync(WINDOWS_POWERSHELL, ["-NoProfile", "-Command", scriptLines.join("\n")]);
8790
+ await execFileAsync2(WINDOWS_POWERSHELL, ["-NoProfile", "-Command", scriptLines.join("\n")]);
8541
8791
  console.log("Brought existing Unity to the front.");
8542
8792
  } catch (error) {
8543
8793
  const message = error instanceof Error ? error.message : String(error);
@@ -8546,7 +8796,7 @@ async function focusUnityProcessWindows(pid) {
8546
8796
  }
8547
8797
  async function isLockfileHeldMac(lockfilePath) {
8548
8798
  try {
8549
- const result = await execFileAsync("lsof", [lockfilePath]);
8799
+ const result = await execFileAsync2("lsof", [lockfilePath]);
8550
8800
  const lines = result.stdout.split("\n").filter((line) => line.length > 0);
8551
8801
  return lines.length > 1;
8552
8802
  } catch {
@@ -8567,7 +8817,7 @@ async function isLockfileHeldWindows(lockfilePath) {
8567
8817
  "}"
8568
8818
  ];
8569
8819
  try {
8570
- const result = await execFileAsync(WINDOWS_POWERSHELL, ["-NoProfile", "-Command", scriptLines.join("\n")]);
8820
+ const result = await execFileAsync2(WINDOWS_POWERSHELL, ["-NoProfile", "-Command", scriptLines.join("\n")]);
8571
8821
  return result.stdout.trim() === "LOCKED";
8572
8822
  } catch {
8573
8823
  return false;
@@ -8677,7 +8927,7 @@ async function sendGracefulQuitMac(pid) {
8677
8927
  "end tell"
8678
8928
  ].join("\n");
8679
8929
  try {
8680
- await execFileAsync("osascript", ["-e", script]);
8930
+ await execFileAsync2("osascript", ["-e", script]);
8681
8931
  } catch {
8682
8932
  }
8683
8933
  }
@@ -8687,7 +8937,7 @@ async function sendGracefulQuitWindows(pid) {
8687
8937
  `try { $proc = Get-Process -Id ${pid} -ErrorAction Stop; $proc.CloseMainWindow() | Out-Null } catch { }`
8688
8938
  ];
8689
8939
  try {
8690
- await execFileAsync(WINDOWS_POWERSHELL, ["-NoProfile", "-Command", scriptLines.join("\n")]);
8940
+ await execFileAsync2(WINDOWS_POWERSHELL, ["-NoProfile", "-Command", scriptLines.join("\n")]);
8691
8941
  } catch {
8692
8942
  }
8693
8943
  }
@@ -8849,7 +9099,7 @@ async function launch(opts) {
8849
9099
  args.push(...unityArgs);
8850
9100
  }
8851
9101
  return new Promise((resolve7, reject) => {
8852
- const child = (0, import_node_child_process.spawn)(unityPath, args, {
9102
+ const child = (0, import_node_child_process2.spawn)(unityPath, args, {
8853
9103
  stdio: "ignore",
8854
9104
  detached: true,
8855
9105
  // Git Bash (MSYS) がWindows パスをUnix 形式に自動変換するのを防ぐ
@@ -9036,6 +9286,15 @@ function registerFocusWindowCommand(program3, helpGroup) {
9036
9286
 
9037
9287
  // src/cli-project-error.ts
9038
9288
  function getProjectResolutionErrorLines(error) {
9289
+ if (error instanceof UnityServerNotRunningError) {
9290
+ return [
9291
+ "Error: Unity Editor is running, but Unity CLI Loop server is not.",
9292
+ "",
9293
+ ` Project: ${error.projectRoot}`,
9294
+ "",
9295
+ "Start the server from: Window > Unity CLI Loop > Server"
9296
+ ];
9297
+ }
9039
9298
  if (error instanceof UnityNotRunningError) {
9040
9299
  return [
9041
9300
  "Error: Unity Editor for this project is not running.",
@@ -9316,7 +9575,7 @@ async function runWithErrorHandling(fn) {
9316
9575
  try {
9317
9576
  await fn();
9318
9577
  } catch (error) {
9319
- if (error instanceof UnityNotRunningError) {
9578
+ if (error instanceof UnityNotRunningError || error instanceof UnityServerNotRunningError) {
9320
9579
  for (const line of getProjectResolutionErrorLines(error)) {
9321
9580
  console.error(line.startsWith("Error: ") ? `\x1B[31m${line}\x1B[0m` : line);
9322
9581
  }