uloop-cli 0.64.0 → 0.65.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.
@@ -5383,8 +5383,8 @@ var require_semver2 = __commonJS({
5383
5383
  });
5384
5384
 
5385
5385
  // src/cli.ts
5386
- var import_fs6 = require("fs");
5387
- var import_path7 = require("path");
5386
+ var import_fs7 = require("fs");
5387
+ var import_path8 = require("path");
5388
5388
  var import_os2 = require("os");
5389
5389
  var import_child_process = require("child_process");
5390
5390
 
@@ -5407,8 +5407,8 @@ var {
5407
5407
 
5408
5408
  // src/execute-tool.ts
5409
5409
  var readline = __toESM(require("readline"), 1);
5410
- var import_fs4 = require("fs");
5411
- var import_path4 = require("path");
5410
+ var import_fs5 = require("fs");
5411
+ var import_path5 = require("path");
5412
5412
  var semver = __toESM(require_semver2(), 1);
5413
5413
 
5414
5414
  // src/direct-unity-client.ts
@@ -5510,7 +5510,14 @@ var DirectUnityClient = class {
5510
5510
  const framedMessage = createFrame(requestJson);
5511
5511
  return new Promise((resolve5, reject) => {
5512
5512
  const socket = this.socket;
5513
+ const cleanup = () => {
5514
+ clearTimeout(timeoutId);
5515
+ socket.off("data", onData);
5516
+ socket.off("error", onError);
5517
+ socket.off("close", onClose);
5518
+ };
5513
5519
  const timeoutId = setTimeout(() => {
5520
+ cleanup();
5514
5521
  reject(
5515
5522
  new Error(
5516
5523
  `Request timed out after ${NETWORK_TIMEOUT_MS}ms. Unity may be frozen or busy. [For AI] Run 'uloop focus-window' to bring Unity to the front, then retry the tool. If the issue persists, report this to the user and ask how to proceed. Do NOT kill Unity processes without user permission.`
@@ -5531,8 +5538,7 @@ var DirectUnityClient = class {
5531
5538
  if (extractResult.jsonContent === null) {
5532
5539
  return;
5533
5540
  }
5534
- clearTimeout(timeoutId);
5535
- socket.off("data", onData);
5541
+ cleanup();
5536
5542
  this.receiveBuffer = extractResult.remainingData;
5537
5543
  const response = JSON.parse(extractResult.jsonContent);
5538
5544
  if (response.error) {
@@ -5541,7 +5547,17 @@ var DirectUnityClient = class {
5541
5547
  }
5542
5548
  resolve5(response.result);
5543
5549
  };
5550
+ const onError = (error) => {
5551
+ cleanup();
5552
+ reject(new Error(`Connection lost: ${error.message}`));
5553
+ };
5554
+ const onClose = () => {
5555
+ cleanup();
5556
+ reject(new Error("UNITY_NO_RESPONSE"));
5557
+ };
5544
5558
  socket.on("data", onData);
5559
+ socket.on("error", onError);
5560
+ socket.on("close", onClose);
5545
5561
  socket.write(framedMessage);
5546
5562
  });
5547
5563
  }
@@ -5783,7 +5799,7 @@ var import_path3 = require("path");
5783
5799
 
5784
5800
  // src/default-tools.json
5785
5801
  var default_tools_default = {
5786
- version: "0.64.0",
5802
+ version: "0.65.0",
5787
5803
  tools: [
5788
5804
  {
5789
5805
  name: "compile",
@@ -5794,6 +5810,10 @@ var default_tools_default = {
5794
5810
  ForceRecompile: {
5795
5811
  type: "boolean",
5796
5812
  description: "Force full recompilation"
5813
+ },
5814
+ WaitForDomainReload: {
5815
+ type: "boolean",
5816
+ description: "Wait for domain reload completion before returning"
5797
5817
  }
5798
5818
  }
5799
5819
  }
@@ -6227,7 +6247,7 @@ function getCachedServerVersion() {
6227
6247
  }
6228
6248
 
6229
6249
  // src/version.ts
6230
- var VERSION = "0.64.0";
6250
+ var VERSION = "0.65.0";
6231
6251
 
6232
6252
  // src/spinner.ts
6233
6253
  var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
@@ -6261,6 +6281,206 @@ function createSpinner(initialMessage) {
6261
6281
  };
6262
6282
  }
6263
6283
 
6284
+ // src/compile-helpers.ts
6285
+ var import_node_assert = __toESM(require("node:assert"), 1);
6286
+ var import_fs4 = require("fs");
6287
+ var net2 = __toESM(require("net"), 1);
6288
+ var import_path4 = require("path");
6289
+ var SAFE_REQUEST_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
6290
+ var COMPILE_FORCE_RECOMPILE_ARG_KEYS = [
6291
+ "ForceRecompile",
6292
+ "forceRecompile",
6293
+ "force_recompile",
6294
+ "force-recompile"
6295
+ ];
6296
+ var COMPILE_WAIT_FOR_DOMAIN_RELOAD_ARG_KEYS = [
6297
+ "WaitForDomainReload",
6298
+ "waitForDomainReload",
6299
+ "wait_for_domain_reload",
6300
+ "wait-for-domain-reload"
6301
+ ];
6302
+ var LOCK_GRACE_PERIOD_MS = 500;
6303
+ var READINESS_CHECK_TIMEOUT_MS = 3e3;
6304
+ var DEFAULT_HOST2 = "127.0.0.1";
6305
+ var CONTENT_LENGTH_HEADER2 = "Content-Length:";
6306
+ var HEADER_SEPARATOR2 = "\r\n\r\n";
6307
+ function toBoolean(value) {
6308
+ if (typeof value === "boolean") {
6309
+ return value;
6310
+ }
6311
+ if (typeof value === "string") {
6312
+ return value.toLowerCase() === "true";
6313
+ }
6314
+ return false;
6315
+ }
6316
+ function getCompileBooleanArg(args, keys) {
6317
+ for (const key of keys) {
6318
+ if (!(key in args)) {
6319
+ continue;
6320
+ }
6321
+ return toBoolean(args[key]);
6322
+ }
6323
+ return false;
6324
+ }
6325
+ function resolveCompileExecutionOptions(args) {
6326
+ return {
6327
+ forceRecompile: getCompileBooleanArg(args, COMPILE_FORCE_RECOMPILE_ARG_KEYS),
6328
+ waitForDomainReload: getCompileBooleanArg(args, COMPILE_WAIT_FOR_DOMAIN_RELOAD_ARG_KEYS)
6329
+ };
6330
+ }
6331
+ function createCompileRequestId() {
6332
+ const timestamp = Date.now();
6333
+ const randomToken = Math.floor(Math.random() * 1e6).toString().padStart(6, "0");
6334
+ return `compile_${timestamp}_${randomToken}`;
6335
+ }
6336
+ function ensureCompileRequestId(args) {
6337
+ const existingRequestId = args["RequestId"];
6338
+ if (typeof existingRequestId === "string" && existingRequestId.length > 0) {
6339
+ if (SAFE_REQUEST_ID_PATTERN.test(existingRequestId)) {
6340
+ return existingRequestId;
6341
+ }
6342
+ }
6343
+ const requestId = createCompileRequestId();
6344
+ args["RequestId"] = requestId;
6345
+ return requestId;
6346
+ }
6347
+ function getCompileResultFilePath(projectRoot, requestId) {
6348
+ (0, import_node_assert.default)(
6349
+ SAFE_REQUEST_ID_PATTERN.test(requestId),
6350
+ `requestId contains unsafe characters: '${requestId}'`
6351
+ );
6352
+ return (0, import_path4.join)(projectRoot, "Temp", "uLoopMCP", "compile-results", `${requestId}.json`);
6353
+ }
6354
+ function isUnityBusyByLockFiles(projectRoot) {
6355
+ const compilingLockPath = (0, import_path4.join)(projectRoot, "Temp", "compiling.lock");
6356
+ if ((0, import_fs4.existsSync)(compilingLockPath)) {
6357
+ return true;
6358
+ }
6359
+ const domainReloadLockPath = (0, import_path4.join)(projectRoot, "Temp", "domainreload.lock");
6360
+ if ((0, import_fs4.existsSync)(domainReloadLockPath)) {
6361
+ return true;
6362
+ }
6363
+ const serverStartingLockPath = (0, import_path4.join)(projectRoot, "Temp", "serverstarting.lock");
6364
+ return (0, import_fs4.existsSync)(serverStartingLockPath);
6365
+ }
6366
+ function stripUtf8Bom(content) {
6367
+ if (content.charCodeAt(0) === 65279) {
6368
+ return content.slice(1);
6369
+ }
6370
+ return content;
6371
+ }
6372
+ function tryReadCompileResult(projectRoot, requestId) {
6373
+ const resultFilePath = getCompileResultFilePath(projectRoot, requestId);
6374
+ if (!(0, import_fs4.existsSync)(resultFilePath)) {
6375
+ return void 0;
6376
+ }
6377
+ try {
6378
+ const content = (0, import_fs4.readFileSync)(resultFilePath, "utf-8");
6379
+ const parsed = JSON.parse(stripUtf8Bom(content));
6380
+ return parsed;
6381
+ } catch {
6382
+ return void 0;
6383
+ }
6384
+ }
6385
+ function canSendRequestToUnity(port) {
6386
+ return new Promise((resolve5) => {
6387
+ const socket = new net2.Socket();
6388
+ const timer = setTimeout(() => {
6389
+ socket.destroy();
6390
+ resolve5(false);
6391
+ }, READINESS_CHECK_TIMEOUT_MS);
6392
+ const cleanup = () => {
6393
+ clearTimeout(timer);
6394
+ socket.destroy();
6395
+ };
6396
+ socket.connect(port, DEFAULT_HOST2, () => {
6397
+ const rpcRequest = JSON.stringify({
6398
+ jsonrpc: "2.0",
6399
+ method: "get-tool-details",
6400
+ params: { IncludeDevelopmentOnly: false },
6401
+ id: 0
6402
+ });
6403
+ const contentLength = Buffer.byteLength(rpcRequest, "utf8");
6404
+ const frame = `${CONTENT_LENGTH_HEADER2} ${contentLength}${HEADER_SEPARATOR2}${rpcRequest}`;
6405
+ socket.write(frame);
6406
+ });
6407
+ let buffer = Buffer.alloc(0);
6408
+ socket.on("data", (chunk) => {
6409
+ buffer = Buffer.concat([buffer, chunk]);
6410
+ const sepIndex = buffer.indexOf(HEADER_SEPARATOR2);
6411
+ if (sepIndex !== -1) {
6412
+ cleanup();
6413
+ resolve5(true);
6414
+ }
6415
+ });
6416
+ socket.on("error", () => {
6417
+ cleanup();
6418
+ resolve5(false);
6419
+ });
6420
+ socket.on("close", () => {
6421
+ clearTimeout(timer);
6422
+ resolve5(false);
6423
+ });
6424
+ });
6425
+ }
6426
+ function sleep(ms) {
6427
+ return new Promise((resolve5) => setTimeout(resolve5, ms));
6428
+ }
6429
+ async function waitForCompileCompletion(options) {
6430
+ const startTime = Date.now();
6431
+ let idleSinceTimestamp = null;
6432
+ while (Date.now() - startTime < options.timeoutMs) {
6433
+ const result = tryReadCompileResult(options.projectRoot, options.requestId);
6434
+ const isBusy = isUnityBusyByLockFiles(options.projectRoot);
6435
+ if (result !== void 0 && !isBusy) {
6436
+ const now = Date.now();
6437
+ if (idleSinceTimestamp === null) {
6438
+ idleSinceTimestamp = now;
6439
+ }
6440
+ const idleDuration = now - idleSinceTimestamp;
6441
+ if (idleDuration >= LOCK_GRACE_PERIOD_MS) {
6442
+ if (options.unityPort !== void 0) {
6443
+ const isReady = await canSendRequestToUnity(options.unityPort);
6444
+ if (isReady) {
6445
+ return { outcome: "completed", result };
6446
+ }
6447
+ } else if (options.isUnityReadyWhenIdle) {
6448
+ const isReady = await options.isUnityReadyWhenIdle();
6449
+ if (isReady) {
6450
+ return { outcome: "completed", result };
6451
+ }
6452
+ } else {
6453
+ return { outcome: "completed", result };
6454
+ }
6455
+ }
6456
+ } else {
6457
+ idleSinceTimestamp = null;
6458
+ }
6459
+ await sleep(options.pollIntervalMs);
6460
+ }
6461
+ const lastResult = tryReadCompileResult(options.projectRoot, options.requestId);
6462
+ if (lastResult !== void 0 && !isUnityBusyByLockFiles(options.projectRoot)) {
6463
+ await sleep(LOCK_GRACE_PERIOD_MS);
6464
+ if (isUnityBusyByLockFiles(options.projectRoot)) {
6465
+ return { outcome: "timed_out" };
6466
+ }
6467
+ if (options.unityPort !== void 0) {
6468
+ const isReady = await canSendRequestToUnity(options.unityPort);
6469
+ if (isReady) {
6470
+ return { outcome: "completed", result: lastResult };
6471
+ }
6472
+ } else if (options.isUnityReadyWhenIdle) {
6473
+ const isReady = await options.isUnityReadyWhenIdle();
6474
+ if (isReady) {
6475
+ return { outcome: "completed", result: lastResult };
6476
+ }
6477
+ } else {
6478
+ return { outcome: "completed", result: lastResult };
6479
+ }
6480
+ }
6481
+ return { outcome: "timed_out" };
6482
+ }
6483
+
6264
6484
  // src/execute-tool.ts
6265
6485
  function suppressStdinEcho() {
6266
6486
  if (!process.stdin.isTTY) {
@@ -6287,10 +6507,23 @@ function suppressStdinEcho() {
6287
6507
  rl.close();
6288
6508
  };
6289
6509
  }
6510
+ function stripInternalFields(result) {
6511
+ const cleaned = { ...result };
6512
+ delete cleaned["ProjectRoot"];
6513
+ return cleaned;
6514
+ }
6290
6515
  var RETRY_DELAY_MS = 500;
6291
6516
  var MAX_RETRIES = 3;
6292
- function sleep(ms) {
6293
- return new Promise((resolve5) => setTimeout(resolve5, ms));
6517
+ var COMPILE_WAIT_TIMEOUT_MS = 9e4;
6518
+ var COMPILE_WAIT_POLL_INTERVAL_MS = 100;
6519
+ function getCompileExecutionOptions(toolName, params) {
6520
+ if (toolName !== "compile") {
6521
+ return {
6522
+ forceRecompile: false,
6523
+ waitForDomainReload: false
6524
+ };
6525
+ }
6526
+ return resolveCompileExecutionOptions(params);
6294
6527
  }
6295
6528
  function isRetryableError(error) {
6296
6529
  if (!(error instanceof Error)) {
@@ -6299,6 +6532,13 @@ function isRetryableError(error) {
6299
6532
  const message = error.message;
6300
6533
  return message.includes("ECONNREFUSED") || message.includes("EADDRNOTAVAIL") || message === "UNITY_NO_RESPONSE";
6301
6534
  }
6535
+ function isTransportDisconnectError(error) {
6536
+ if (!(error instanceof Error)) {
6537
+ return false;
6538
+ }
6539
+ const message = error.message;
6540
+ return message === "UNITY_NO_RESPONSE" || message.startsWith("Connection lost:");
6541
+ }
6302
6542
  function isVersionOlder(v1, v2) {
6303
6543
  const parsed1 = semver.valid(v1);
6304
6544
  const parsed2 = semver.valid(v2);
@@ -6330,16 +6570,16 @@ function checkUnityBusyState() {
6330
6570
  if (projectRoot === null) {
6331
6571
  return;
6332
6572
  }
6333
- const compilingLock = (0, import_path4.join)(projectRoot, "Temp", "compiling.lock");
6334
- if ((0, import_fs4.existsSync)(compilingLock)) {
6573
+ const compilingLock = (0, import_path5.join)(projectRoot, "Temp", "compiling.lock");
6574
+ if ((0, import_fs5.existsSync)(compilingLock)) {
6335
6575
  throw new Error("UNITY_COMPILING");
6336
6576
  }
6337
- const domainReloadLock = (0, import_path4.join)(projectRoot, "Temp", "domainreload.lock");
6338
- if ((0, import_fs4.existsSync)(domainReloadLock)) {
6577
+ const domainReloadLock = (0, import_path5.join)(projectRoot, "Temp", "domainreload.lock");
6578
+ if ((0, import_fs5.existsSync)(domainReloadLock)) {
6339
6579
  throw new Error("UNITY_DOMAIN_RELOAD");
6340
6580
  }
6341
- const serverStartingLock = (0, import_path4.join)(projectRoot, "Temp", "serverstarting.lock");
6342
- if ((0, import_fs4.existsSync)(serverStartingLock)) {
6581
+ const serverStartingLock = (0, import_path5.join)(projectRoot, "Temp", "serverstarting.lock");
6582
+ if ((0, import_fs5.existsSync)(serverStartingLock)) {
6343
6583
  throw new Error("UNITY_SERVER_STARTING");
6344
6584
  }
6345
6585
  }
@@ -6353,27 +6593,47 @@ async function executeToolCommand(toolName, params, globalOptions) {
6353
6593
  portNumber = parsed;
6354
6594
  }
6355
6595
  const port = await resolveUnityPort(portNumber);
6596
+ const compileOptions = getCompileExecutionOptions(toolName, params);
6597
+ const shouldWaitForDomainReload = compileOptions.waitForDomainReload;
6598
+ const compileRequestId = shouldWaitForDomainReload ? ensureCompileRequestId(params) : void 0;
6356
6599
  const restoreStdin = suppressStdinEcho();
6357
6600
  const spinner = createSpinner("Connecting to Unity...");
6358
6601
  let lastError;
6602
+ let immediateResult;
6603
+ const projectRoot = findUnityProjectRoot();
6604
+ let requestDispatched = false;
6359
6605
  for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
6360
6606
  checkUnityBusyState();
6361
6607
  const client = new DirectUnityClient(port);
6362
6608
  try {
6363
6609
  await client.connect();
6364
6610
  spinner.update(`Executing ${toolName}...`);
6611
+ requestDispatched = true;
6365
6612
  const result = await client.sendRequest(toolName, params);
6366
6613
  if (result === void 0 || result === null) {
6367
6614
  throw new Error("UNITY_NO_RESPONSE");
6368
6615
  }
6369
- spinner.stop();
6370
- restoreStdin();
6371
- checkServerVersion(result);
6372
- console.log(JSON.stringify(result, null, 2));
6373
- return;
6616
+ immediateResult = result;
6617
+ if (!shouldWaitForDomainReload) {
6618
+ spinner.stop();
6619
+ restoreStdin();
6620
+ checkServerVersion(result);
6621
+ console.log(JSON.stringify(stripInternalFields(result), null, 2));
6622
+ return;
6623
+ }
6624
+ break;
6374
6625
  } catch (error) {
6375
6626
  lastError = error;
6376
6627
  client.disconnect();
6628
+ if (requestDispatched && shouldWaitForDomainReload) {
6629
+ if (isTransportDisconnectError(error)) {
6630
+ spinner.update("Connection lost during compile. Waiting for result file...");
6631
+ break;
6632
+ }
6633
+ spinner.stop();
6634
+ restoreStdin();
6635
+ throw error instanceof Error ? error : new Error(String(error));
6636
+ }
6377
6637
  if (!isRetryableError(error) || attempt >= MAX_RETRIES) {
6378
6638
  break;
6379
6639
  }
@@ -6383,9 +6643,70 @@ async function executeToolCommand(toolName, params, globalOptions) {
6383
6643
  client.disconnect();
6384
6644
  }
6385
6645
  }
6646
+ if (shouldWaitForDomainReload && compileRequestId) {
6647
+ if (immediateResult === void 0 && !requestDispatched) {
6648
+ spinner.stop();
6649
+ restoreStdin();
6650
+ if (lastError instanceof Error) {
6651
+ throw lastError;
6652
+ }
6653
+ throw new Error(
6654
+ "Compile request never reached Unity. Check that Unity is running and retry."
6655
+ );
6656
+ }
6657
+ const projectRootFromUnity = immediateResult !== void 0 ? immediateResult["ProjectRoot"] : void 0;
6658
+ const effectiveProjectRoot = projectRootFromUnity ?? projectRoot;
6659
+ if (effectiveProjectRoot === null) {
6660
+ spinner.stop();
6661
+ restoreStdin();
6662
+ if (immediateResult !== void 0) {
6663
+ checkServerVersion(immediateResult);
6664
+ console.log(JSON.stringify(stripInternalFields(immediateResult), null, 2));
6665
+ return;
6666
+ }
6667
+ if (lastError instanceof Error) {
6668
+ throw lastError;
6669
+ }
6670
+ throw new Error(
6671
+ "Compile request failed and project root is unknown. Check connection and retry."
6672
+ );
6673
+ }
6674
+ spinner.update("Waiting for domain reload to complete...");
6675
+ const { outcome, result: storedResult } = await waitForCompileCompletion({
6676
+ projectRoot: effectiveProjectRoot,
6677
+ requestId: compileRequestId,
6678
+ timeoutMs: COMPILE_WAIT_TIMEOUT_MS,
6679
+ pollIntervalMs: COMPILE_WAIT_POLL_INTERVAL_MS,
6680
+ unityPort: port
6681
+ });
6682
+ if (outcome === "timed_out") {
6683
+ lastError = new Error(
6684
+ `Compile wait timed out after ${COMPILE_WAIT_TIMEOUT_MS}ms. Run 'uloop fix' and retry.`
6685
+ );
6686
+ } else {
6687
+ const finalResult = storedResult ?? immediateResult;
6688
+ if (finalResult !== void 0) {
6689
+ spinner.stop();
6690
+ restoreStdin();
6691
+ checkServerVersion(finalResult);
6692
+ console.log(JSON.stringify(stripInternalFields(finalResult), null, 2));
6693
+ return;
6694
+ }
6695
+ }
6696
+ }
6386
6697
  spinner.stop();
6387
6698
  restoreStdin();
6388
- throw lastError;
6699
+ if (lastError === void 0) {
6700
+ throw new Error("Tool execution failed without error details.");
6701
+ }
6702
+ if (lastError instanceof Error) {
6703
+ throw lastError;
6704
+ }
6705
+ if (typeof lastError === "string") {
6706
+ throw new Error(lastError);
6707
+ }
6708
+ const serializedError = JSON.stringify(lastError);
6709
+ throw new Error(serializedError ?? "Unknown error");
6389
6710
  }
6390
6711
  async function listAvailableTools(globalOptions) {
6391
6712
  let portNumber;
@@ -6515,8 +6836,8 @@ function pascalToKebabCase(pascal) {
6515
6836
  }
6516
6837
 
6517
6838
  // src/skills/skills-manager.ts
6518
- var import_fs5 = require("fs");
6519
- var import_path5 = require("path");
6839
+ var import_fs6 = require("fs");
6840
+ var import_path6 = require("path");
6520
6841
  var import_os = require("os");
6521
6842
 
6522
6843
  // src/skills/deprecated-skills.ts
@@ -6563,7 +6884,7 @@ var SkillsPathConstants = class _SkillsPathConstants {
6563
6884
  ];
6564
6885
  };
6565
6886
  function getGlobalSkillsDir(target) {
6566
- return (0, import_path5.join)((0, import_os.homedir)(), target.projectDir, "skills");
6887
+ return (0, import_path6.join)((0, import_os.homedir)(), target.projectDir, "skills");
6567
6888
  }
6568
6889
  function getProjectSkillsDir(target) {
6569
6890
  const status = getUnityProjectStatus();
@@ -6578,35 +6899,35 @@ function getProjectSkillsDir(target) {
6578
6899
  Please install uLoopMCP package first, then run this command again.`
6579
6900
  );
6580
6901
  }
6581
- return (0, import_path5.join)(status.path, target.projectDir, "skills");
6902
+ return (0, import_path6.join)(status.path, target.projectDir, "skills");
6582
6903
  }
6583
6904
  function getSkillPath(skillDirName, target, global) {
6584
6905
  const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
6585
- return (0, import_path5.join)(baseDir, skillDirName, target.skillFileName);
6906
+ return (0, import_path6.join)(baseDir, skillDirName, target.skillFileName);
6586
6907
  }
6587
6908
  function isSkillInstalled(skill, target, global) {
6588
6909
  const skillPath = getSkillPath(skill.dirName, target, global);
6589
- return (0, import_fs5.existsSync)(skillPath);
6910
+ return (0, import_fs6.existsSync)(skillPath);
6590
6911
  }
6591
6912
  function isSkillOutdated(skill, target, global) {
6592
6913
  const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
6593
- const skillDir = (0, import_path5.join)(baseDir, skill.dirName);
6594
- const skillPath = (0, import_path5.join)(skillDir, target.skillFileName);
6595
- if (!(0, import_fs5.existsSync)(skillPath)) {
6914
+ const skillDir = (0, import_path6.join)(baseDir, skill.dirName);
6915
+ const skillPath = (0, import_path6.join)(skillDir, target.skillFileName);
6916
+ if (!(0, import_fs6.existsSync)(skillPath)) {
6596
6917
  return false;
6597
6918
  }
6598
- const installedContent = (0, import_fs5.readFileSync)(skillPath, "utf-8");
6919
+ const installedContent = (0, import_fs6.readFileSync)(skillPath, "utf-8");
6599
6920
  if (installedContent !== skill.content) {
6600
6921
  return true;
6601
6922
  }
6602
6923
  if ("additionalFiles" in skill && skill.additionalFiles) {
6603
6924
  const additionalFiles = skill.additionalFiles;
6604
6925
  for (const [relativePath, expectedContent] of Object.entries(additionalFiles)) {
6605
- const filePath = (0, import_path5.join)(skillDir, relativePath);
6606
- if (!(0, import_fs5.existsSync)(filePath)) {
6926
+ const filePath = (0, import_path6.join)(skillDir, relativePath);
6927
+ if (!(0, import_fs6.existsSync)(filePath)) {
6607
6928
  return true;
6608
6929
  }
6609
- const installedFileContent = (0, import_fs5.readFileSync)(filePath);
6930
+ const installedFileContent = (0, import_fs6.readFileSync)(filePath);
6610
6931
  if (!installedFileContent.equals(expectedContent)) {
6611
6932
  return true;
6612
6933
  }
@@ -6670,24 +6991,24 @@ function warnLegacySkillStructure(toolPath, legacySkillMdPath) {
6670
6991
  console.error("");
6671
6992
  }
6672
6993
  function scanEditorFolderForSkills(editorPath, skills, sourceType, warnLegacy = true) {
6673
- if (!(0, import_fs5.existsSync)(editorPath)) {
6994
+ if (!(0, import_fs6.existsSync)(editorPath)) {
6674
6995
  return;
6675
6996
  }
6676
- const entries = (0, import_fs5.readdirSync)(editorPath, { withFileTypes: true });
6997
+ const entries = (0, import_fs6.readdirSync)(editorPath, { withFileTypes: true });
6677
6998
  for (const entry of entries) {
6678
6999
  if (EXCLUDED_DIRS2.has(entry.name)) {
6679
7000
  continue;
6680
7001
  }
6681
- const fullPath = (0, import_path5.join)(editorPath, entry.name);
7002
+ const fullPath = (0, import_path6.join)(editorPath, entry.name);
6682
7003
  if (entry.isDirectory()) {
6683
- const skillDir = (0, import_path5.join)(fullPath, SkillsPathConstants.SKILL_DIR);
6684
- const skillMdPath = (0, import_path5.join)(skillDir, SkillsPathConstants.SKILL_FILE);
6685
- const legacySkillMdPath = (0, import_path5.join)(fullPath, SkillsPathConstants.SKILL_FILE);
6686
- if (warnLegacy && !(0, import_fs5.existsSync)(skillMdPath) && (0, import_fs5.existsSync)(legacySkillMdPath)) {
7004
+ const skillDir = (0, import_path6.join)(fullPath, SkillsPathConstants.SKILL_DIR);
7005
+ const skillMdPath = (0, import_path6.join)(skillDir, SkillsPathConstants.SKILL_FILE);
7006
+ const legacySkillMdPath = (0, import_path6.join)(fullPath, SkillsPathConstants.SKILL_FILE);
7007
+ if (warnLegacy && !(0, import_fs6.existsSync)(skillMdPath) && (0, import_fs6.existsSync)(legacySkillMdPath)) {
6687
7008
  warnLegacySkillStructure(fullPath, legacySkillMdPath);
6688
7009
  }
6689
- if ((0, import_fs5.existsSync)(skillMdPath)) {
6690
- const content = (0, import_fs5.readFileSync)(skillMdPath, "utf-8");
7010
+ if ((0, import_fs6.existsSync)(skillMdPath)) {
7011
+ const content = (0, import_fs6.readFileSync)(skillMdPath, "utf-8");
6691
7012
  const frontmatter = parseFrontmatter(content);
6692
7013
  if (frontmatter.internal === true) {
6693
7014
  continue;
@@ -6710,15 +7031,15 @@ function scanEditorFolderForSkills(editorPath, skills, sourceType, warnLegacy =
6710
7031
  function findEditorFolders(basePath, maxDepth = 2) {
6711
7032
  const editorFolders = [];
6712
7033
  function scan(currentPath, depth) {
6713
- if (depth > maxDepth || !(0, import_fs5.existsSync)(currentPath)) {
7034
+ if (depth > maxDepth || !(0, import_fs6.existsSync)(currentPath)) {
6714
7035
  return;
6715
7036
  }
6716
- const entries = (0, import_fs5.readdirSync)(currentPath, { withFileTypes: true });
7037
+ const entries = (0, import_fs6.readdirSync)(currentPath, { withFileTypes: true });
6717
7038
  for (const entry of entries) {
6718
7039
  if (!entry.isDirectory() || EXCLUDED_DIRS2.has(entry.name)) {
6719
7040
  continue;
6720
7041
  }
6721
- const fullPath = (0, import_path5.join)(currentPath, entry.name);
7042
+ const fullPath = (0, import_path6.join)(currentPath, entry.name);
6722
7043
  if (entry.name === "Editor") {
6723
7044
  editorFolders.push(fullPath);
6724
7045
  } else {
@@ -6737,12 +7058,12 @@ function collectProjectSkills(excludedRoots = []) {
6737
7058
  const skills = [];
6738
7059
  const seenNames = /* @__PURE__ */ new Set();
6739
7060
  const searchPaths = [
6740
- (0, import_path5.join)(projectRoot, SkillsPathConstants.ASSETS_DIR),
6741
- (0, import_path5.join)(projectRoot, SkillsPathConstants.PACKAGES_DIR),
6742
- (0, import_path5.join)(projectRoot, SkillsPathConstants.LIBRARY_DIR, SkillsPathConstants.PACKAGE_CACHE_DIR)
7061
+ (0, import_path6.join)(projectRoot, SkillsPathConstants.ASSETS_DIR),
7062
+ (0, import_path6.join)(projectRoot, SkillsPathConstants.PACKAGES_DIR),
7063
+ (0, import_path6.join)(projectRoot, SkillsPathConstants.LIBRARY_DIR, SkillsPathConstants.PACKAGE_CACHE_DIR)
6743
7064
  ];
6744
7065
  for (const searchPath of searchPaths) {
6745
- if (!(0, import_fs5.existsSync)(searchPath)) {
7066
+ if (!(0, import_fs6.existsSync)(searchPath)) {
6746
7067
  continue;
6747
7068
  }
6748
7069
  const editorFolders = findEditorFolders(searchPath, 3);
@@ -6773,26 +7094,26 @@ function getAllSkillStatuses(target, global) {
6773
7094
  }
6774
7095
  function installSkill(skill, target, global) {
6775
7096
  const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
6776
- const skillDir = (0, import_path5.join)(baseDir, skill.dirName);
6777
- const skillPath = (0, import_path5.join)(skillDir, target.skillFileName);
6778
- (0, import_fs5.mkdirSync)(skillDir, { recursive: true });
6779
- (0, import_fs5.writeFileSync)(skillPath, skill.content, "utf-8");
7097
+ const skillDir = (0, import_path6.join)(baseDir, skill.dirName);
7098
+ const skillPath = (0, import_path6.join)(skillDir, target.skillFileName);
7099
+ (0, import_fs6.mkdirSync)(skillDir, { recursive: true });
7100
+ (0, import_fs6.writeFileSync)(skillPath, skill.content, "utf-8");
6780
7101
  if ("additionalFiles" in skill && skill.additionalFiles) {
6781
7102
  const additionalFiles = skill.additionalFiles;
6782
7103
  for (const [relativePath, content] of Object.entries(additionalFiles)) {
6783
- const fullPath = (0, import_path5.join)(skillDir, relativePath);
6784
- (0, import_fs5.mkdirSync)((0, import_path5.dirname)(fullPath), { recursive: true });
6785
- (0, import_fs5.writeFileSync)(fullPath, content);
7104
+ const fullPath = (0, import_path6.join)(skillDir, relativePath);
7105
+ (0, import_fs6.mkdirSync)((0, import_path6.dirname)(fullPath), { recursive: true });
7106
+ (0, import_fs6.writeFileSync)(fullPath, content);
6786
7107
  }
6787
7108
  }
6788
7109
  }
6789
7110
  function uninstallSkill(skill, target, global) {
6790
7111
  const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
6791
- const skillDir = (0, import_path5.join)(baseDir, skill.dirName);
6792
- if (!(0, import_fs5.existsSync)(skillDir)) {
7112
+ const skillDir = (0, import_path6.join)(baseDir, skill.dirName);
7113
+ if (!(0, import_fs6.existsSync)(skillDir)) {
6793
7114
  return false;
6794
7115
  }
6795
- (0, import_fs5.rmSync)(skillDir, { recursive: true, force: true });
7116
+ (0, import_fs6.rmSync)(skillDir, { recursive: true, force: true });
6796
7117
  return true;
6797
7118
  }
6798
7119
  function installAllSkills(target, global) {
@@ -6806,9 +7127,9 @@ function installAllSkills(target, global) {
6806
7127
  };
6807
7128
  const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
6808
7129
  for (const deprecatedName of DEPRECATED_SKILLS) {
6809
- const deprecatedDir = (0, import_path5.join)(baseDir, deprecatedName);
6810
- if ((0, import_fs5.existsSync)(deprecatedDir)) {
6811
- (0, import_fs5.rmSync)(deprecatedDir, { recursive: true, force: true });
7130
+ const deprecatedDir = (0, import_path6.join)(baseDir, deprecatedName);
7131
+ if ((0, import_fs6.existsSync)(deprecatedDir)) {
7132
+ (0, import_fs6.rmSync)(deprecatedDir, { recursive: true, force: true });
6812
7133
  result.deprecatedRemoved++;
6813
7134
  }
6814
7135
  }
@@ -6835,9 +7156,9 @@ function uninstallAllSkills(target, global) {
6835
7156
  const result = { removed: 0, notFound: 0 };
6836
7157
  const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
6837
7158
  for (const deprecatedName of DEPRECATED_SKILLS) {
6838
- const deprecatedDir = (0, import_path5.join)(baseDir, deprecatedName);
6839
- if ((0, import_fs5.existsSync)(deprecatedDir)) {
6840
- (0, import_fs5.rmSync)(deprecatedDir, { recursive: true, force: true });
7159
+ const deprecatedDir = (0, import_path6.join)(baseDir, deprecatedName);
7160
+ if ((0, import_fs6.existsSync)(deprecatedDir)) {
7161
+ (0, import_fs6.rmSync)(deprecatedDir, { recursive: true, force: true });
6841
7162
  result.removed++;
6842
7163
  }
6843
7164
  }
@@ -6866,13 +7187,13 @@ function collectAllSkills() {
6866
7187
  return dedupeSkillsByName([packageSkills, cliOnlySkills, projectSkills]);
6867
7188
  }
6868
7189
  function collectPackageSkillsFromRoot(packageRoot) {
6869
- const mcpToolsRoot = (0, import_path5.join)(
7190
+ const mcpToolsRoot = (0, import_path6.join)(
6870
7191
  packageRoot,
6871
7192
  SkillsPathConstants.EDITOR_DIR,
6872
7193
  SkillsPathConstants.API_DIR,
6873
7194
  SkillsPathConstants.MCP_TOOLS_DIR
6874
7195
  );
6875
- if (!(0, import_fs5.existsSync)(mcpToolsRoot)) {
7196
+ if (!(0, import_fs6.existsSync)(mcpToolsRoot)) {
6876
7197
  return [];
6877
7198
  }
6878
7199
  const skills = [];
@@ -6880,7 +7201,7 @@ function collectPackageSkillsFromRoot(packageRoot) {
6880
7201
  return skills;
6881
7202
  }
6882
7203
  function collectCliOnlySkills() {
6883
- const cliOnlyRoot = (0, import_path5.resolve)(
7204
+ const cliOnlyRoot = (0, import_path6.resolve)(
6884
7205
  __dirname,
6885
7206
  SkillsPathConstants.DIST_PARENT_DIR,
6886
7207
  SkillsPathConstants.SRC_DIR,
@@ -6888,7 +7209,7 @@ function collectCliOnlySkills() {
6888
7209
  SkillsPathConstants.CLI_ONLY_DIR,
6889
7210
  SkillsPathConstants.CLI_ONLY_SUBDIR
6890
7211
  );
6891
- if (!(0, import_fs5.existsSync)(cliOnlyRoot)) {
7212
+ if (!(0, import_fs6.existsSync)(cliOnlyRoot)) {
6892
7213
  return [];
6893
7214
  }
6894
7215
  const skills = [];
@@ -6907,12 +7228,12 @@ function isExcludedFile(fileName) {
6907
7228
  return false;
6908
7229
  }
6909
7230
  function collectSkillFolderFilesRecursive(baseDir, currentDir, additionalFiles) {
6910
- const entries = (0, import_fs5.readdirSync)(currentDir, { withFileTypes: true });
7231
+ const entries = (0, import_fs6.readdirSync)(currentDir, { withFileTypes: true });
6911
7232
  for (const entry of entries) {
6912
7233
  if (isExcludedFile(entry.name)) {
6913
7234
  continue;
6914
7235
  }
6915
- const fullPath = (0, import_path5.join)(currentDir, entry.name);
7236
+ const fullPath = (0, import_path6.join)(currentDir, entry.name);
6916
7237
  const relativePath = fullPath.slice(baseDir.length + 1);
6917
7238
  if (entry.isDirectory()) {
6918
7239
  if (EXCLUDED_DIRS2.has(entry.name)) {
@@ -6923,12 +7244,12 @@ function collectSkillFolderFilesRecursive(baseDir, currentDir, additionalFiles)
6923
7244
  if (entry.name === SkillsPathConstants.SKILL_FILE) {
6924
7245
  continue;
6925
7246
  }
6926
- additionalFiles[relativePath] = (0, import_fs5.readFileSync)(fullPath);
7247
+ additionalFiles[relativePath] = (0, import_fs6.readFileSync)(fullPath);
6927
7248
  }
6928
7249
  }
6929
7250
  }
6930
7251
  function collectSkillFolderFiles(skillDir) {
6931
- if (!(0, import_fs5.existsSync)(skillDir)) {
7252
+ if (!(0, import_fs6.existsSync)(skillDir)) {
6932
7253
  return void 0;
6933
7254
  }
6934
7255
  const additionalFiles = {};
@@ -6951,13 +7272,13 @@ function dedupeSkillsByName(skillGroups) {
6951
7272
  }
6952
7273
  function resolvePackageRoot(projectRoot) {
6953
7274
  const candidates = [];
6954
- candidates.push((0, import_path5.join)(projectRoot, SkillsPathConstants.PACKAGES_DIR, SkillsPathConstants.SRC_DIR));
7275
+ candidates.push((0, import_path6.join)(projectRoot, SkillsPathConstants.PACKAGES_DIR, SkillsPathConstants.SRC_DIR));
6955
7276
  const manifestPaths = resolveManifestPackagePaths(projectRoot);
6956
7277
  for (const manifestPath of manifestPaths) {
6957
7278
  candidates.push(manifestPath);
6958
7279
  }
6959
7280
  for (const packageName of SkillsPathConstants.PACKAGE_NAMES) {
6960
- candidates.push((0, import_path5.join)(projectRoot, SkillsPathConstants.PACKAGES_DIR, packageName));
7281
+ candidates.push((0, import_path6.join)(projectRoot, SkillsPathConstants.PACKAGES_DIR, packageName));
6961
7282
  }
6962
7283
  const directRoot = resolveFirstPackageRoot(candidates);
6963
7284
  if (directRoot) {
@@ -6966,15 +7287,15 @@ function resolvePackageRoot(projectRoot) {
6966
7287
  return resolvePackageCacheRoot(projectRoot);
6967
7288
  }
6968
7289
  function resolveManifestPackagePaths(projectRoot) {
6969
- const manifestPath = (0, import_path5.join)(
7290
+ const manifestPath = (0, import_path6.join)(
6970
7291
  projectRoot,
6971
7292
  SkillsPathConstants.PACKAGES_DIR,
6972
7293
  SkillsPathConstants.MANIFEST_FILE
6973
7294
  );
6974
- if (!(0, import_fs5.existsSync)(manifestPath)) {
7295
+ if (!(0, import_fs6.existsSync)(manifestPath)) {
6975
7296
  return [];
6976
7297
  }
6977
- const manifestContent = (0, import_fs5.readFileSync)(manifestPath, "utf-8");
7298
+ const manifestContent = (0, import_fs6.readFileSync)(manifestPath, "utf-8");
6978
7299
  let manifestJson;
6979
7300
  try {
6980
7301
  manifestJson = JSON.parse(manifestContent);
@@ -7018,10 +7339,10 @@ function resolveDependencyPath(rawPath, projectRoot) {
7018
7339
  if (normalizedPath.startsWith("//")) {
7019
7340
  normalizedPath = normalizedPath.slice(2);
7020
7341
  }
7021
- if ((0, import_path5.isAbsolute)(normalizedPath)) {
7342
+ if ((0, import_path6.isAbsolute)(normalizedPath)) {
7022
7343
  return normalizedPath;
7023
7344
  }
7024
- return (0, import_path5.resolve)(projectRoot, normalizedPath);
7345
+ return (0, import_path6.resolve)(projectRoot, normalizedPath);
7025
7346
  }
7026
7347
  function resolveFirstPackageRoot(candidates) {
7027
7348
  for (const candidate of candidates) {
@@ -7033,15 +7354,15 @@ function resolveFirstPackageRoot(candidates) {
7033
7354
  return null;
7034
7355
  }
7035
7356
  function resolvePackageCacheRoot(projectRoot) {
7036
- const packageCacheDir = (0, import_path5.join)(
7357
+ const packageCacheDir = (0, import_path6.join)(
7037
7358
  projectRoot,
7038
7359
  SkillsPathConstants.LIBRARY_DIR,
7039
7360
  SkillsPathConstants.PACKAGE_CACHE_DIR
7040
7361
  );
7041
- if (!(0, import_fs5.existsSync)(packageCacheDir)) {
7362
+ if (!(0, import_fs6.existsSync)(packageCacheDir)) {
7042
7363
  return null;
7043
7364
  }
7044
- const entries = (0, import_fs5.readdirSync)(packageCacheDir, { withFileTypes: true });
7365
+ const entries = (0, import_fs6.readdirSync)(packageCacheDir, { withFileTypes: true });
7045
7366
  for (const entry of entries) {
7046
7367
  if (!entry.isDirectory()) {
7047
7368
  continue;
@@ -7049,7 +7370,7 @@ function resolvePackageCacheRoot(projectRoot) {
7049
7370
  if (!isTargetPackageCacheDir(entry.name)) {
7050
7371
  continue;
7051
7372
  }
7052
- const candidate = (0, import_path5.join)(packageCacheDir, entry.name);
7373
+ const candidate = (0, import_path6.join)(packageCacheDir, entry.name);
7053
7374
  const resolvedRoot = resolvePackageRootCandidate(candidate);
7054
7375
  if (resolvedRoot) {
7055
7376
  return resolvedRoot;
@@ -7058,26 +7379,26 @@ function resolvePackageCacheRoot(projectRoot) {
7058
7379
  return null;
7059
7380
  }
7060
7381
  function resolvePackageRootCandidate(candidate) {
7061
- if (!(0, import_fs5.existsSync)(candidate)) {
7382
+ if (!(0, import_fs6.existsSync)(candidate)) {
7062
7383
  return null;
7063
7384
  }
7064
- const directToolsPath = (0, import_path5.join)(
7385
+ const directToolsPath = (0, import_path6.join)(
7065
7386
  candidate,
7066
7387
  SkillsPathConstants.EDITOR_DIR,
7067
7388
  SkillsPathConstants.API_DIR,
7068
7389
  SkillsPathConstants.MCP_TOOLS_DIR
7069
7390
  );
7070
- if ((0, import_fs5.existsSync)(directToolsPath)) {
7391
+ if ((0, import_fs6.existsSync)(directToolsPath)) {
7071
7392
  return candidate;
7072
7393
  }
7073
- const nestedRoot = (0, import_path5.join)(candidate, SkillsPathConstants.PACKAGES_DIR, SkillsPathConstants.SRC_DIR);
7074
- const nestedToolsPath = (0, import_path5.join)(
7394
+ const nestedRoot = (0, import_path6.join)(candidate, SkillsPathConstants.PACKAGES_DIR, SkillsPathConstants.SRC_DIR);
7395
+ const nestedToolsPath = (0, import_path6.join)(
7075
7396
  nestedRoot,
7076
7397
  SkillsPathConstants.EDITOR_DIR,
7077
7398
  SkillsPathConstants.API_DIR,
7078
7399
  SkillsPathConstants.MCP_TOOLS_DIR
7079
7400
  );
7080
- if ((0, import_fs5.existsSync)(nestedToolsPath)) {
7401
+ if ((0, import_fs6.existsSync)(nestedToolsPath)) {
7081
7402
  return nestedRoot;
7082
7403
  }
7083
7404
  return null;
@@ -7103,12 +7424,12 @@ function isUnderExcludedRoots(targetPath, excludedRoots) {
7103
7424
  return false;
7104
7425
  }
7105
7426
  function isPathUnder(childPath, parentPath) {
7106
- const resolvedChild = (0, import_path5.resolve)(childPath);
7107
- const resolvedParent = (0, import_path5.resolve)(parentPath);
7427
+ const resolvedChild = (0, import_path6.resolve)(childPath);
7428
+ const resolvedParent = (0, import_path6.resolve)(parentPath);
7108
7429
  if (resolvedChild === resolvedParent) {
7109
7430
  return true;
7110
7431
  }
7111
- return resolvedChild.startsWith(resolvedParent + import_path5.sep);
7432
+ return resolvedChild.startsWith(resolvedParent + import_path6.sep);
7112
7433
  }
7113
7434
 
7114
7435
  // src/skills/target-config.ts
@@ -7263,7 +7584,7 @@ Uninstalling uloop skills (${location})...`);
7263
7584
  }
7264
7585
 
7265
7586
  // src/commands/launch.ts
7266
- var import_path6 = require("path");
7587
+ var import_path7 = require("path");
7267
7588
 
7268
7589
  // node_modules/launch-unity/dist/lib.js
7269
7590
  var import_node_child_process = require("node:child_process");
@@ -7276,7 +7597,7 @@ var import_node_util = require("node:util");
7276
7597
  var import_promises2 = require("node:fs/promises");
7277
7598
  var import_node_fs = require("node:fs");
7278
7599
  var import_node_path = require("node:path");
7279
- var import_node_assert = __toESM(require("node:assert"), 1);
7600
+ var import_node_assert2 = __toESM(require("node:assert"), 1);
7280
7601
  var resolveUnityHubProjectFiles = () => {
7281
7602
  if (process.platform === "darwin") {
7282
7603
  const home = process.env.HOME;
@@ -7447,7 +7768,7 @@ var resolveUnityHubProjectsInfoFile = () => {
7447
7768
  return void 0;
7448
7769
  };
7449
7770
  var parseCliArgs = (cliArgsString) => {
7450
- (0, import_node_assert.default)(cliArgsString !== null && cliArgsString !== void 0, "cliArgsString must not be null");
7771
+ (0, import_node_assert2.default)(cliArgsString !== null && cliArgsString !== void 0, "cliArgsString must not be null");
7451
7772
  const trimmed = cliArgsString.trim();
7452
7773
  if (trimmed.length === 0) {
7453
7774
  return [];
@@ -7503,7 +7824,7 @@ var groupCliArgs = (args) => {
7503
7824
  return groups;
7504
7825
  };
7505
7826
  var getProjectCliArgs = async (projectPath) => {
7506
- (0, import_node_assert.default)(projectPath !== null && projectPath !== void 0, "projectPath must not be null");
7827
+ (0, import_node_assert2.default)(projectPath !== null && projectPath !== void 0, "projectPath must not be null");
7507
7828
  const infoFilePath = resolveUnityHubProjectsInfoFile();
7508
7829
  if (!infoFilePath) {
7509
7830
  logDebug("projectsInfo.json path could not be resolved.");
@@ -7551,6 +7872,8 @@ var PROCESS_LIST_ARGS_MAC = ["-axo", "pid=,command=", "-ww"];
7551
7872
  var WINDOWS_POWERSHELL = "powershell";
7552
7873
  var UNITY_LOCKFILE_NAME = "UnityLockfile";
7553
7874
  var TEMP_DIRECTORY_NAME = "Temp";
7875
+ var ASSETS_DIRECTORY_NAME = "Assets";
7876
+ var RECOVERY_DIRECTORY_NAME = "_Recovery";
7554
7877
  function getUnityVersion(projectPath) {
7555
7878
  const versionFile = (0, import_node_path2.join)(projectPath, "ProjectSettings", "ProjectVersion.txt");
7556
7879
  if (!(0, import_node_fs2.existsSync)(versionFile)) {
@@ -7850,6 +8173,20 @@ async function handleStaleLockfile(projectPath) {
7850
8173
  }
7851
8174
  console.log();
7852
8175
  }
8176
+ async function deleteRecoveryDirectory(projectPath) {
8177
+ const recoveryPath = (0, import_node_path2.join)(projectPath, ASSETS_DIRECTORY_NAME, RECOVERY_DIRECTORY_NAME);
8178
+ if (!(0, import_node_fs2.existsSync)(recoveryPath)) {
8179
+ return;
8180
+ }
8181
+ console.log(`Deleting recovery directory: ${recoveryPath}`);
8182
+ try {
8183
+ await (0, import_promises3.rm)(recoveryPath, { recursive: true, force: true });
8184
+ console.log("Deleted recovery directory.");
8185
+ } catch (error) {
8186
+ const message = error instanceof Error ? error.message : String(error);
8187
+ console.warn(`Failed to delete recovery directory: ${message}`);
8188
+ }
8189
+ }
7853
8190
  var LOCKFILE_POLL_INTERVAL_MS = 100;
7854
8191
  var LOCKFILE_WAIT_TIMEOUT_MS = 5e3;
7855
8192
  var KILL_POLL_INTERVAL_MS = 100;
@@ -8140,6 +8477,9 @@ async function orchestrateLaunch(options) {
8140
8477
  return { action: "focused", projectPath: resolvedProjectPath, pid: runningProcess.pid };
8141
8478
  }
8142
8479
  }
8480
+ if (options.deleteRecovery) {
8481
+ await deleteRecoveryDirectory(resolvedProjectPath);
8482
+ }
8143
8483
  await handleStaleLockfile(resolvedProjectPath);
8144
8484
  const resolved = {
8145
8485
  projectPath: resolvedProjectPath,
@@ -8164,7 +8504,7 @@ async function orchestrateLaunch(options) {
8164
8504
  function registerLaunchCommand(program3) {
8165
8505
  program3.command("launch").description(
8166
8506
  "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"
8167
- ).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) => {
8507
+ ).argument("[project-path]", "Path to Unity project").option("-r, --restart", "Kill running Unity and restart").option("-d, --delete-recovery", "Delete Assets/_Recovery before launch").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) => {
8168
8508
  await runLaunchCommand(projectPath, options);
8169
8509
  });
8170
8510
  }
@@ -8182,13 +8522,14 @@ function parseMaxDepth(value) {
8182
8522
  async function runLaunchCommand(projectPath, options) {
8183
8523
  const maxDepth = parseMaxDepth(options.maxDepth);
8184
8524
  await orchestrateLaunch({
8185
- projectPath: projectPath ? (0, import_path6.resolve)(projectPath) : void 0,
8525
+ projectPath: projectPath ? (0, import_path7.resolve)(projectPath) : void 0,
8186
8526
  searchRoot: process.cwd(),
8187
8527
  searchMaxDepth: maxDepth,
8188
8528
  platform: options.platform,
8189
8529
  unityArgs: [],
8190
8530
  restart: options.restart === true,
8191
8531
  quit: options.quit === true,
8532
+ deleteRecovery: options.deleteRecovery === true,
8192
8533
  addUnityHub: options.addUnityHub === true,
8193
8534
  favoriteUnityHub: options.favorite === true
8194
8535
  });
@@ -8481,7 +8822,7 @@ async function runWithErrorHandling(fn) {
8481
8822
  }
8482
8823
  function detectShell() {
8483
8824
  const shell = process.env["SHELL"] || "";
8484
- const shellName = (0, import_path7.basename)(shell).replace(/\.exe$/i, "");
8825
+ const shellName = (0, import_path8.basename)(shell).replace(/\.exe$/i, "");
8485
8826
  if (shellName === "zsh") {
8486
8827
  return "zsh";
8487
8828
  }
@@ -8496,12 +8837,12 @@ function detectShell() {
8496
8837
  function getShellConfigPath(shell) {
8497
8838
  const home = (0, import_os2.homedir)();
8498
8839
  if (shell === "zsh") {
8499
- return (0, import_path7.join)(home, ".zshrc");
8840
+ return (0, import_path8.join)(home, ".zshrc");
8500
8841
  }
8501
8842
  if (shell === "powershell") {
8502
- return (0, import_path7.join)(home, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
8843
+ return (0, import_path8.join)(home, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
8503
8844
  }
8504
- return (0, import_path7.join)(home, ".bashrc");
8845
+ return (0, import_path8.join)(home, ".bashrc");
8505
8846
  }
8506
8847
  function getCompletionScript(shell) {
8507
8848
  if (shell === "bash") {
@@ -8638,12 +8979,12 @@ function cleanupLockFiles() {
8638
8979
  console.error("Could not find Unity project root.");
8639
8980
  process.exit(1);
8640
8981
  }
8641
- const tempDir = (0, import_path7.join)(projectRoot, "Temp");
8982
+ const tempDir = (0, import_path8.join)(projectRoot, "Temp");
8642
8983
  let cleaned = 0;
8643
8984
  for (const lockFile of LOCK_FILES) {
8644
- const lockPath = (0, import_path7.join)(tempDir, lockFile);
8645
- if ((0, import_fs6.existsSync)(lockPath)) {
8646
- (0, import_fs6.unlinkSync)(lockPath);
8985
+ const lockPath = (0, import_path8.join)(tempDir, lockFile);
8986
+ if ((0, import_fs7.existsSync)(lockPath)) {
8987
+ (0, import_fs7.unlinkSync)(lockPath);
8647
8988
  console.log(`Removed: ${lockFile}`);
8648
8989
  cleaned++;
8649
8990
  }
@@ -8678,13 +9019,13 @@ function handleCompletion(install, shellOverride) {
8678
9019
  return;
8679
9020
  }
8680
9021
  const configPath = getShellConfigPath(shell);
8681
- const configDir = (0, import_path7.dirname)(configPath);
8682
- if (!(0, import_fs6.existsSync)(configDir)) {
8683
- (0, import_fs6.mkdirSync)(configDir, { recursive: true });
9022
+ const configDir = (0, import_path8.dirname)(configPath);
9023
+ if (!(0, import_fs7.existsSync)(configDir)) {
9024
+ (0, import_fs7.mkdirSync)(configDir, { recursive: true });
8684
9025
  }
8685
9026
  let content = "";
8686
- if ((0, import_fs6.existsSync)(configPath)) {
8687
- content = (0, import_fs6.readFileSync)(configPath, "utf-8");
9027
+ if ((0, import_fs7.existsSync)(configPath)) {
9028
+ content = (0, import_fs7.readFileSync)(configPath, "utf-8");
8688
9029
  content = content.replace(
8689
9030
  /\n?# >>> uloop completion >>>[\s\S]*?# <<< uloop completion <<<\n?/g,
8690
9031
  ""
@@ -8698,7 +9039,7 @@ ${startMarker}
8698
9039
  ${script}
8699
9040
  ${endMarker}
8700
9041
  `;
8701
- (0, import_fs6.writeFileSync)(configPath, content + lineToAdd, "utf-8");
9042
+ (0, import_fs7.writeFileSync)(configPath, content + lineToAdd, "utf-8");
8702
9043
  } else {
8703
9044
  const evalLine = `eval "$(uloop completion --shell ${shell})"`;
8704
9045
  const lineToAdd = `
@@ -8706,7 +9047,7 @@ ${startMarker}
8706
9047
  ${evalLine}
8707
9048
  ${endMarker}
8708
9049
  `;
8709
- (0, import_fs6.writeFileSync)(configPath, content + lineToAdd, "utf-8");
9050
+ (0, import_fs7.writeFileSync)(configPath, content + lineToAdd, "utf-8");
8710
9051
  }
8711
9052
  console.log(`Completion installed to ${configPath}`);
8712
9053
  if (shell === "powershell") {
@@ -8760,12 +9101,29 @@ function shouldSkipAutoSync(cmdName, args) {
8760
9101
  }
8761
9102
  return args.some((arg) => NO_SYNC_FLAGS.includes(arg));
8762
9103
  }
9104
+ function extractSyncGlobalOptions(args) {
9105
+ for (let i = 0; i < args.length; i++) {
9106
+ const arg = args[i];
9107
+ if (arg === "--port" || arg === "-p") {
9108
+ const nextArg = args[i + 1];
9109
+ if (nextArg !== void 0 && !nextArg.startsWith("-")) {
9110
+ return { port: nextArg };
9111
+ }
9112
+ continue;
9113
+ }
9114
+ if (arg.startsWith("--port=")) {
9115
+ return { port: arg.slice("--port=".length) };
9116
+ }
9117
+ }
9118
+ return {};
9119
+ }
8763
9120
  async function main() {
8764
9121
  if (handleCompletionOptions()) {
8765
9122
  return;
8766
9123
  }
8767
9124
  const args = process.argv.slice(2);
8768
9125
  const cmdName = args.find((arg) => !arg.startsWith("-"));
9126
+ const syncGlobalOptions = extractSyncGlobalOptions(args);
8769
9127
  if (!shouldSkipAutoSync(cmdName, args)) {
8770
9128
  const cachedVersion = loadToolsCache().version;
8771
9129
  if (hasCacheFile() && cachedVersion !== VERSION) {
@@ -8773,7 +9131,7 @@ async function main() {
8773
9131
  `\x1B[33mCache outdated (${cachedVersion} \u2192 ${VERSION}). Syncing tools from Unity...\x1B[0m`
8774
9132
  );
8775
9133
  try {
8776
- await syncTools({});
9134
+ await syncTools(syncGlobalOptions);
8777
9135
  console.log("\x1B[32m\u2713 Tools synced successfully.\x1B[0m\n");
8778
9136
  } catch (error) {
8779
9137
  const message = error instanceof Error ? error.message : String(error);
@@ -8795,7 +9153,7 @@ async function main() {
8795
9153
  if (cmdName && !commandExists(cmdName)) {
8796
9154
  console.log(`\x1B[33mUnknown command '${cmdName}'. Syncing tools from Unity...\x1B[0m`);
8797
9155
  try {
8798
- await syncTools({});
9156
+ await syncTools(syncGlobalOptions);
8799
9157
  const newCache = loadToolsCache();
8800
9158
  const tool = newCache.tools.find((t) => t.name === cmdName);
8801
9159
  if (tool) {