uloop-cli 0.68.2 → 0.69.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.
@@ -795,7 +795,7 @@ ${itemIndentStr}`);
795
795
  var require_option = __commonJS({
796
796
  "node_modules/commander/lib/option.js"(exports2) {
797
797
  var { InvalidArgumentError: InvalidArgumentError2 } = require_error();
798
- var Option2 = class {
798
+ var Option3 = class {
799
799
  /**
800
800
  * Initialize a new `Option` with the given `flags` and `description`.
801
801
  *
@@ -1099,7 +1099,7 @@ var require_option = __commonJS({
1099
1099
  );
1100
1100
  return { shortFlag, longFlag };
1101
1101
  }
1102
- exports2.Option = Option2;
1102
+ exports2.Option = Option3;
1103
1103
  exports2.DualOptions = DualOptions;
1104
1104
  }
1105
1105
  });
@@ -1195,7 +1195,7 @@ var require_command = __commonJS({
1195
1195
  var { Argument: Argument2, humanReadableArgName } = require_argument();
1196
1196
  var { CommanderError: CommanderError2 } = require_error();
1197
1197
  var { Help: Help2, stripColor } = require_help();
1198
- var { Option: Option2, DualOptions } = require_option();
1198
+ var { Option: Option3, DualOptions } = require_option();
1199
1199
  var { suggestSimilar } = require_suggestSimilar();
1200
1200
  var Command2 = class _Command extends EventEmitter {
1201
1201
  /**
@@ -1680,7 +1680,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1680
1680
  * @return {Option} new option
1681
1681
  */
1682
1682
  createOption(flags, description) {
1683
- return new Option2(flags, description);
1683
+ return new Option3(flags, description);
1684
1684
  }
1685
1685
  /**
1686
1686
  * Wrap parseArgs to catch 'commander.invalidArgument'.
@@ -1805,7 +1805,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1805
1805
  * @private
1806
1806
  */
1807
1807
  _optionEx(config, flags, description, fn, defaultValue) {
1808
- if (typeof flags === "object" && flags instanceof Option2) {
1808
+ if (typeof flags === "object" && flags instanceof Option3) {
1809
1809
  throw new Error(
1810
1810
  "To add an Option object use addOption() instead of option() or requiredOption()"
1811
1811
  );
@@ -3437,13 +3437,13 @@ var require_commander = __commonJS({
3437
3437
  var { Command: Command2 } = require_command();
3438
3438
  var { CommanderError: CommanderError2, InvalidArgumentError: InvalidArgumentError2 } = require_error();
3439
3439
  var { Help: Help2 } = require_help();
3440
- var { Option: Option2 } = require_option();
3440
+ var { Option: Option3 } = require_option();
3441
3441
  exports2.program = new Command2();
3442
3442
  exports2.createCommand = (name) => new Command2(name);
3443
- exports2.createOption = (flags, description) => new Option2(flags, description);
3443
+ exports2.createOption = (flags, description) => new Option3(flags, description);
3444
3444
  exports2.createArgument = (name, description) => new Argument2(name, description);
3445
3445
  exports2.Command = Command2;
3446
- exports2.Option = Option2;
3446
+ exports2.Option = Option3;
3447
3447
  exports2.Argument = Argument2;
3448
3448
  exports2.Help = Help2;
3449
3449
  exports2.CommanderError = CommanderError2;
@@ -5384,7 +5384,7 @@ var require_semver2 = __commonJS({
5384
5384
 
5385
5385
  // src/cli.ts
5386
5386
  var import_fs8 = require("fs");
5387
- var import_path9 = require("path");
5387
+ var import_path10 = require("path");
5388
5388
  var import_os2 = require("os");
5389
5389
  var import_child_process = require("child_process");
5390
5390
 
@@ -5408,7 +5408,7 @@ var {
5408
5408
  // src/execute-tool.ts
5409
5409
  var readline = __toESM(require("readline"), 1);
5410
5410
  var import_fs5 = require("fs");
5411
- var import_path5 = require("path");
5411
+ var import_path6 = require("path");
5412
5412
  var semver = __toESM(require_semver2(), 1);
5413
5413
 
5414
5414
  // src/direct-unity-client.ts
@@ -5736,7 +5736,12 @@ function findUnityProjectInParentsWithoutUloop(startPath) {
5736
5736
  }
5737
5737
 
5738
5738
  // src/port-resolver.ts
5739
- var DEFAULT_PORT = 8700;
5739
+ var UnityNotRunningError = class extends Error {
5740
+ constructor(projectRoot) {
5741
+ super("UNITY_NOT_RUNNING");
5742
+ this.projectRoot = projectRoot;
5743
+ }
5744
+ };
5740
5745
  function normalizePort(port) {
5741
5746
  if (typeof port !== "number") {
5742
5747
  return null;
@@ -5780,11 +5785,7 @@ async function resolveUnityPort(explicitPort, projectPath) {
5780
5785
  }
5781
5786
  if (projectPath !== void 0) {
5782
5787
  const resolved = validateProjectPath(projectPath);
5783
- const settingsPort2 = await readPortFromSettings(resolved);
5784
- if (settingsPort2 !== null) {
5785
- return settingsPort2;
5786
- }
5787
- return DEFAULT_PORT;
5788
+ return await readPortFromSettingsOrThrow(resolved);
5788
5789
  }
5789
5790
  const projectRoot = findUnityProjectRoot();
5790
5791
  if (projectRoot === null) {
@@ -5792,39 +5793,98 @@ async function resolveUnityPort(explicitPort, projectPath) {
5792
5793
  "Unity project not found. Use --port or --project-path option to specify the target."
5793
5794
  );
5794
5795
  }
5795
- const settingsPort = await readPortFromSettings(projectRoot);
5796
- if (settingsPort !== null) {
5797
- return settingsPort;
5798
- }
5799
- return DEFAULT_PORT;
5796
+ return await readPortFromSettingsOrThrow(projectRoot);
5800
5797
  }
5801
- async function readPortFromSettings(projectRoot) {
5798
+ function createSettingsReadError(projectRoot) {
5799
+ const settingsPath = (0, import_path2.join)(projectRoot, "UserSettings/UnityMcpSettings.json");
5800
+ return new Error(
5801
+ `Could not read Unity server port from settings.
5802
+
5803
+ Settings file: ${settingsPath}
5804
+
5805
+ Run 'uloop launch -r' to restart Unity, or use --port to specify the port directly.`
5806
+ );
5807
+ }
5808
+ async function readPortFromSettingsOrThrow(projectRoot) {
5802
5809
  const settingsPath = (0, import_path2.join)(projectRoot, "UserSettings/UnityMcpSettings.json");
5803
5810
  if (!(0, import_fs2.existsSync)(settingsPath)) {
5804
- return null;
5811
+ throw createSettingsReadError(projectRoot);
5805
5812
  }
5806
5813
  let content;
5807
5814
  try {
5808
5815
  content = await (0, import_promises.readFile)(settingsPath, "utf-8");
5809
5816
  } catch {
5810
- return null;
5817
+ throw createSettingsReadError(projectRoot);
5811
5818
  }
5812
- let settings;
5819
+ let parsed;
5813
5820
  try {
5814
- settings = JSON.parse(content);
5821
+ parsed = JSON.parse(content);
5815
5822
  } catch {
5816
- return null;
5823
+ throw createSettingsReadError(projectRoot);
5824
+ }
5825
+ if (typeof parsed !== "object" || parsed === null) {
5826
+ throw createSettingsReadError(projectRoot);
5827
+ }
5828
+ const settings = parsed;
5829
+ if (settings.isServerRunning === false) {
5830
+ throw new UnityNotRunningError(projectRoot);
5831
+ }
5832
+ const port = resolvePortFromUnitySettings(settings);
5833
+ if (port === null) {
5834
+ throw createSettingsReadError(projectRoot);
5835
+ }
5836
+ return port;
5837
+ }
5838
+
5839
+ // src/project-validator.ts
5840
+ var import_node_assert = __toESM(require("node:assert"), 1);
5841
+ var import_promises2 = require("fs/promises");
5842
+ var import_path3 = require("path");
5843
+ var ProjectMismatchError = class extends Error {
5844
+ constructor(expectedProjectRoot, connectedProjectRoot) {
5845
+ super("PROJECT_MISMATCH");
5846
+ this.expectedProjectRoot = expectedProjectRoot;
5847
+ this.connectedProjectRoot = connectedProjectRoot;
5848
+ }
5849
+ };
5850
+ var JSON_RPC_METHOD_NOT_FOUND = -32601;
5851
+ async function normalizePath(path) {
5852
+ const resolved = await (0, import_promises2.realpath)(path);
5853
+ return resolved.replace(/\/+$/, "");
5854
+ }
5855
+ async function validateConnectedProject(client, expectedProjectRoot) {
5856
+ (0, import_node_assert.default)(client.isConnected(), "client must be connected before validation");
5857
+ let response;
5858
+ try {
5859
+ response = await client.sendRequest("get-version", {});
5860
+ } catch (error) {
5861
+ if (error instanceof Error && (error.message.includes(`${JSON_RPC_METHOD_NOT_FOUND}`) || /method not found/i.test(error.message))) {
5862
+ console.error(
5863
+ "Warning: Could not verify project identity (get-version not available). Consider updating uLoopMCP package."
5864
+ );
5865
+ return;
5866
+ }
5867
+ throw error;
5868
+ }
5869
+ if (typeof response?.DataPath !== "string" || response.DataPath.length === 0) {
5870
+ console.error("Warning: Could not verify project identity (invalid get-version response).");
5871
+ return;
5872
+ }
5873
+ const connectedProjectRoot = (0, import_path3.dirname)(response.DataPath);
5874
+ const normalizedExpected = await normalizePath(expectedProjectRoot);
5875
+ const normalizedConnected = await normalizePath(connectedProjectRoot);
5876
+ if (normalizedExpected !== normalizedConnected) {
5877
+ throw new ProjectMismatchError(normalizedExpected, normalizedConnected);
5817
5878
  }
5818
- return resolvePortFromUnitySettings(settings);
5819
5879
  }
5820
5880
 
5821
5881
  // src/tool-cache.ts
5822
5882
  var import_fs3 = require("fs");
5823
- var import_path3 = require("path");
5883
+ var import_path4 = require("path");
5824
5884
 
5825
5885
  // src/default-tools.json
5826
5886
  var default_tools_default = {
5827
- version: "0.68.2",
5887
+ version: "0.69.0",
5828
5888
  tools: [
5829
5889
  {
5830
5890
  name: "compile",
@@ -6064,6 +6124,34 @@ var default_tools_default = {
6064
6124
  }
6065
6125
  }
6066
6126
  },
6127
+ {
6128
+ name: "get-unity-search-providers",
6129
+ description: "Get detailed information about Unity Search providers including display names, descriptions, active status, and capabilities",
6130
+ inputSchema: {
6131
+ type: "object",
6132
+ properties: {
6133
+ ProviderId: {
6134
+ type: "string",
6135
+ description: "Specific provider ID to get details for (empty = all providers). Examples: 'asset', 'scene', 'menu', 'settings'"
6136
+ },
6137
+ ActiveOnly: {
6138
+ type: "boolean",
6139
+ description: "Whether to include only active providers",
6140
+ default: false
6141
+ },
6142
+ SortByPriority: {
6143
+ type: "boolean",
6144
+ description: "Sort providers by priority (lower number = higher priority)",
6145
+ default: true
6146
+ },
6147
+ IncludeDescriptions: {
6148
+ type: "boolean",
6149
+ description: "Include detailed descriptions for each provider",
6150
+ default: true
6151
+ }
6152
+ }
6153
+ }
6154
+ },
6067
6155
  {
6068
6156
  name: "get-menu-items",
6069
6157
  description: "Retrieve Unity MenuItems",
@@ -6263,21 +6351,24 @@ var default_tools_default = {
6263
6351
  // src/tool-cache.ts
6264
6352
  var CACHE_DIR = ".uloop";
6265
6353
  var CACHE_FILE = "tools.json";
6266
- function getCacheDir() {
6354
+ function getCacheDir(projectPath) {
6355
+ if (projectPath !== void 0) {
6356
+ return (0, import_path4.join)(projectPath, CACHE_DIR);
6357
+ }
6267
6358
  const projectRoot = findUnityProjectRoot();
6268
6359
  if (projectRoot === null) {
6269
- return (0, import_path3.join)(process.cwd(), CACHE_DIR);
6360
+ return (0, import_path4.join)(process.cwd(), CACHE_DIR);
6270
6361
  }
6271
- return (0, import_path3.join)(projectRoot, CACHE_DIR);
6362
+ return (0, import_path4.join)(projectRoot, CACHE_DIR);
6272
6363
  }
6273
- function getCachePath() {
6274
- return (0, import_path3.join)(getCacheDir(), CACHE_FILE);
6364
+ function getCachePath(projectPath) {
6365
+ return (0, import_path4.join)(getCacheDir(projectPath), CACHE_FILE);
6275
6366
  }
6276
6367
  function getDefaultTools() {
6277
6368
  return default_tools_default;
6278
6369
  }
6279
- function loadToolsCache() {
6280
- const cachePath = getCachePath();
6370
+ function loadToolsCache(projectPath) {
6371
+ const cachePath = getCachePath(projectPath);
6281
6372
  if ((0, import_fs3.existsSync)(cachePath)) {
6282
6373
  try {
6283
6374
  const content = (0, import_fs3.readFileSync)(cachePath, "utf-8");
@@ -6303,6 +6394,10 @@ function hasCacheFile() {
6303
6394
  function getCacheFilePath() {
6304
6395
  return getCachePath();
6305
6396
  }
6397
+ function getDefaultToolNames() {
6398
+ const defaultTools = getDefaultTools();
6399
+ return new Set(defaultTools.tools.map((tool) => tool.name));
6400
+ }
6306
6401
  function getCachedServerVersion() {
6307
6402
  const cachePath = getCachePath();
6308
6403
  if (!(0, import_fs3.existsSync)(cachePath)) {
@@ -6318,7 +6413,7 @@ function getCachedServerVersion() {
6318
6413
  }
6319
6414
 
6320
6415
  // src/version.ts
6321
- var VERSION = "0.68.2";
6416
+ var VERSION = "0.69.0";
6322
6417
 
6323
6418
  // src/spinner.ts
6324
6419
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
@@ -6353,10 +6448,10 @@ function createSpinner(initialMessage) {
6353
6448
  }
6354
6449
 
6355
6450
  // src/compile-helpers.ts
6356
- var import_node_assert = __toESM(require("node:assert"), 1);
6451
+ var import_node_assert2 = __toESM(require("node:assert"), 1);
6357
6452
  var import_fs4 = require("fs");
6358
6453
  var net2 = __toESM(require("net"), 1);
6359
- var import_path4 = require("path");
6454
+ var import_path5 = require("path");
6360
6455
  var SAFE_REQUEST_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
6361
6456
  var COMPILE_FORCE_RECOMPILE_ARG_KEYS = [
6362
6457
  "ForceRecompile",
@@ -6416,22 +6511,22 @@ function ensureCompileRequestId(args) {
6416
6511
  return requestId;
6417
6512
  }
6418
6513
  function getCompileResultFilePath(projectRoot, requestId) {
6419
- (0, import_node_assert.default)(
6514
+ (0, import_node_assert2.default)(
6420
6515
  SAFE_REQUEST_ID_PATTERN.test(requestId),
6421
6516
  `requestId contains unsafe characters: '${requestId}'`
6422
6517
  );
6423
- return (0, import_path4.join)(projectRoot, "Temp", "uLoopMCP", "compile-results", `${requestId}.json`);
6518
+ return (0, import_path5.join)(projectRoot, "Temp", "uLoopMCP", "compile-results", `${requestId}.json`);
6424
6519
  }
6425
6520
  function isUnityBusyByLockFiles(projectRoot) {
6426
- const compilingLockPath = (0, import_path4.join)(projectRoot, "Temp", "compiling.lock");
6521
+ const compilingLockPath = (0, import_path5.join)(projectRoot, "Temp", "compiling.lock");
6427
6522
  if ((0, import_fs4.existsSync)(compilingLockPath)) {
6428
6523
  return true;
6429
6524
  }
6430
- const domainReloadLockPath = (0, import_path4.join)(projectRoot, "Temp", "domainreload.lock");
6525
+ const domainReloadLockPath = (0, import_path5.join)(projectRoot, "Temp", "domainreload.lock");
6431
6526
  if ((0, import_fs4.existsSync)(domainReloadLockPath)) {
6432
6527
  return true;
6433
6528
  }
6434
- const serverStartingLockPath = (0, import_path4.join)(projectRoot, "Temp", "serverstarting.lock");
6529
+ const serverStartingLockPath = (0, import_path5.join)(projectRoot, "Temp", "serverstarting.lock");
6435
6530
  return (0, import_fs4.existsSync)(serverStartingLockPath);
6436
6531
  }
6437
6532
  function stripUtf8Bom(content) {
@@ -6641,15 +6736,15 @@ function checkUnityBusyState(projectPath) {
6641
6736
  if (projectRoot === null) {
6642
6737
  return;
6643
6738
  }
6644
- const compilingLock = (0, import_path5.join)(projectRoot, "Temp", "compiling.lock");
6739
+ const compilingLock = (0, import_path6.join)(projectRoot, "Temp", "compiling.lock");
6645
6740
  if ((0, import_fs5.existsSync)(compilingLock)) {
6646
6741
  throw new Error("UNITY_COMPILING");
6647
6742
  }
6648
- const domainReloadLock = (0, import_path5.join)(projectRoot, "Temp", "domainreload.lock");
6743
+ const domainReloadLock = (0, import_path6.join)(projectRoot, "Temp", "domainreload.lock");
6649
6744
  if ((0, import_fs5.existsSync)(domainReloadLock)) {
6650
6745
  throw new Error("UNITY_DOMAIN_RELOAD");
6651
6746
  }
6652
- const serverStartingLock = (0, import_path5.join)(projectRoot, "Temp", "serverstarting.lock");
6747
+ const serverStartingLock = (0, import_path6.join)(projectRoot, "Temp", "serverstarting.lock");
6653
6748
  if ((0, import_fs5.existsSync)(serverStartingLock)) {
6654
6749
  throw new Error("UNITY_SERVER_STARTING");
6655
6750
  }
@@ -6672,12 +6767,16 @@ async function executeToolCommand(toolName, params, globalOptions) {
6672
6767
  let lastError;
6673
6768
  let immediateResult;
6674
6769
  const projectRoot = globalOptions.projectPath !== void 0 ? validateProjectPath(globalOptions.projectPath) : findUnityProjectRoot();
6770
+ const shouldValidateProject = portNumber === void 0 && projectRoot !== null;
6675
6771
  let requestDispatched = false;
6676
6772
  for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
6677
6773
  checkUnityBusyState(globalOptions.projectPath);
6678
6774
  const client = new DirectUnityClient(port);
6679
6775
  try {
6680
6776
  await client.connect();
6777
+ if (shouldValidateProject) {
6778
+ await validateConnectedProject(client, projectRoot);
6779
+ }
6681
6780
  spinner.update(`Executing ${toolName}...`);
6682
6781
  requestDispatched = true;
6683
6782
  const result = await client.sendRequest(toolName, params);
@@ -6789,6 +6888,8 @@ async function listAvailableTools(globalOptions) {
6789
6888
  portNumber = parsed;
6790
6889
  }
6791
6890
  const port = await resolveUnityPort(portNumber, globalOptions.projectPath);
6891
+ const projectRoot = globalOptions.projectPath !== void 0 ? validateProjectPath(globalOptions.projectPath) : findUnityProjectRoot();
6892
+ const shouldValidateProject = portNumber === void 0 && projectRoot !== null;
6792
6893
  const restoreStdin = suppressStdinEcho();
6793
6894
  const spinner = createSpinner("Connecting to Unity...");
6794
6895
  let lastError;
@@ -6797,6 +6898,9 @@ async function listAvailableTools(globalOptions) {
6797
6898
  const client = new DirectUnityClient(port);
6798
6899
  try {
6799
6900
  await client.connect();
6901
+ if (shouldValidateProject) {
6902
+ await validateConnectedProject(client, projectRoot);
6903
+ }
6800
6904
  spinner.update("Fetching tool list...");
6801
6905
  const result = await client.sendRequest("get-tool-details", { IncludeDevelopmentOnly: false });
6802
6906
  if (!result.Tools || !Array.isArray(result.Tools)) {
@@ -6846,6 +6950,8 @@ async function syncTools(globalOptions) {
6846
6950
  portNumber = parsed;
6847
6951
  }
6848
6952
  const port = await resolveUnityPort(portNumber, globalOptions.projectPath);
6953
+ const projectRoot = globalOptions.projectPath !== void 0 ? validateProjectPath(globalOptions.projectPath) : findUnityProjectRoot();
6954
+ const shouldValidateProject = portNumber === void 0 && projectRoot !== null;
6849
6955
  const restoreStdin = suppressStdinEcho();
6850
6956
  const spinner = createSpinner("Connecting to Unity...");
6851
6957
  let lastError;
@@ -6854,6 +6960,9 @@ async function syncTools(globalOptions) {
6854
6960
  const client = new DirectUnityClient(port);
6855
6961
  try {
6856
6962
  await client.connect();
6963
+ if (shouldValidateProject) {
6964
+ await validateConnectedProject(client, projectRoot);
6965
+ }
6857
6966
  spinner.update("Syncing tools...");
6858
6967
  const result = await client.sendRequest("get-tool-details", { IncludeDevelopmentOnly: false });
6859
6968
  spinner.stop();
@@ -6908,7 +7017,7 @@ function pascalToKebabCase(pascal) {
6908
7017
 
6909
7018
  // src/skills/skills-manager.ts
6910
7019
  var import_fs7 = require("fs");
6911
- var import_path7 = require("path");
7020
+ var import_path8 = require("path");
6912
7021
  var import_os = require("os");
6913
7022
 
6914
7023
  // src/skills/deprecated-skills.ts
@@ -6916,20 +7025,20 @@ var DEPRECATED_SKILLS = [
6916
7025
  "uloop-capture-window",
6917
7026
  // renamed to uloop-screenshot in v0.54.0
6918
7027
  "uloop-get-provider-details"
6919
- // internal development-only tool, not for end users
7028
+ // renamed to uloop-get-unity-search-providers
6920
7029
  ];
6921
7030
 
6922
7031
  // src/tool-settings-loader.ts
6923
7032
  var import_fs6 = require("fs");
6924
- var import_path6 = require("path");
7033
+ var import_path7 = require("path");
6925
7034
  var ULOOP_DIR = ".uloop";
6926
7035
  var TOOL_SETTINGS_FILE = "settings.tools.json";
6927
7036
  function loadDisabledTools(projectPath) {
6928
- const projectRoot = projectPath !== void 0 ? (0, import_path6.resolve)(projectPath) : findUnityProjectRoot();
7037
+ const projectRoot = projectPath !== void 0 ? (0, import_path7.resolve)(projectPath) : findUnityProjectRoot();
6929
7038
  if (projectRoot === null) {
6930
7039
  return [];
6931
7040
  }
6932
- const settingsPath = (0, import_path6.join)(projectRoot, ULOOP_DIR, TOOL_SETTINGS_FILE);
7041
+ const settingsPath = (0, import_path7.join)(projectRoot, ULOOP_DIR, TOOL_SETTINGS_FILE);
6933
7042
  let content;
6934
7043
  try {
6935
7044
  content = (0, import_fs6.readFileSync)(settingsPath, "utf-8");
@@ -7004,7 +7113,7 @@ var SkillsPathConstants = class _SkillsPathConstants {
7004
7113
  ];
7005
7114
  };
7006
7115
  function getGlobalSkillsDir(target) {
7007
- return (0, import_path7.join)((0, import_os.homedir)(), target.projectDir, "skills");
7116
+ return (0, import_path8.join)((0, import_os.homedir)(), target.projectDir, "skills");
7008
7117
  }
7009
7118
  function getProjectSkillsDir(target) {
7010
7119
  const status = getUnityProjectStatus();
@@ -7019,11 +7128,11 @@ function getProjectSkillsDir(target) {
7019
7128
  Please install uLoopMCP package first, then run this command again.`
7020
7129
  );
7021
7130
  }
7022
- return (0, import_path7.join)(status.path, target.projectDir, "skills");
7131
+ return (0, import_path8.join)(status.path, target.projectDir, "skills");
7023
7132
  }
7024
7133
  function getSkillPath(skillDirName, target, global) {
7025
7134
  const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
7026
- return (0, import_path7.join)(baseDir, skillDirName, target.skillFileName);
7135
+ return (0, import_path8.join)(baseDir, skillDirName, target.skillFileName);
7027
7136
  }
7028
7137
  function isSkillInstalled(skill, target, global) {
7029
7138
  const skillPath = getSkillPath(skill.dirName, target, global);
@@ -7031,8 +7140,8 @@ function isSkillInstalled(skill, target, global) {
7031
7140
  }
7032
7141
  function isSkillOutdated(skill, target, global) {
7033
7142
  const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
7034
- const skillDir = (0, import_path7.join)(baseDir, skill.dirName);
7035
- const skillPath = (0, import_path7.join)(skillDir, target.skillFileName);
7143
+ const skillDir = (0, import_path8.join)(baseDir, skill.dirName);
7144
+ const skillPath = (0, import_path8.join)(skillDir, target.skillFileName);
7036
7145
  if (!(0, import_fs7.existsSync)(skillPath)) {
7037
7146
  return false;
7038
7147
  }
@@ -7043,7 +7152,7 @@ function isSkillOutdated(skill, target, global) {
7043
7152
  if ("additionalFiles" in skill && skill.additionalFiles) {
7044
7153
  const additionalFiles = skill.additionalFiles;
7045
7154
  for (const [relativePath, expectedContent] of Object.entries(additionalFiles)) {
7046
- const filePath = (0, import_path7.join)(skillDir, relativePath);
7155
+ const filePath = (0, import_path8.join)(skillDir, relativePath);
7047
7156
  if (!(0, import_fs7.existsSync)(filePath)) {
7048
7157
  return true;
7049
7158
  }
@@ -7119,11 +7228,11 @@ function scanEditorFolderForSkills(editorPath, skills, sourceType, warnLegacy =
7119
7228
  if (EXCLUDED_DIRS2.has(entry.name)) {
7120
7229
  continue;
7121
7230
  }
7122
- const fullPath = (0, import_path7.join)(editorPath, entry.name);
7231
+ const fullPath = (0, import_path8.join)(editorPath, entry.name);
7123
7232
  if (entry.isDirectory()) {
7124
- const skillDir = (0, import_path7.join)(fullPath, SkillsPathConstants.SKILL_DIR);
7125
- const skillMdPath = (0, import_path7.join)(skillDir, SkillsPathConstants.SKILL_FILE);
7126
- const legacySkillMdPath = (0, import_path7.join)(fullPath, SkillsPathConstants.SKILL_FILE);
7233
+ const skillDir = (0, import_path8.join)(fullPath, SkillsPathConstants.SKILL_DIR);
7234
+ const skillMdPath = (0, import_path8.join)(skillDir, SkillsPathConstants.SKILL_FILE);
7235
+ const legacySkillMdPath = (0, import_path8.join)(fullPath, SkillsPathConstants.SKILL_FILE);
7127
7236
  if (warnLegacy && !(0, import_fs7.existsSync)(skillMdPath) && (0, import_fs7.existsSync)(legacySkillMdPath)) {
7128
7237
  warnLegacySkillStructure(fullPath, legacySkillMdPath);
7129
7238
  }
@@ -7161,7 +7270,7 @@ function findEditorFolders(basePath, maxDepth = 2) {
7161
7270
  if (!entry.isDirectory() || EXCLUDED_DIRS2.has(entry.name)) {
7162
7271
  continue;
7163
7272
  }
7164
- const fullPath = (0, import_path7.join)(currentPath, entry.name);
7273
+ const fullPath = (0, import_path8.join)(currentPath, entry.name);
7165
7274
  if (entry.name === "Editor") {
7166
7275
  editorFolders.push(fullPath);
7167
7276
  } else {
@@ -7180,9 +7289,9 @@ function collectProjectSkills(excludedRoots = []) {
7180
7289
  const skills = [];
7181
7290
  const seenNames = /* @__PURE__ */ new Set();
7182
7291
  const searchPaths = [
7183
- (0, import_path7.join)(projectRoot, SkillsPathConstants.ASSETS_DIR),
7184
- (0, import_path7.join)(projectRoot, SkillsPathConstants.PACKAGES_DIR),
7185
- (0, import_path7.join)(projectRoot, SkillsPathConstants.LIBRARY_DIR, SkillsPathConstants.PACKAGE_CACHE_DIR)
7292
+ (0, import_path8.join)(projectRoot, SkillsPathConstants.ASSETS_DIR),
7293
+ (0, import_path8.join)(projectRoot, SkillsPathConstants.PACKAGES_DIR),
7294
+ (0, import_path8.join)(projectRoot, SkillsPathConstants.LIBRARY_DIR, SkillsPathConstants.PACKAGE_CACHE_DIR)
7186
7295
  ];
7187
7296
  for (const searchPath of searchPaths) {
7188
7297
  if (!(0, import_fs7.existsSync)(searchPath)) {
@@ -7216,22 +7325,22 @@ function getAllSkillStatuses(target, global) {
7216
7325
  }
7217
7326
  function installSkill(skill, target, global) {
7218
7327
  const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
7219
- const skillDir = (0, import_path7.join)(baseDir, skill.dirName);
7220
- const skillPath = (0, import_path7.join)(skillDir, target.skillFileName);
7328
+ const skillDir = (0, import_path8.join)(baseDir, skill.dirName);
7329
+ const skillPath = (0, import_path8.join)(skillDir, target.skillFileName);
7221
7330
  (0, import_fs7.mkdirSync)(skillDir, { recursive: true });
7222
7331
  (0, import_fs7.writeFileSync)(skillPath, skill.content, "utf-8");
7223
7332
  if ("additionalFiles" in skill && skill.additionalFiles) {
7224
7333
  const additionalFiles = skill.additionalFiles;
7225
7334
  for (const [relativePath, content] of Object.entries(additionalFiles)) {
7226
- const fullPath = (0, import_path7.join)(skillDir, relativePath);
7227
- (0, import_fs7.mkdirSync)((0, import_path7.dirname)(fullPath), { recursive: true });
7335
+ const fullPath = (0, import_path8.join)(skillDir, relativePath);
7336
+ (0, import_fs7.mkdirSync)((0, import_path8.dirname)(fullPath), { recursive: true });
7228
7337
  (0, import_fs7.writeFileSync)(fullPath, content);
7229
7338
  }
7230
7339
  }
7231
7340
  }
7232
7341
  function uninstallSkill(skill, target, global) {
7233
7342
  const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
7234
- const skillDir = (0, import_path7.join)(baseDir, skill.dirName);
7343
+ const skillDir = (0, import_path8.join)(baseDir, skill.dirName);
7235
7344
  if (!(0, import_fs7.existsSync)(skillDir)) {
7236
7345
  return false;
7237
7346
  }
@@ -7249,7 +7358,7 @@ function installAllSkills(target, global) {
7249
7358
  };
7250
7359
  const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
7251
7360
  for (const deprecatedName of DEPRECATED_SKILLS) {
7252
- const deprecatedDir = (0, import_path7.join)(baseDir, deprecatedName);
7361
+ const deprecatedDir = (0, import_path8.join)(baseDir, deprecatedName);
7253
7362
  if ((0, import_fs7.existsSync)(deprecatedDir)) {
7254
7363
  (0, import_fs7.rmSync)(deprecatedDir, { recursive: true, force: true });
7255
7364
  result.deprecatedRemoved++;
@@ -7293,7 +7402,7 @@ function uninstallAllSkills(target, global) {
7293
7402
  const result = { removed: 0, notFound: 0 };
7294
7403
  const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
7295
7404
  for (const deprecatedName of DEPRECATED_SKILLS) {
7296
- const deprecatedDir = (0, import_path7.join)(baseDir, deprecatedName);
7405
+ const deprecatedDir = (0, import_path8.join)(baseDir, deprecatedName);
7297
7406
  if ((0, import_fs7.existsSync)(deprecatedDir)) {
7298
7407
  (0, import_fs7.rmSync)(deprecatedDir, { recursive: true, force: true });
7299
7408
  result.removed++;
@@ -7324,7 +7433,7 @@ function collectAllSkills() {
7324
7433
  return dedupeSkillsByName([packageSkills, cliOnlySkills, projectSkills]);
7325
7434
  }
7326
7435
  function collectPackageSkillsFromRoot(packageRoot) {
7327
- const mcpToolsRoot = (0, import_path7.join)(
7436
+ const mcpToolsRoot = (0, import_path8.join)(
7328
7437
  packageRoot,
7329
7438
  SkillsPathConstants.EDITOR_DIR,
7330
7439
  SkillsPathConstants.API_DIR,
@@ -7338,7 +7447,7 @@ function collectPackageSkillsFromRoot(packageRoot) {
7338
7447
  return skills;
7339
7448
  }
7340
7449
  function collectCliOnlySkills() {
7341
- const cliOnlyRoot = (0, import_path7.resolve)(
7450
+ const cliOnlyRoot = (0, import_path8.resolve)(
7342
7451
  __dirname,
7343
7452
  SkillsPathConstants.DIST_PARENT_DIR,
7344
7453
  SkillsPathConstants.SRC_DIR,
@@ -7370,7 +7479,7 @@ function collectSkillFolderFilesRecursive(baseDir, currentDir, additionalFiles)
7370
7479
  if (isExcludedFile(entry.name)) {
7371
7480
  continue;
7372
7481
  }
7373
- const fullPath = (0, import_path7.join)(currentDir, entry.name);
7482
+ const fullPath = (0, import_path8.join)(currentDir, entry.name);
7374
7483
  const relativePath = fullPath.slice(baseDir.length + 1);
7375
7484
  if (entry.isDirectory()) {
7376
7485
  if (EXCLUDED_DIRS2.has(entry.name)) {
@@ -7409,13 +7518,13 @@ function dedupeSkillsByName(skillGroups) {
7409
7518
  }
7410
7519
  function resolvePackageRoot(projectRoot) {
7411
7520
  const candidates = [];
7412
- candidates.push((0, import_path7.join)(projectRoot, SkillsPathConstants.PACKAGES_DIR, SkillsPathConstants.SRC_DIR));
7521
+ candidates.push((0, import_path8.join)(projectRoot, SkillsPathConstants.PACKAGES_DIR, SkillsPathConstants.SRC_DIR));
7413
7522
  const manifestPaths = resolveManifestPackagePaths(projectRoot);
7414
7523
  for (const manifestPath of manifestPaths) {
7415
7524
  candidates.push(manifestPath);
7416
7525
  }
7417
7526
  for (const packageName of SkillsPathConstants.PACKAGE_NAMES) {
7418
- candidates.push((0, import_path7.join)(projectRoot, SkillsPathConstants.PACKAGES_DIR, packageName));
7527
+ candidates.push((0, import_path8.join)(projectRoot, SkillsPathConstants.PACKAGES_DIR, packageName));
7419
7528
  }
7420
7529
  const directRoot = resolveFirstPackageRoot(candidates);
7421
7530
  if (directRoot) {
@@ -7424,7 +7533,7 @@ function resolvePackageRoot(projectRoot) {
7424
7533
  return resolvePackageCacheRoot(projectRoot);
7425
7534
  }
7426
7535
  function resolveManifestPackagePaths(projectRoot) {
7427
- const manifestPath = (0, import_path7.join)(
7536
+ const manifestPath = (0, import_path8.join)(
7428
7537
  projectRoot,
7429
7538
  SkillsPathConstants.PACKAGES_DIR,
7430
7539
  SkillsPathConstants.MANIFEST_FILE
@@ -7476,10 +7585,10 @@ function resolveDependencyPath(rawPath, projectRoot) {
7476
7585
  if (normalizedPath.startsWith("//")) {
7477
7586
  normalizedPath = normalizedPath.slice(2);
7478
7587
  }
7479
- if ((0, import_path7.isAbsolute)(normalizedPath)) {
7588
+ if ((0, import_path8.isAbsolute)(normalizedPath)) {
7480
7589
  return normalizedPath;
7481
7590
  }
7482
- return (0, import_path7.resolve)(projectRoot, normalizedPath);
7591
+ return (0, import_path8.resolve)(projectRoot, normalizedPath);
7483
7592
  }
7484
7593
  function resolveFirstPackageRoot(candidates) {
7485
7594
  for (const candidate of candidates) {
@@ -7491,7 +7600,7 @@ function resolveFirstPackageRoot(candidates) {
7491
7600
  return null;
7492
7601
  }
7493
7602
  function resolvePackageCacheRoot(projectRoot) {
7494
- const packageCacheDir = (0, import_path7.join)(
7603
+ const packageCacheDir = (0, import_path8.join)(
7495
7604
  projectRoot,
7496
7605
  SkillsPathConstants.LIBRARY_DIR,
7497
7606
  SkillsPathConstants.PACKAGE_CACHE_DIR
@@ -7507,7 +7616,7 @@ function resolvePackageCacheRoot(projectRoot) {
7507
7616
  if (!isTargetPackageCacheDir(entry.name)) {
7508
7617
  continue;
7509
7618
  }
7510
- const candidate = (0, import_path7.join)(packageCacheDir, entry.name);
7619
+ const candidate = (0, import_path8.join)(packageCacheDir, entry.name);
7511
7620
  const resolvedRoot = resolvePackageRootCandidate(candidate);
7512
7621
  if (resolvedRoot) {
7513
7622
  return resolvedRoot;
@@ -7519,7 +7628,7 @@ function resolvePackageRootCandidate(candidate) {
7519
7628
  if (!(0, import_fs7.existsSync)(candidate)) {
7520
7629
  return null;
7521
7630
  }
7522
- const directToolsPath = (0, import_path7.join)(
7631
+ const directToolsPath = (0, import_path8.join)(
7523
7632
  candidate,
7524
7633
  SkillsPathConstants.EDITOR_DIR,
7525
7634
  SkillsPathConstants.API_DIR,
@@ -7528,8 +7637,8 @@ function resolvePackageRootCandidate(candidate) {
7528
7637
  if ((0, import_fs7.existsSync)(directToolsPath)) {
7529
7638
  return candidate;
7530
7639
  }
7531
- const nestedRoot = (0, import_path7.join)(candidate, SkillsPathConstants.PACKAGES_DIR, SkillsPathConstants.SRC_DIR);
7532
- const nestedToolsPath = (0, import_path7.join)(
7640
+ const nestedRoot = (0, import_path8.join)(candidate, SkillsPathConstants.PACKAGES_DIR, SkillsPathConstants.SRC_DIR);
7641
+ const nestedToolsPath = (0, import_path8.join)(
7533
7642
  nestedRoot,
7534
7643
  SkillsPathConstants.EDITOR_DIR,
7535
7644
  SkillsPathConstants.API_DIR,
@@ -7561,12 +7670,12 @@ function isUnderExcludedRoots(targetPath, excludedRoots) {
7561
7670
  return false;
7562
7671
  }
7563
7672
  function isPathUnder(childPath, parentPath) {
7564
- const resolvedChild = (0, import_path7.resolve)(childPath);
7565
- const resolvedParent = (0, import_path7.resolve)(parentPath);
7673
+ const resolvedChild = (0, import_path8.resolve)(childPath);
7674
+ const resolvedParent = (0, import_path8.resolve)(parentPath);
7566
7675
  if (resolvedChild === resolvedParent) {
7567
7676
  return true;
7568
7677
  }
7569
- return resolvedChild.startsWith(resolvedParent + import_path7.sep);
7678
+ return resolvedChild.startsWith(resolvedParent + import_path8.sep);
7570
7679
  }
7571
7680
 
7572
7681
  // src/skills/target-config.ts
@@ -7751,20 +7860,20 @@ Uninstalling uloop skills (${location})...`);
7751
7860
  }
7752
7861
 
7753
7862
  // src/commands/launch.ts
7754
- var import_path8 = require("path");
7863
+ var import_path9 = require("path");
7755
7864
 
7756
7865
  // node_modules/launch-unity/dist/lib.js
7757
7866
  var import_node_child_process = require("node:child_process");
7758
7867
  var import_node_fs2 = require("node:fs");
7759
- var import_promises3 = require("node:fs/promises");
7868
+ var import_promises4 = require("node:fs/promises");
7760
7869
  var import_node_path2 = require("node:path");
7761
7870
  var import_node_util = require("node:util");
7762
7871
 
7763
7872
  // node_modules/launch-unity/dist/unityHub.js
7764
- var import_promises2 = require("node:fs/promises");
7873
+ var import_promises3 = require("node:fs/promises");
7765
7874
  var import_node_fs = require("node:fs");
7766
7875
  var import_node_path = require("node:path");
7767
- var import_node_assert2 = __toESM(require("node:assert"), 1);
7876
+ var import_node_assert3 = __toESM(require("node:assert"), 1);
7768
7877
  var resolveUnityHubProjectFiles = () => {
7769
7878
  if (process.platform === "darwin") {
7770
7879
  const home = process.env.HOME;
@@ -7791,7 +7900,7 @@ var removeTrailingSeparators = (target) => {
7791
7900
  }
7792
7901
  return trimmed;
7793
7902
  };
7794
- var normalizePath = (target) => {
7903
+ var normalizePath2 = (target) => {
7795
7904
  const resolvedPath = (0, import_node_path.resolve)(target);
7796
7905
  return removeTrailingSeparators(resolvedPath);
7797
7906
  };
@@ -7799,14 +7908,14 @@ var resolvePathWithActualCase = (target) => {
7799
7908
  try {
7800
7909
  return removeTrailingSeparators(import_node_fs.realpathSync.native(target));
7801
7910
  } catch {
7802
- return normalizePath(target);
7911
+ return normalizePath2(target);
7803
7912
  }
7804
7913
  };
7805
7914
  var toComparablePath = (value) => {
7806
7915
  return value.replace(/\\/g, "/").toLocaleLowerCase();
7807
7916
  };
7808
7917
  var pathsEqual = (left, right) => {
7809
- return toComparablePath(normalizePath(left)) === toComparablePath(normalizePath(right));
7918
+ return toComparablePath(normalizePath2(left)) === toComparablePath(normalizePath2(right));
7810
7919
  };
7811
7920
  var safeParseProjectsJson = (content) => {
7812
7921
  try {
@@ -7831,7 +7940,7 @@ var ensureProjectEntryAndUpdate = async (projectPath, version, when, setFavorite
7831
7940
  }
7832
7941
  for (const path of candidates) {
7833
7942
  logDebug(`Trying Unity Hub file: ${path}`);
7834
- const content = await (0, import_promises2.readFile)(path, "utf8").catch(() => void 0);
7943
+ const content = await (0, import_promises3.readFile)(path, "utf8").catch(() => void 0);
7835
7944
  if (!content) {
7836
7945
  logDebug("Read failed or empty content, skipping.");
7837
7946
  continue;
@@ -7866,7 +7975,7 @@ var ensureProjectEntryAndUpdate = async (projectPath, version, when, setFavorite
7866
7975
  }
7867
7976
  };
7868
7977
  try {
7869
- await (0, import_promises2.writeFile)(path, JSON.stringify(updatedJson, void 0, 2), "utf8");
7978
+ await (0, import_promises3.writeFile)(path, JSON.stringify(updatedJson, void 0, 2), "utf8");
7870
7979
  logDebug("Write succeeded.");
7871
7980
  } catch (error) {
7872
7981
  logDebug(`Write failed: ${error instanceof Error ? error.message : String(error)}`);
@@ -7883,7 +7992,7 @@ var updateLastModifiedIfExists = async (projectPath, when) => {
7883
7992
  let content;
7884
7993
  let json;
7885
7994
  try {
7886
- content = await (0, import_promises2.readFile)(path, "utf8");
7995
+ content = await (0, import_promises3.readFile)(path, "utf8");
7887
7996
  } catch {
7888
7997
  continue;
7889
7998
  }
@@ -7911,7 +8020,7 @@ var updateLastModifiedIfExists = async (projectPath, when) => {
7911
8020
  lastModified: when.getTime()
7912
8021
  };
7913
8022
  try {
7914
- await (0, import_promises2.writeFile)(path, JSON.stringify(json, void 0, 2), "utf8");
8023
+ await (0, import_promises3.writeFile)(path, JSON.stringify(json, void 0, 2), "utf8");
7915
8024
  } catch {
7916
8025
  }
7917
8026
  return;
@@ -7935,7 +8044,7 @@ var resolveUnityHubProjectsInfoFile = () => {
7935
8044
  return void 0;
7936
8045
  };
7937
8046
  var parseCliArgs = (cliArgsString) => {
7938
- (0, import_node_assert2.default)(cliArgsString !== null && cliArgsString !== void 0, "cliArgsString must not be null");
8047
+ (0, import_node_assert3.default)(cliArgsString !== null && cliArgsString !== void 0, "cliArgsString must not be null");
7939
8048
  const trimmed = cliArgsString.trim();
7940
8049
  if (trimmed.length === 0) {
7941
8050
  return [];
@@ -7991,7 +8100,7 @@ var groupCliArgs = (args) => {
7991
8100
  return groups;
7992
8101
  };
7993
8102
  var getProjectCliArgs = async (projectPath) => {
7994
- (0, import_node_assert2.default)(projectPath !== null && projectPath !== void 0, "projectPath must not be null");
8103
+ (0, import_node_assert3.default)(projectPath !== null && projectPath !== void 0, "projectPath must not be null");
7995
8104
  const infoFilePath = resolveUnityHubProjectsInfoFile();
7996
8105
  if (!infoFilePath) {
7997
8106
  logDebug("projectsInfo.json path could not be resolved.");
@@ -8000,7 +8109,7 @@ var getProjectCliArgs = async (projectPath) => {
8000
8109
  logDebug(`Reading projectsInfo.json: ${infoFilePath}`);
8001
8110
  let content;
8002
8111
  try {
8003
- content = await (0, import_promises2.readFile)(infoFilePath, "utf8");
8112
+ content = await (0, import_promises3.readFile)(infoFilePath, "utf8");
8004
8113
  } catch {
8005
8114
  logDebug("projectsInfo.json not found or not readable.");
8006
8115
  return [];
@@ -8012,7 +8121,7 @@ var getProjectCliArgs = async (projectPath) => {
8012
8121
  logDebug("projectsInfo.json parse failed.");
8013
8122
  return [];
8014
8123
  }
8015
- const normalizedProjectPath = normalizePath(projectPath);
8124
+ const normalizedProjectPath = normalizePath2(projectPath);
8016
8125
  const projectKey = Object.keys(json).find((key) => pathsEqual(key, normalizedProjectPath));
8017
8126
  if (!projectKey) {
8018
8127
  logDebug(`No entry found for project: ${normalizedProjectPath}`);
@@ -8091,7 +8200,7 @@ var removeTrailingSeparators2 = (target) => {
8091
8200
  }
8092
8201
  return trimmed;
8093
8202
  };
8094
- var normalizePath2 = (target) => {
8203
+ var normalizePath3 = (target) => {
8095
8204
  const resolvedPath = (0, import_node_path2.resolve)(target);
8096
8205
  const trimmed = removeTrailingSeparators2(resolvedPath);
8097
8206
  return trimmed;
@@ -8100,7 +8209,7 @@ var toComparablePath2 = (value) => {
8100
8209
  return value.replace(/\\/g, "/").toLocaleLowerCase();
8101
8210
  };
8102
8211
  var pathsEqual2 = (left, right) => {
8103
- return toComparablePath2(normalizePath2(left)) === toComparablePath2(normalizePath2(right));
8212
+ return toComparablePath2(normalizePath3(left)) === toComparablePath2(normalizePath3(right));
8104
8213
  };
8105
8214
  function extractProjectPath(command) {
8106
8215
  const match = command.match(PROJECT_PATH_PATTERN);
@@ -8161,7 +8270,7 @@ async function listUnityProcessesMac() {
8161
8270
  }
8162
8271
  processes.push({
8163
8272
  pid: pidValue,
8164
- projectPath: normalizePath2(projectArgument)
8273
+ projectPath: normalizePath3(projectArgument)
8165
8274
  });
8166
8275
  }
8167
8276
  return processes;
@@ -8209,7 +8318,7 @@ async function listUnityProcessesWindows() {
8209
8318
  }
8210
8319
  processes.push({
8211
8320
  pid: pidValue,
8212
- projectPath: normalizePath2(projectArgument)
8321
+ projectPath: normalizePath3(projectArgument)
8213
8322
  });
8214
8323
  }
8215
8324
  return processes;
@@ -8224,7 +8333,7 @@ async function listUnityProcesses() {
8224
8333
  return [];
8225
8334
  }
8226
8335
  async function findRunningUnityProcess(projectPath) {
8227
- const normalizedTarget = normalizePath2(projectPath);
8336
+ const normalizedTarget = normalizePath3(projectPath);
8228
8337
  const processes = await listUnityProcesses();
8229
8338
  return processes.find((candidate) => pathsEqual2(candidate.projectPath, normalizedTarget));
8230
8339
  }
@@ -8325,14 +8434,14 @@ async function handleStaleLockfile(projectPath) {
8325
8434
  console.log(`UnityLockfile found without active Unity process: ${lockfilePath}`);
8326
8435
  console.log("Assuming previous crash. Cleaning Temp directory and continuing launch.");
8327
8436
  try {
8328
- await (0, import_promises3.rm)(tempDirectoryPath, { recursive: true, force: true });
8437
+ await (0, import_promises4.rm)(tempDirectoryPath, { recursive: true, force: true });
8329
8438
  console.log("Deleted Temp directory.");
8330
8439
  } catch (error) {
8331
8440
  const message = error instanceof Error ? error.message : String(error);
8332
8441
  console.warn(`Failed to delete Temp directory: ${message}`);
8333
8442
  }
8334
8443
  try {
8335
- await (0, import_promises3.rm)(lockfilePath, { force: true });
8444
+ await (0, import_promises4.rm)(lockfilePath, { force: true });
8336
8445
  console.log("Deleted UnityLockfile.");
8337
8446
  } catch (error) {
8338
8447
  const message = error instanceof Error ? error.message : String(error);
@@ -8347,7 +8456,7 @@ async function deleteRecoveryDirectory(projectPath) {
8347
8456
  }
8348
8457
  console.log(`Deleting recovery directory: ${recoveryPath}`);
8349
8458
  try {
8350
- await (0, import_promises3.rm)(recoveryPath, { recursive: true, force: true });
8459
+ await (0, import_promises4.rm)(recoveryPath, { recursive: true, force: true });
8351
8460
  console.log("Deleted recovery directory.");
8352
8461
  } catch (error) {
8353
8462
  const message = error instanceof Error ? error.message : String(error);
@@ -8502,7 +8611,7 @@ function findUnityProjectBfs(rootDir, maxDepth) {
8502
8611
  rootCanonical = rootDir;
8503
8612
  }
8504
8613
  queue.push({ dir: rootCanonical, depth: 0 });
8505
- const visited = /* @__PURE__ */ new Set([toComparablePath2(normalizePath2(rootCanonical))]);
8614
+ const visited = /* @__PURE__ */ new Set([toComparablePath2(normalizePath3(rootCanonical))]);
8506
8615
  while (queue.length > 0) {
8507
8616
  const current = queue.shift();
8508
8617
  if (!current) {
@@ -8510,7 +8619,7 @@ function findUnityProjectBfs(rootDir, maxDepth) {
8510
8619
  }
8511
8620
  const { dir, depth } = current;
8512
8621
  if (isUnityProjectRoot(dir)) {
8513
- return normalizePath2(dir);
8622
+ return normalizePath3(dir);
8514
8623
  }
8515
8624
  const canDescend = maxDepth === -1 || depth < maxDepth;
8516
8625
  if (!canDescend) {
@@ -8531,7 +8640,7 @@ function findUnityProjectBfs(rootDir, maxDepth) {
8531
8640
  } catch {
8532
8641
  continue;
8533
8642
  }
8534
- const key = toComparablePath2(normalizePath2(childCanonical));
8643
+ const key = toComparablePath2(normalizePath3(childCanonical));
8535
8644
  if (visited.has(key)) {
8536
8645
  continue;
8537
8646
  }
@@ -8689,7 +8798,7 @@ function parseMaxDepth(value) {
8689
8798
  async function runLaunchCommand(projectPath, options) {
8690
8799
  const maxDepth = parseMaxDepth(options.maxDepth);
8691
8800
  await orchestrateLaunch({
8692
- projectPath: projectPath ? (0, import_path8.resolve)(projectPath) : void 0,
8801
+ projectPath: projectPath ? (0, import_path9.resolve)(projectPath) : void 0,
8693
8802
  searchRoot: process.cwd(),
8694
8803
  searchMaxDepth: maxDepth,
8695
8804
  platform: options.platform,
@@ -8703,8 +8812,12 @@ async function runLaunchCommand(projectPath, options) {
8703
8812
  }
8704
8813
 
8705
8814
  // src/commands/focus-window.ts
8706
- function registerFocusWindowCommand(program3) {
8707
- program3.command("focus-window").description("Bring Unity Editor window to front using OS-level commands").option("--project-path <path>", "Unity project path").action(async (options) => {
8815
+ function registerFocusWindowCommand(program3, helpGroup) {
8816
+ const cmd = program3.command("focus-window").description("Bring Unity Editor window to front using OS-level commands").option("--project-path <path>", "Unity project path");
8817
+ if (helpGroup !== void 0) {
8818
+ cmd.helpGroup(helpGroup);
8819
+ }
8820
+ cmd.action(async (options) => {
8708
8821
  let projectRoot;
8709
8822
  if (options.projectPath !== void 0) {
8710
8823
  try {
@@ -8765,6 +8878,14 @@ function registerFocusWindowCommand(program3) {
8765
8878
  var FOCUS_WINDOW_COMMAND = "focus-window";
8766
8879
  var LAUNCH_COMMAND = "launch";
8767
8880
  var UPDATE_COMMAND = "update";
8881
+ var HELP_GROUP_BUILTIN_TOOLS = "Built-in Tools:";
8882
+ var HELP_GROUP_THIRD_PARTY_TOOLS = "Third-party Tools:";
8883
+ var HELP_GROUP_CLI_COMMANDS = "CLI Commands:";
8884
+ var HELP_GROUP_ORDER = [
8885
+ HELP_GROUP_CLI_COMMANDS,
8886
+ HELP_GROUP_BUILTIN_TOOLS,
8887
+ HELP_GROUP_THIRD_PARTY_TOOLS
8888
+ ];
8768
8889
  var NO_SYNC_FLAGS = ["-v", "--version", "-h", "--help"];
8769
8890
  var BUILTIN_COMMANDS = [
8770
8891
  "list",
@@ -8777,9 +8898,44 @@ var BUILTIN_COMMANDS = [
8777
8898
  FOCUS_WINDOW_COMMAND
8778
8899
  ];
8779
8900
  var program2 = new Command();
8780
- program2.name("uloop").description("Unity MCP CLI - Direct communication with Unity Editor").version(VERSION, "-v, --version", "Output the version number").showHelpAfterError("(run with -h for available options)").configureHelp({ sortSubcommands: true });
8901
+ program2.name("uloop").description("Unity MCP CLI - Direct communication with Unity Editor").version(VERSION, "-v, --version", "Output the version number").showHelpAfterError("(run with -h for available options)").configureHelp({
8902
+ sortSubcommands: true,
8903
+ // commander.js default groupItems determines group display order by registration order,
8904
+ // but CLI commands are registered at module level (before tools), so the default order
8905
+ // would be wrong. We re-implement to enforce HELP_GROUP_ORDER.
8906
+ groupItems(unsortedItems, visibleItems, getGroup) {
8907
+ const groupMap = /* @__PURE__ */ new Map();
8908
+ for (const item of unsortedItems) {
8909
+ const group = getGroup(item);
8910
+ if (!groupMap.has(group)) {
8911
+ groupMap.set(group, []);
8912
+ }
8913
+ }
8914
+ for (const item of visibleItems) {
8915
+ const group = getGroup(item);
8916
+ if (!groupMap.has(group)) {
8917
+ groupMap.set(group, []);
8918
+ }
8919
+ groupMap.get(group).push(item);
8920
+ }
8921
+ const ordered = /* @__PURE__ */ new Map();
8922
+ for (const key of HELP_GROUP_ORDER) {
8923
+ const items = groupMap.get(key);
8924
+ if (items !== void 0) {
8925
+ ordered.set(key, items);
8926
+ groupMap.delete(key);
8927
+ }
8928
+ }
8929
+ for (const [key, value] of groupMap) {
8930
+ ordered.set(key, value);
8931
+ }
8932
+ return ordered;
8933
+ }
8934
+ });
8781
8935
  program2.option("--list-commands", "List all command names (for shell completion)");
8782
8936
  program2.option("--list-options <cmd>", "List options for a command (for shell completion)");
8937
+ program2.commandsGroup(HELP_GROUP_CLI_COMMANDS);
8938
+ program2.helpCommand(true);
8783
8939
  program2.command("list").description("List all available tools from Unity").option("-p, --port <port>", "Unity TCP port").option("--project-path <path>", "Unity project path").action(async (options) => {
8784
8940
  await runWithErrorHandling(() => listAvailableTools(extractGlobalOptions(options)));
8785
8941
  });
@@ -8800,11 +8956,12 @@ program2.command("fix").description("Clean up stale lock files that may prevent
8800
8956
  });
8801
8957
  registerSkillsCommand(program2);
8802
8958
  registerLaunchCommand(program2);
8803
- function registerToolCommand(tool) {
8959
+ function registerToolCommand(tool, helpGroup) {
8804
8960
  if (BUILTIN_COMMANDS.includes(tool.name)) {
8805
8961
  return;
8806
8962
  }
8807
- const cmd = program2.command(tool.name).description(tool.description);
8963
+ const firstLine = tool.description.split("\n")[0];
8964
+ const cmd = program2.command(tool.name).description(firstLine).helpGroup(helpGroup);
8808
8965
  const properties = tool.inputSchema.properties;
8809
8966
  for (const [propName, propInfo] of Object.entries(properties)) {
8810
8967
  const optionStr = generateOptionString(propName, propInfo);
@@ -8923,6 +9080,9 @@ function convertValue(value, propInfo) {
8923
9080
  }
8924
9081
  return value;
8925
9082
  }
9083
+ function getToolHelpGroup(toolName, defaultToolNames) {
9084
+ return defaultToolNames.has(toolName) ? HELP_GROUP_BUILTIN_TOOLS : HELP_GROUP_THIRD_PARTY_TOOLS;
9085
+ }
8926
9086
  function extractGlobalOptions(options) {
8927
9087
  return {
8928
9088
  port: options["port"],
@@ -8970,6 +9130,26 @@ async function runWithErrorHandling(fn) {
8970
9130
  try {
8971
9131
  await fn();
8972
9132
  } catch (error) {
9133
+ if (error instanceof UnityNotRunningError) {
9134
+ console.error("\x1B[31mError: Unity Editor for this project is not running.\x1B[0m");
9135
+ console.error("");
9136
+ console.error(` Project: ${error.projectRoot}`);
9137
+ console.error("");
9138
+ console.error("Start the Unity Editor for this project and try again.");
9139
+ process.exit(1);
9140
+ }
9141
+ if (error instanceof ProjectMismatchError) {
9142
+ console.error("\x1B[31mError: Unity Editor for this project is not running.\x1B[0m");
9143
+ console.error("");
9144
+ console.error(` Project: ${error.expectedProjectRoot}`);
9145
+ console.error(` Connected to: ${error.connectedProjectRoot}`);
9146
+ console.error("");
9147
+ console.error("Another Unity instance was found, but it belongs to a different project.");
9148
+ console.error(
9149
+ "Start the Unity Editor for this project, or use --port to specify the target."
9150
+ );
9151
+ process.exit(1);
9152
+ }
8973
9153
  const message = error instanceof Error ? error.message : String(error);
8974
9154
  if (message === "UNITY_COMPILING") {
8975
9155
  console.error("\x1B[33m\u23F3 Unity is compiling scripts.\x1B[0m");
@@ -9014,7 +9194,7 @@ async function runWithErrorHandling(fn) {
9014
9194
  }
9015
9195
  function detectShell() {
9016
9196
  const shell = process.env["SHELL"] || "";
9017
- const shellName = (0, import_path9.basename)(shell).replace(/\.exe$/i, "");
9197
+ const shellName = (0, import_path10.basename)(shell).replace(/\.exe$/i, "");
9018
9198
  if (shellName === "zsh") {
9019
9199
  return "zsh";
9020
9200
  }
@@ -9029,12 +9209,12 @@ function detectShell() {
9029
9209
  function getShellConfigPath(shell) {
9030
9210
  const home = (0, import_os2.homedir)();
9031
9211
  if (shell === "zsh") {
9032
- return (0, import_path9.join)(home, ".zshrc");
9212
+ return (0, import_path10.join)(home, ".zshrc");
9033
9213
  }
9034
9214
  if (shell === "powershell") {
9035
- return (0, import_path9.join)(home, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
9215
+ return (0, import_path10.join)(home, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
9036
9216
  }
9037
- return (0, import_path9.join)(home, ".bashrc");
9217
+ return (0, import_path10.join)(home, ".bashrc");
9038
9218
  }
9039
9219
  function getCompletionScript(shell) {
9040
9220
  if (shell === "bash") {
@@ -9171,10 +9351,10 @@ function cleanupLockFiles(projectPath) {
9171
9351
  console.error("Could not find Unity project root.");
9172
9352
  process.exit(1);
9173
9353
  }
9174
- const tempDir = (0, import_path9.join)(projectRoot, "Temp");
9354
+ const tempDir = (0, import_path10.join)(projectRoot, "Temp");
9175
9355
  let cleaned = 0;
9176
9356
  for (const lockFile of LOCK_FILES) {
9177
- const lockPath = (0, import_path9.join)(tempDir, lockFile);
9357
+ const lockPath = (0, import_path10.join)(tempDir, lockFile);
9178
9358
  if ((0, import_fs8.existsSync)(lockPath)) {
9179
9359
  (0, import_fs8.unlinkSync)(lockPath);
9180
9360
  console.log(`Removed: ${lockFile}`);
@@ -9211,7 +9391,7 @@ function handleCompletion(install, shellOverride) {
9211
9391
  return;
9212
9392
  }
9213
9393
  const configPath = getShellConfigPath(shell);
9214
- const configDir = (0, import_path9.dirname)(configPath);
9394
+ const configDir = (0, import_path10.dirname)(configPath);
9215
9395
  if (!(0, import_fs8.existsSync)(configDir)) {
9216
9396
  (0, import_fs8.mkdirSync)(configDir, { recursive: true });
9217
9397
  }
@@ -9305,6 +9485,20 @@ function shouldSkipAutoSync(cmdName, args) {
9305
9485
  }
9306
9486
  return args.some((arg) => NO_SYNC_FLAGS.includes(arg));
9307
9487
  }
9488
+ var OPTIONS_WITH_VALUE = /* @__PURE__ */ new Set(["--port", "-p", "--project-path"]);
9489
+ function findCommandName(args) {
9490
+ for (let i = 0; i < args.length; i++) {
9491
+ const arg = args[i];
9492
+ if (arg.startsWith("-")) {
9493
+ if (OPTIONS_WITH_VALUE.has(arg)) {
9494
+ i++;
9495
+ }
9496
+ continue;
9497
+ }
9498
+ return arg;
9499
+ }
9500
+ return void 0;
9501
+ }
9308
9502
  function extractSyncGlobalOptions(args) {
9309
9503
  const options = {};
9310
9504
  for (let i = 0; i < args.length; i++) {
@@ -9339,20 +9533,21 @@ async function main() {
9339
9533
  return;
9340
9534
  }
9341
9535
  const args = process.argv.slice(2);
9342
- const cmdName = args.find((arg) => !arg.startsWith("-"));
9343
9536
  const syncGlobalOptions = extractSyncGlobalOptions(args);
9537
+ const cmdName = findCommandName(args);
9344
9538
  const NO_PROJECT_COMMANDS = [UPDATE_COMMAND, "completion"];
9345
9539
  const skipProjectDetection = cmdName === void 0 || NO_PROJECT_COMMANDS.includes(cmdName);
9346
9540
  if (skipProjectDetection) {
9347
- const defaultTools = getDefaultTools();
9541
+ const defaultToolNames2 = getDefaultToolNames();
9348
9542
  const isTopLevelHelp = cmdName === void 0 && (args.includes("-h") || args.includes("--help"));
9349
9543
  const shouldFilter = syncGlobalOptions.projectPath !== void 0 || isTopLevelHelp;
9350
- const tools = shouldFilter ? filterEnabledTools(defaultTools.tools, syncGlobalOptions.projectPath) : defaultTools.tools;
9544
+ const sourceTools = shouldFilter ? loadToolsCache(syncGlobalOptions.projectPath).tools : getDefaultTools().tools;
9545
+ const tools = shouldFilter ? filterEnabledTools(sourceTools, syncGlobalOptions.projectPath) : sourceTools;
9351
9546
  if (!shouldFilter || isToolEnabled(FOCUS_WINDOW_COMMAND, syncGlobalOptions.projectPath)) {
9352
- registerFocusWindowCommand(program2);
9547
+ registerFocusWindowCommand(program2, HELP_GROUP_BUILTIN_TOOLS);
9353
9548
  }
9354
9549
  for (const tool of tools) {
9355
- registerToolCommand(tool);
9550
+ registerToolCommand(tool, getToolHelpGroup(tool.name, defaultToolNames2));
9356
9551
  }
9357
9552
  program2.parse();
9358
9553
  return;
@@ -9381,11 +9576,12 @@ async function main() {
9381
9576
  }
9382
9577
  const toolsCache = loadToolsCache();
9383
9578
  const projectPath = syncGlobalOptions.projectPath;
9579
+ const defaultToolNames = getDefaultToolNames();
9384
9580
  if (isToolEnabled(FOCUS_WINDOW_COMMAND, projectPath)) {
9385
- registerFocusWindowCommand(program2);
9581
+ registerFocusWindowCommand(program2, HELP_GROUP_BUILTIN_TOOLS);
9386
9582
  }
9387
9583
  for (const tool of filterEnabledTools(toolsCache.tools, projectPath)) {
9388
- registerToolCommand(tool);
9584
+ registerToolCommand(tool, getToolHelpGroup(tool.name, defaultToolNames));
9389
9585
  }
9390
9586
  if (cmdName && !commandExists(cmdName, projectPath)) {
9391
9587
  if (!isToolEnabled(cmdName, projectPath)) {
@@ -9398,7 +9594,7 @@ async function main() {
9398
9594
  const newCache = loadToolsCache();
9399
9595
  const tool = filterEnabledTools(newCache.tools, projectPath).find((t) => t.name === cmdName);
9400
9596
  if (tool) {
9401
- registerToolCommand(tool);
9597
+ registerToolCommand(tool, getToolHelpGroup(tool.name, defaultToolNames));
9402
9598
  console.log(`\x1B[32m\u2713 Found '${cmdName}' after sync.\x1B[0m
9403
9599
  `);
9404
9600
  } else {