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.
- package/README.md +3 -0
- package/dist/cli.bundle.cjs +476 -118
- package/dist/cli.bundle.cjs.map +4 -4
- package/package.json +4 -4
- package/src/__tests__/cli-e2e.test.ts +147 -3
- package/src/__tests__/execute-tool.test.ts +31 -0
- package/src/cli.ts +22 -2
- package/src/commands/launch.ts +3 -0
- package/src/compile-helpers.ts +291 -0
- package/src/default-tools.json +5 -1
- package/src/direct-unity-client.ts +22 -3
- package/src/execute-tool.ts +170 -10
- package/src/version.ts +1 -1
package/dist/cli.bundle.cjs
CHANGED
|
@@ -5383,8 +5383,8 @@ var require_semver2 = __commonJS({
|
|
|
5383
5383
|
});
|
|
5384
5384
|
|
|
5385
5385
|
// src/cli.ts
|
|
5386
|
-
var
|
|
5387
|
-
var
|
|
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
|
|
5411
|
-
var
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
6293
|
-
|
|
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,
|
|
6334
|
-
if ((0,
|
|
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,
|
|
6338
|
-
if ((0,
|
|
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,
|
|
6342
|
-
if ((0,
|
|
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
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
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
|
-
|
|
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
|
|
6519
|
-
var
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
6594
|
-
const skillPath = (0,
|
|
6595
|
-
if (!(0,
|
|
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,
|
|
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,
|
|
6606
|
-
if (!(0,
|
|
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,
|
|
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,
|
|
6994
|
+
if (!(0, import_fs6.existsSync)(editorPath)) {
|
|
6674
6995
|
return;
|
|
6675
6996
|
}
|
|
6676
|
-
const entries = (0,
|
|
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,
|
|
7002
|
+
const fullPath = (0, import_path6.join)(editorPath, entry.name);
|
|
6682
7003
|
if (entry.isDirectory()) {
|
|
6683
|
-
const skillDir = (0,
|
|
6684
|
-
const skillMdPath = (0,
|
|
6685
|
-
const legacySkillMdPath = (0,
|
|
6686
|
-
if (warnLegacy && !(0,
|
|
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,
|
|
6690
|
-
const content = (0,
|
|
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,
|
|
7034
|
+
if (depth > maxDepth || !(0, import_fs6.existsSync)(currentPath)) {
|
|
6714
7035
|
return;
|
|
6715
7036
|
}
|
|
6716
|
-
const entries = (0,
|
|
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,
|
|
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,
|
|
6741
|
-
(0,
|
|
6742
|
-
(0,
|
|
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,
|
|
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,
|
|
6777
|
-
const skillPath = (0,
|
|
6778
|
-
(0,
|
|
6779
|
-
(0,
|
|
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,
|
|
6784
|
-
(0,
|
|
6785
|
-
(0,
|
|
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,
|
|
6792
|
-
if (!(0,
|
|
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,
|
|
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,
|
|
6810
|
-
if ((0,
|
|
6811
|
-
(0,
|
|
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,
|
|
6839
|
-
if ((0,
|
|
6840
|
-
(0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
7247
|
+
additionalFiles[relativePath] = (0, import_fs6.readFileSync)(fullPath);
|
|
6927
7248
|
}
|
|
6928
7249
|
}
|
|
6929
7250
|
}
|
|
6930
7251
|
function collectSkillFolderFiles(skillDir) {
|
|
6931
|
-
if (!(0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
7295
|
+
if (!(0, import_fs6.existsSync)(manifestPath)) {
|
|
6975
7296
|
return [];
|
|
6976
7297
|
}
|
|
6977
|
-
const manifestContent = (0,
|
|
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,
|
|
7342
|
+
if ((0, import_path6.isAbsolute)(normalizedPath)) {
|
|
7022
7343
|
return normalizedPath;
|
|
7023
7344
|
}
|
|
7024
|
-
return (0,
|
|
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,
|
|
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,
|
|
7362
|
+
if (!(0, import_fs6.existsSync)(packageCacheDir)) {
|
|
7042
7363
|
return null;
|
|
7043
7364
|
}
|
|
7044
|
-
const entries = (0,
|
|
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,
|
|
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,
|
|
7382
|
+
if (!(0, import_fs6.existsSync)(candidate)) {
|
|
7062
7383
|
return null;
|
|
7063
7384
|
}
|
|
7064
|
-
const directToolsPath = (0,
|
|
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,
|
|
7391
|
+
if ((0, import_fs6.existsSync)(directToolsPath)) {
|
|
7071
7392
|
return candidate;
|
|
7072
7393
|
}
|
|
7073
|
-
const nestedRoot = (0,
|
|
7074
|
-
const nestedToolsPath = (0,
|
|
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,
|
|
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,
|
|
7107
|
-
const resolvedParent = (0,
|
|
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 +
|
|
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
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
8840
|
+
return (0, import_path8.join)(home, ".zshrc");
|
|
8500
8841
|
}
|
|
8501
8842
|
if (shell === "powershell") {
|
|
8502
|
-
return (0,
|
|
8843
|
+
return (0, import_path8.join)(home, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
|
|
8503
8844
|
}
|
|
8504
|
-
return (0,
|
|
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,
|
|
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,
|
|
8645
|
-
if ((0,
|
|
8646
|
-
(0,
|
|
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,
|
|
8682
|
-
if (!(0,
|
|
8683
|
-
(0,
|
|
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,
|
|
8687
|
-
content = (0,
|
|
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,
|
|
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,
|
|
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) {
|