uloop-cli 0.64.1 → 0.66.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 +567 -147
- package/dist/cli.bundle.cjs.map +4 -4
- package/package.json +5 -5
- package/src/__tests__/execute-tool.test.ts +31 -0
- package/src/__tests__/port-resolver.test.ts +31 -1
- package/src/cli.ts +54 -8
- package/src/commands/focus-window.ts +20 -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 +184 -19
- package/src/port-resolver.ts +42 -4
- package/src/project-root.ts +2 -2
- package/src/skills/skill-definitions/cli-only/uloop-focus-window/SKILL.md +7 -0
- 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
|
|
@@ -5486,13 +5486,13 @@ var DirectUnityClient = class {
|
|
|
5486
5486
|
requestId = 0;
|
|
5487
5487
|
receiveBuffer = Buffer.alloc(0);
|
|
5488
5488
|
async connect() {
|
|
5489
|
-
return new Promise((
|
|
5489
|
+
return new Promise((resolve6, reject) => {
|
|
5490
5490
|
this.socket = new net.Socket();
|
|
5491
5491
|
this.socket.on("error", (error) => {
|
|
5492
5492
|
reject(new Error(`Connection error: ${error.message}`));
|
|
5493
5493
|
});
|
|
5494
5494
|
this.socket.connect(this.port, this.host, () => {
|
|
5495
|
-
|
|
5495
|
+
resolve6();
|
|
5496
5496
|
});
|
|
5497
5497
|
});
|
|
5498
5498
|
}
|
|
@@ -5508,9 +5508,16 @@ var DirectUnityClient = class {
|
|
|
5508
5508
|
};
|
|
5509
5509
|
const requestJson = JSON.stringify(request);
|
|
5510
5510
|
const framedMessage = createFrame(requestJson);
|
|
5511
|
-
return new Promise((
|
|
5511
|
+
return new Promise((resolve6, 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,17 +5538,26 @@ 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) {
|
|
5539
5545
|
reject(new Error(`Unity error: ${response.error.message}`));
|
|
5540
5546
|
return;
|
|
5541
5547
|
}
|
|
5542
|
-
|
|
5548
|
+
resolve6(response.result);
|
|
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"));
|
|
5543
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
|
}
|
|
@@ -5743,13 +5759,41 @@ function resolvePortFromUnitySettings(settings) {
|
|
|
5743
5759
|
}
|
|
5744
5760
|
return null;
|
|
5745
5761
|
}
|
|
5746
|
-
|
|
5762
|
+
function validateProjectPath(projectPath) {
|
|
5763
|
+
const resolved = (0, import_path2.resolve)(projectPath);
|
|
5764
|
+
if (!(0, import_fs2.existsSync)(resolved)) {
|
|
5765
|
+
throw new Error(`Path does not exist: ${resolved}`);
|
|
5766
|
+
}
|
|
5767
|
+
if (!isUnityProject(resolved)) {
|
|
5768
|
+
throw new Error(`Not a Unity project (Assets/ or ProjectSettings/ not found): ${resolved}`);
|
|
5769
|
+
}
|
|
5770
|
+
if (!hasUloopInstalled(resolved)) {
|
|
5771
|
+
throw new Error(
|
|
5772
|
+
`uLoopMCP is not installed in this project (UserSettings/UnityMcpSettings.json not found): ${resolved}`
|
|
5773
|
+
);
|
|
5774
|
+
}
|
|
5775
|
+
return resolved;
|
|
5776
|
+
}
|
|
5777
|
+
async function resolveUnityPort(explicitPort, projectPath) {
|
|
5778
|
+
if (explicitPort !== void 0 && projectPath !== void 0) {
|
|
5779
|
+
throw new Error("Cannot specify both --port and --project-path. Use one or the other.");
|
|
5780
|
+
}
|
|
5747
5781
|
if (explicitPort !== void 0) {
|
|
5748
5782
|
return explicitPort;
|
|
5749
5783
|
}
|
|
5784
|
+
if (projectPath !== void 0) {
|
|
5785
|
+
const resolved = validateProjectPath(projectPath);
|
|
5786
|
+
const settingsPort2 = await readPortFromSettings(resolved);
|
|
5787
|
+
if (settingsPort2 !== null) {
|
|
5788
|
+
return settingsPort2;
|
|
5789
|
+
}
|
|
5790
|
+
return DEFAULT_PORT;
|
|
5791
|
+
}
|
|
5750
5792
|
const projectRoot = findUnityProjectRoot();
|
|
5751
5793
|
if (projectRoot === null) {
|
|
5752
|
-
throw new Error(
|
|
5794
|
+
throw new Error(
|
|
5795
|
+
"Unity project not found. Use --port or --project-path option to specify the target."
|
|
5796
|
+
);
|
|
5753
5797
|
}
|
|
5754
5798
|
const settingsPort = await readPortFromSettings(projectRoot);
|
|
5755
5799
|
if (settingsPort !== null) {
|
|
@@ -5783,7 +5827,7 @@ var import_path3 = require("path");
|
|
|
5783
5827
|
|
|
5784
5828
|
// src/default-tools.json
|
|
5785
5829
|
var default_tools_default = {
|
|
5786
|
-
version: "0.
|
|
5830
|
+
version: "0.66.0",
|
|
5787
5831
|
tools: [
|
|
5788
5832
|
{
|
|
5789
5833
|
name: "compile",
|
|
@@ -5794,6 +5838,10 @@ var default_tools_default = {
|
|
|
5794
5838
|
ForceRecompile: {
|
|
5795
5839
|
type: "boolean",
|
|
5796
5840
|
description: "Force full recompilation"
|
|
5841
|
+
},
|
|
5842
|
+
WaitForDomainReload: {
|
|
5843
|
+
type: "boolean",
|
|
5844
|
+
description: "Wait for domain reload completion before returning"
|
|
5797
5845
|
}
|
|
5798
5846
|
}
|
|
5799
5847
|
}
|
|
@@ -6227,7 +6275,7 @@ function getCachedServerVersion() {
|
|
|
6227
6275
|
}
|
|
6228
6276
|
|
|
6229
6277
|
// src/version.ts
|
|
6230
|
-
var VERSION = "0.
|
|
6278
|
+
var VERSION = "0.66.0";
|
|
6231
6279
|
|
|
6232
6280
|
// src/spinner.ts
|
|
6233
6281
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
@@ -6261,6 +6309,206 @@ function createSpinner(initialMessage) {
|
|
|
6261
6309
|
};
|
|
6262
6310
|
}
|
|
6263
6311
|
|
|
6312
|
+
// src/compile-helpers.ts
|
|
6313
|
+
var import_node_assert = __toESM(require("node:assert"), 1);
|
|
6314
|
+
var import_fs4 = require("fs");
|
|
6315
|
+
var net2 = __toESM(require("net"), 1);
|
|
6316
|
+
var import_path4 = require("path");
|
|
6317
|
+
var SAFE_REQUEST_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
6318
|
+
var COMPILE_FORCE_RECOMPILE_ARG_KEYS = [
|
|
6319
|
+
"ForceRecompile",
|
|
6320
|
+
"forceRecompile",
|
|
6321
|
+
"force_recompile",
|
|
6322
|
+
"force-recompile"
|
|
6323
|
+
];
|
|
6324
|
+
var COMPILE_WAIT_FOR_DOMAIN_RELOAD_ARG_KEYS = [
|
|
6325
|
+
"WaitForDomainReload",
|
|
6326
|
+
"waitForDomainReload",
|
|
6327
|
+
"wait_for_domain_reload",
|
|
6328
|
+
"wait-for-domain-reload"
|
|
6329
|
+
];
|
|
6330
|
+
var LOCK_GRACE_PERIOD_MS = 500;
|
|
6331
|
+
var READINESS_CHECK_TIMEOUT_MS = 3e3;
|
|
6332
|
+
var DEFAULT_HOST2 = "127.0.0.1";
|
|
6333
|
+
var CONTENT_LENGTH_HEADER2 = "Content-Length:";
|
|
6334
|
+
var HEADER_SEPARATOR2 = "\r\n\r\n";
|
|
6335
|
+
function toBoolean(value) {
|
|
6336
|
+
if (typeof value === "boolean") {
|
|
6337
|
+
return value;
|
|
6338
|
+
}
|
|
6339
|
+
if (typeof value === "string") {
|
|
6340
|
+
return value.toLowerCase() === "true";
|
|
6341
|
+
}
|
|
6342
|
+
return false;
|
|
6343
|
+
}
|
|
6344
|
+
function getCompileBooleanArg(args, keys) {
|
|
6345
|
+
for (const key of keys) {
|
|
6346
|
+
if (!(key in args)) {
|
|
6347
|
+
continue;
|
|
6348
|
+
}
|
|
6349
|
+
return toBoolean(args[key]);
|
|
6350
|
+
}
|
|
6351
|
+
return false;
|
|
6352
|
+
}
|
|
6353
|
+
function resolveCompileExecutionOptions(args) {
|
|
6354
|
+
return {
|
|
6355
|
+
forceRecompile: getCompileBooleanArg(args, COMPILE_FORCE_RECOMPILE_ARG_KEYS),
|
|
6356
|
+
waitForDomainReload: getCompileBooleanArg(args, COMPILE_WAIT_FOR_DOMAIN_RELOAD_ARG_KEYS)
|
|
6357
|
+
};
|
|
6358
|
+
}
|
|
6359
|
+
function createCompileRequestId() {
|
|
6360
|
+
const timestamp = Date.now();
|
|
6361
|
+
const randomToken = Math.floor(Math.random() * 1e6).toString().padStart(6, "0");
|
|
6362
|
+
return `compile_${timestamp}_${randomToken}`;
|
|
6363
|
+
}
|
|
6364
|
+
function ensureCompileRequestId(args) {
|
|
6365
|
+
const existingRequestId = args["RequestId"];
|
|
6366
|
+
if (typeof existingRequestId === "string" && existingRequestId.length > 0) {
|
|
6367
|
+
if (SAFE_REQUEST_ID_PATTERN.test(existingRequestId)) {
|
|
6368
|
+
return existingRequestId;
|
|
6369
|
+
}
|
|
6370
|
+
}
|
|
6371
|
+
const requestId = createCompileRequestId();
|
|
6372
|
+
args["RequestId"] = requestId;
|
|
6373
|
+
return requestId;
|
|
6374
|
+
}
|
|
6375
|
+
function getCompileResultFilePath(projectRoot, requestId) {
|
|
6376
|
+
(0, import_node_assert.default)(
|
|
6377
|
+
SAFE_REQUEST_ID_PATTERN.test(requestId),
|
|
6378
|
+
`requestId contains unsafe characters: '${requestId}'`
|
|
6379
|
+
);
|
|
6380
|
+
return (0, import_path4.join)(projectRoot, "Temp", "uLoopMCP", "compile-results", `${requestId}.json`);
|
|
6381
|
+
}
|
|
6382
|
+
function isUnityBusyByLockFiles(projectRoot) {
|
|
6383
|
+
const compilingLockPath = (0, import_path4.join)(projectRoot, "Temp", "compiling.lock");
|
|
6384
|
+
if ((0, import_fs4.existsSync)(compilingLockPath)) {
|
|
6385
|
+
return true;
|
|
6386
|
+
}
|
|
6387
|
+
const domainReloadLockPath = (0, import_path4.join)(projectRoot, "Temp", "domainreload.lock");
|
|
6388
|
+
if ((0, import_fs4.existsSync)(domainReloadLockPath)) {
|
|
6389
|
+
return true;
|
|
6390
|
+
}
|
|
6391
|
+
const serverStartingLockPath = (0, import_path4.join)(projectRoot, "Temp", "serverstarting.lock");
|
|
6392
|
+
return (0, import_fs4.existsSync)(serverStartingLockPath);
|
|
6393
|
+
}
|
|
6394
|
+
function stripUtf8Bom(content) {
|
|
6395
|
+
if (content.charCodeAt(0) === 65279) {
|
|
6396
|
+
return content.slice(1);
|
|
6397
|
+
}
|
|
6398
|
+
return content;
|
|
6399
|
+
}
|
|
6400
|
+
function tryReadCompileResult(projectRoot, requestId) {
|
|
6401
|
+
const resultFilePath = getCompileResultFilePath(projectRoot, requestId);
|
|
6402
|
+
if (!(0, import_fs4.existsSync)(resultFilePath)) {
|
|
6403
|
+
return void 0;
|
|
6404
|
+
}
|
|
6405
|
+
try {
|
|
6406
|
+
const content = (0, import_fs4.readFileSync)(resultFilePath, "utf-8");
|
|
6407
|
+
const parsed = JSON.parse(stripUtf8Bom(content));
|
|
6408
|
+
return parsed;
|
|
6409
|
+
} catch {
|
|
6410
|
+
return void 0;
|
|
6411
|
+
}
|
|
6412
|
+
}
|
|
6413
|
+
function canSendRequestToUnity(port) {
|
|
6414
|
+
return new Promise((resolve6) => {
|
|
6415
|
+
const socket = new net2.Socket();
|
|
6416
|
+
const timer = setTimeout(() => {
|
|
6417
|
+
socket.destroy();
|
|
6418
|
+
resolve6(false);
|
|
6419
|
+
}, READINESS_CHECK_TIMEOUT_MS);
|
|
6420
|
+
const cleanup = () => {
|
|
6421
|
+
clearTimeout(timer);
|
|
6422
|
+
socket.destroy();
|
|
6423
|
+
};
|
|
6424
|
+
socket.connect(port, DEFAULT_HOST2, () => {
|
|
6425
|
+
const rpcRequest = JSON.stringify({
|
|
6426
|
+
jsonrpc: "2.0",
|
|
6427
|
+
method: "get-tool-details",
|
|
6428
|
+
params: { IncludeDevelopmentOnly: false },
|
|
6429
|
+
id: 0
|
|
6430
|
+
});
|
|
6431
|
+
const contentLength = Buffer.byteLength(rpcRequest, "utf8");
|
|
6432
|
+
const frame = `${CONTENT_LENGTH_HEADER2} ${contentLength}${HEADER_SEPARATOR2}${rpcRequest}`;
|
|
6433
|
+
socket.write(frame);
|
|
6434
|
+
});
|
|
6435
|
+
let buffer = Buffer.alloc(0);
|
|
6436
|
+
socket.on("data", (chunk) => {
|
|
6437
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
6438
|
+
const sepIndex = buffer.indexOf(HEADER_SEPARATOR2);
|
|
6439
|
+
if (sepIndex !== -1) {
|
|
6440
|
+
cleanup();
|
|
6441
|
+
resolve6(true);
|
|
6442
|
+
}
|
|
6443
|
+
});
|
|
6444
|
+
socket.on("error", () => {
|
|
6445
|
+
cleanup();
|
|
6446
|
+
resolve6(false);
|
|
6447
|
+
});
|
|
6448
|
+
socket.on("close", () => {
|
|
6449
|
+
clearTimeout(timer);
|
|
6450
|
+
resolve6(false);
|
|
6451
|
+
});
|
|
6452
|
+
});
|
|
6453
|
+
}
|
|
6454
|
+
function sleep(ms) {
|
|
6455
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
6456
|
+
}
|
|
6457
|
+
async function waitForCompileCompletion(options) {
|
|
6458
|
+
const startTime = Date.now();
|
|
6459
|
+
let idleSinceTimestamp = null;
|
|
6460
|
+
while (Date.now() - startTime < options.timeoutMs) {
|
|
6461
|
+
const result = tryReadCompileResult(options.projectRoot, options.requestId);
|
|
6462
|
+
const isBusy = isUnityBusyByLockFiles(options.projectRoot);
|
|
6463
|
+
if (result !== void 0 && !isBusy) {
|
|
6464
|
+
const now = Date.now();
|
|
6465
|
+
if (idleSinceTimestamp === null) {
|
|
6466
|
+
idleSinceTimestamp = now;
|
|
6467
|
+
}
|
|
6468
|
+
const idleDuration = now - idleSinceTimestamp;
|
|
6469
|
+
if (idleDuration >= LOCK_GRACE_PERIOD_MS) {
|
|
6470
|
+
if (options.unityPort !== void 0) {
|
|
6471
|
+
const isReady = await canSendRequestToUnity(options.unityPort);
|
|
6472
|
+
if (isReady) {
|
|
6473
|
+
return { outcome: "completed", result };
|
|
6474
|
+
}
|
|
6475
|
+
} else if (options.isUnityReadyWhenIdle) {
|
|
6476
|
+
const isReady = await options.isUnityReadyWhenIdle();
|
|
6477
|
+
if (isReady) {
|
|
6478
|
+
return { outcome: "completed", result };
|
|
6479
|
+
}
|
|
6480
|
+
} else {
|
|
6481
|
+
return { outcome: "completed", result };
|
|
6482
|
+
}
|
|
6483
|
+
}
|
|
6484
|
+
} else {
|
|
6485
|
+
idleSinceTimestamp = null;
|
|
6486
|
+
}
|
|
6487
|
+
await sleep(options.pollIntervalMs);
|
|
6488
|
+
}
|
|
6489
|
+
const lastResult = tryReadCompileResult(options.projectRoot, options.requestId);
|
|
6490
|
+
if (lastResult !== void 0 && !isUnityBusyByLockFiles(options.projectRoot)) {
|
|
6491
|
+
await sleep(LOCK_GRACE_PERIOD_MS);
|
|
6492
|
+
if (isUnityBusyByLockFiles(options.projectRoot)) {
|
|
6493
|
+
return { outcome: "timed_out" };
|
|
6494
|
+
}
|
|
6495
|
+
if (options.unityPort !== void 0) {
|
|
6496
|
+
const isReady = await canSendRequestToUnity(options.unityPort);
|
|
6497
|
+
if (isReady) {
|
|
6498
|
+
return { outcome: "completed", result: lastResult };
|
|
6499
|
+
}
|
|
6500
|
+
} else if (options.isUnityReadyWhenIdle) {
|
|
6501
|
+
const isReady = await options.isUnityReadyWhenIdle();
|
|
6502
|
+
if (isReady) {
|
|
6503
|
+
return { outcome: "completed", result: lastResult };
|
|
6504
|
+
}
|
|
6505
|
+
} else {
|
|
6506
|
+
return { outcome: "completed", result: lastResult };
|
|
6507
|
+
}
|
|
6508
|
+
}
|
|
6509
|
+
return { outcome: "timed_out" };
|
|
6510
|
+
}
|
|
6511
|
+
|
|
6264
6512
|
// src/execute-tool.ts
|
|
6265
6513
|
function suppressStdinEcho() {
|
|
6266
6514
|
if (!process.stdin.isTTY) {
|
|
@@ -6287,10 +6535,23 @@ function suppressStdinEcho() {
|
|
|
6287
6535
|
rl.close();
|
|
6288
6536
|
};
|
|
6289
6537
|
}
|
|
6538
|
+
function stripInternalFields(result) {
|
|
6539
|
+
const cleaned = { ...result };
|
|
6540
|
+
delete cleaned["ProjectRoot"];
|
|
6541
|
+
return cleaned;
|
|
6542
|
+
}
|
|
6290
6543
|
var RETRY_DELAY_MS = 500;
|
|
6291
6544
|
var MAX_RETRIES = 3;
|
|
6292
|
-
|
|
6293
|
-
|
|
6545
|
+
var COMPILE_WAIT_TIMEOUT_MS = 9e4;
|
|
6546
|
+
var COMPILE_WAIT_POLL_INTERVAL_MS = 100;
|
|
6547
|
+
function getCompileExecutionOptions(toolName, params) {
|
|
6548
|
+
if (toolName !== "compile") {
|
|
6549
|
+
return {
|
|
6550
|
+
forceRecompile: false,
|
|
6551
|
+
waitForDomainReload: false
|
|
6552
|
+
};
|
|
6553
|
+
}
|
|
6554
|
+
return resolveCompileExecutionOptions(params);
|
|
6294
6555
|
}
|
|
6295
6556
|
function isRetryableError(error) {
|
|
6296
6557
|
if (!(error instanceof Error)) {
|
|
@@ -6299,6 +6560,13 @@ function isRetryableError(error) {
|
|
|
6299
6560
|
const message = error.message;
|
|
6300
6561
|
return message.includes("ECONNREFUSED") || message.includes("EADDRNOTAVAIL") || message === "UNITY_NO_RESPONSE";
|
|
6301
6562
|
}
|
|
6563
|
+
function isTransportDisconnectError(error) {
|
|
6564
|
+
if (!(error instanceof Error)) {
|
|
6565
|
+
return false;
|
|
6566
|
+
}
|
|
6567
|
+
const message = error.message;
|
|
6568
|
+
return message === "UNITY_NO_RESPONSE" || message.startsWith("Connection lost:");
|
|
6569
|
+
}
|
|
6302
6570
|
function isVersionOlder(v1, v2) {
|
|
6303
6571
|
const parsed1 = semver.valid(v1);
|
|
6304
6572
|
const parsed2 = semver.valid(v2);
|
|
@@ -6325,21 +6593,21 @@ function checkServerVersion(result) {
|
|
|
6325
6593
|
printVersionWarning(VERSION, serverVersion);
|
|
6326
6594
|
}
|
|
6327
6595
|
}
|
|
6328
|
-
function checkUnityBusyState() {
|
|
6329
|
-
const projectRoot = findUnityProjectRoot();
|
|
6596
|
+
function checkUnityBusyState(projectPath) {
|
|
6597
|
+
const projectRoot = projectPath !== void 0 ? validateProjectPath(projectPath) : findUnityProjectRoot();
|
|
6330
6598
|
if (projectRoot === null) {
|
|
6331
6599
|
return;
|
|
6332
6600
|
}
|
|
6333
|
-
const compilingLock = (0,
|
|
6334
|
-
if ((0,
|
|
6601
|
+
const compilingLock = (0, import_path5.join)(projectRoot, "Temp", "compiling.lock");
|
|
6602
|
+
if ((0, import_fs5.existsSync)(compilingLock)) {
|
|
6335
6603
|
throw new Error("UNITY_COMPILING");
|
|
6336
6604
|
}
|
|
6337
|
-
const domainReloadLock = (0,
|
|
6338
|
-
if ((0,
|
|
6605
|
+
const domainReloadLock = (0, import_path5.join)(projectRoot, "Temp", "domainreload.lock");
|
|
6606
|
+
if ((0, import_fs5.existsSync)(domainReloadLock)) {
|
|
6339
6607
|
throw new Error("UNITY_DOMAIN_RELOAD");
|
|
6340
6608
|
}
|
|
6341
|
-
const serverStartingLock = (0,
|
|
6342
|
-
if ((0,
|
|
6609
|
+
const serverStartingLock = (0, import_path5.join)(projectRoot, "Temp", "serverstarting.lock");
|
|
6610
|
+
if ((0, import_fs5.existsSync)(serverStartingLock)) {
|
|
6343
6611
|
throw new Error("UNITY_SERVER_STARTING");
|
|
6344
6612
|
}
|
|
6345
6613
|
}
|
|
@@ -6352,28 +6620,48 @@ async function executeToolCommand(toolName, params, globalOptions) {
|
|
|
6352
6620
|
}
|
|
6353
6621
|
portNumber = parsed;
|
|
6354
6622
|
}
|
|
6355
|
-
const port = await resolveUnityPort(portNumber);
|
|
6623
|
+
const port = await resolveUnityPort(portNumber, globalOptions.projectPath);
|
|
6624
|
+
const compileOptions = getCompileExecutionOptions(toolName, params);
|
|
6625
|
+
const shouldWaitForDomainReload = compileOptions.waitForDomainReload;
|
|
6626
|
+
const compileRequestId = shouldWaitForDomainReload ? ensureCompileRequestId(params) : void 0;
|
|
6356
6627
|
const restoreStdin = suppressStdinEcho();
|
|
6357
6628
|
const spinner = createSpinner("Connecting to Unity...");
|
|
6358
6629
|
let lastError;
|
|
6630
|
+
let immediateResult;
|
|
6631
|
+
const projectRoot = globalOptions.projectPath !== void 0 ? validateProjectPath(globalOptions.projectPath) : findUnityProjectRoot();
|
|
6632
|
+
let requestDispatched = false;
|
|
6359
6633
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
6360
|
-
checkUnityBusyState();
|
|
6634
|
+
checkUnityBusyState(globalOptions.projectPath);
|
|
6361
6635
|
const client = new DirectUnityClient(port);
|
|
6362
6636
|
try {
|
|
6363
6637
|
await client.connect();
|
|
6364
6638
|
spinner.update(`Executing ${toolName}...`);
|
|
6639
|
+
requestDispatched = true;
|
|
6365
6640
|
const result = await client.sendRequest(toolName, params);
|
|
6366
6641
|
if (result === void 0 || result === null) {
|
|
6367
6642
|
throw new Error("UNITY_NO_RESPONSE");
|
|
6368
6643
|
}
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6644
|
+
immediateResult = result;
|
|
6645
|
+
if (!shouldWaitForDomainReload) {
|
|
6646
|
+
spinner.stop();
|
|
6647
|
+
restoreStdin();
|
|
6648
|
+
checkServerVersion(result);
|
|
6649
|
+
console.log(JSON.stringify(stripInternalFields(result), null, 2));
|
|
6650
|
+
return;
|
|
6651
|
+
}
|
|
6652
|
+
break;
|
|
6374
6653
|
} catch (error) {
|
|
6375
6654
|
lastError = error;
|
|
6376
6655
|
client.disconnect();
|
|
6656
|
+
if (requestDispatched && shouldWaitForDomainReload) {
|
|
6657
|
+
if (isTransportDisconnectError(error)) {
|
|
6658
|
+
spinner.update("Connection lost during compile. Waiting for result file...");
|
|
6659
|
+
break;
|
|
6660
|
+
}
|
|
6661
|
+
spinner.stop();
|
|
6662
|
+
restoreStdin();
|
|
6663
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
6664
|
+
}
|
|
6377
6665
|
if (!isRetryableError(error) || attempt >= MAX_RETRIES) {
|
|
6378
6666
|
break;
|
|
6379
6667
|
}
|
|
@@ -6383,9 +6671,70 @@ async function executeToolCommand(toolName, params, globalOptions) {
|
|
|
6383
6671
|
client.disconnect();
|
|
6384
6672
|
}
|
|
6385
6673
|
}
|
|
6674
|
+
if (shouldWaitForDomainReload && compileRequestId) {
|
|
6675
|
+
if (immediateResult === void 0 && !requestDispatched) {
|
|
6676
|
+
spinner.stop();
|
|
6677
|
+
restoreStdin();
|
|
6678
|
+
if (lastError instanceof Error) {
|
|
6679
|
+
throw lastError;
|
|
6680
|
+
}
|
|
6681
|
+
throw new Error(
|
|
6682
|
+
"Compile request never reached Unity. Check that Unity is running and retry."
|
|
6683
|
+
);
|
|
6684
|
+
}
|
|
6685
|
+
const projectRootFromUnity = immediateResult !== void 0 ? immediateResult["ProjectRoot"] : void 0;
|
|
6686
|
+
const effectiveProjectRoot = projectRootFromUnity ?? projectRoot;
|
|
6687
|
+
if (effectiveProjectRoot === null) {
|
|
6688
|
+
spinner.stop();
|
|
6689
|
+
restoreStdin();
|
|
6690
|
+
if (immediateResult !== void 0) {
|
|
6691
|
+
checkServerVersion(immediateResult);
|
|
6692
|
+
console.log(JSON.stringify(stripInternalFields(immediateResult), null, 2));
|
|
6693
|
+
return;
|
|
6694
|
+
}
|
|
6695
|
+
if (lastError instanceof Error) {
|
|
6696
|
+
throw lastError;
|
|
6697
|
+
}
|
|
6698
|
+
throw new Error(
|
|
6699
|
+
"Compile request failed and project root is unknown. Check connection and retry."
|
|
6700
|
+
);
|
|
6701
|
+
}
|
|
6702
|
+
spinner.update("Waiting for domain reload to complete...");
|
|
6703
|
+
const { outcome, result: storedResult } = await waitForCompileCompletion({
|
|
6704
|
+
projectRoot: effectiveProjectRoot,
|
|
6705
|
+
requestId: compileRequestId,
|
|
6706
|
+
timeoutMs: COMPILE_WAIT_TIMEOUT_MS,
|
|
6707
|
+
pollIntervalMs: COMPILE_WAIT_POLL_INTERVAL_MS,
|
|
6708
|
+
unityPort: port
|
|
6709
|
+
});
|
|
6710
|
+
if (outcome === "timed_out") {
|
|
6711
|
+
lastError = new Error(
|
|
6712
|
+
`Compile wait timed out after ${COMPILE_WAIT_TIMEOUT_MS}ms. Run 'uloop fix' and retry.`
|
|
6713
|
+
);
|
|
6714
|
+
} else {
|
|
6715
|
+
const finalResult = storedResult ?? immediateResult;
|
|
6716
|
+
if (finalResult !== void 0) {
|
|
6717
|
+
spinner.stop();
|
|
6718
|
+
restoreStdin();
|
|
6719
|
+
checkServerVersion(finalResult);
|
|
6720
|
+
console.log(JSON.stringify(stripInternalFields(finalResult), null, 2));
|
|
6721
|
+
return;
|
|
6722
|
+
}
|
|
6723
|
+
}
|
|
6724
|
+
}
|
|
6386
6725
|
spinner.stop();
|
|
6387
6726
|
restoreStdin();
|
|
6388
|
-
|
|
6727
|
+
if (lastError === void 0) {
|
|
6728
|
+
throw new Error("Tool execution failed without error details.");
|
|
6729
|
+
}
|
|
6730
|
+
if (lastError instanceof Error) {
|
|
6731
|
+
throw lastError;
|
|
6732
|
+
}
|
|
6733
|
+
if (typeof lastError === "string") {
|
|
6734
|
+
throw new Error(lastError);
|
|
6735
|
+
}
|
|
6736
|
+
const serializedError = JSON.stringify(lastError);
|
|
6737
|
+
throw new Error(serializedError ?? "Unknown error");
|
|
6389
6738
|
}
|
|
6390
6739
|
async function listAvailableTools(globalOptions) {
|
|
6391
6740
|
let portNumber;
|
|
@@ -6396,12 +6745,12 @@ async function listAvailableTools(globalOptions) {
|
|
|
6396
6745
|
}
|
|
6397
6746
|
portNumber = parsed;
|
|
6398
6747
|
}
|
|
6399
|
-
const port = await resolveUnityPort(portNumber);
|
|
6748
|
+
const port = await resolveUnityPort(portNumber, globalOptions.projectPath);
|
|
6400
6749
|
const restoreStdin = suppressStdinEcho();
|
|
6401
6750
|
const spinner = createSpinner("Connecting to Unity...");
|
|
6402
6751
|
let lastError;
|
|
6403
6752
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
6404
|
-
checkUnityBusyState();
|
|
6753
|
+
checkUnityBusyState(globalOptions.projectPath);
|
|
6405
6754
|
const client = new DirectUnityClient(port);
|
|
6406
6755
|
try {
|
|
6407
6756
|
await client.connect();
|
|
@@ -6453,12 +6802,12 @@ async function syncTools(globalOptions) {
|
|
|
6453
6802
|
}
|
|
6454
6803
|
portNumber = parsed;
|
|
6455
6804
|
}
|
|
6456
|
-
const port = await resolveUnityPort(portNumber);
|
|
6805
|
+
const port = await resolveUnityPort(portNumber, globalOptions.projectPath);
|
|
6457
6806
|
const restoreStdin = suppressStdinEcho();
|
|
6458
6807
|
const spinner = createSpinner("Connecting to Unity...");
|
|
6459
6808
|
let lastError;
|
|
6460
6809
|
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
6461
|
-
checkUnityBusyState();
|
|
6810
|
+
checkUnityBusyState(globalOptions.projectPath);
|
|
6462
6811
|
const client = new DirectUnityClient(port);
|
|
6463
6812
|
try {
|
|
6464
6813
|
await client.connect();
|
|
@@ -6515,8 +6864,8 @@ function pascalToKebabCase(pascal) {
|
|
|
6515
6864
|
}
|
|
6516
6865
|
|
|
6517
6866
|
// src/skills/skills-manager.ts
|
|
6518
|
-
var
|
|
6519
|
-
var
|
|
6867
|
+
var import_fs6 = require("fs");
|
|
6868
|
+
var import_path6 = require("path");
|
|
6520
6869
|
var import_os = require("os");
|
|
6521
6870
|
|
|
6522
6871
|
// src/skills/deprecated-skills.ts
|
|
@@ -6563,7 +6912,7 @@ var SkillsPathConstants = class _SkillsPathConstants {
|
|
|
6563
6912
|
];
|
|
6564
6913
|
};
|
|
6565
6914
|
function getGlobalSkillsDir(target) {
|
|
6566
|
-
return (0,
|
|
6915
|
+
return (0, import_path6.join)((0, import_os.homedir)(), target.projectDir, "skills");
|
|
6567
6916
|
}
|
|
6568
6917
|
function getProjectSkillsDir(target) {
|
|
6569
6918
|
const status = getUnityProjectStatus();
|
|
@@ -6578,35 +6927,35 @@ function getProjectSkillsDir(target) {
|
|
|
6578
6927
|
Please install uLoopMCP package first, then run this command again.`
|
|
6579
6928
|
);
|
|
6580
6929
|
}
|
|
6581
|
-
return (0,
|
|
6930
|
+
return (0, import_path6.join)(status.path, target.projectDir, "skills");
|
|
6582
6931
|
}
|
|
6583
6932
|
function getSkillPath(skillDirName, target, global) {
|
|
6584
6933
|
const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
|
|
6585
|
-
return (0,
|
|
6934
|
+
return (0, import_path6.join)(baseDir, skillDirName, target.skillFileName);
|
|
6586
6935
|
}
|
|
6587
6936
|
function isSkillInstalled(skill, target, global) {
|
|
6588
6937
|
const skillPath = getSkillPath(skill.dirName, target, global);
|
|
6589
|
-
return (0,
|
|
6938
|
+
return (0, import_fs6.existsSync)(skillPath);
|
|
6590
6939
|
}
|
|
6591
6940
|
function isSkillOutdated(skill, target, global) {
|
|
6592
6941
|
const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
|
|
6593
|
-
const skillDir = (0,
|
|
6594
|
-
const skillPath = (0,
|
|
6595
|
-
if (!(0,
|
|
6942
|
+
const skillDir = (0, import_path6.join)(baseDir, skill.dirName);
|
|
6943
|
+
const skillPath = (0, import_path6.join)(skillDir, target.skillFileName);
|
|
6944
|
+
if (!(0, import_fs6.existsSync)(skillPath)) {
|
|
6596
6945
|
return false;
|
|
6597
6946
|
}
|
|
6598
|
-
const installedContent = (0,
|
|
6947
|
+
const installedContent = (0, import_fs6.readFileSync)(skillPath, "utf-8");
|
|
6599
6948
|
if (installedContent !== skill.content) {
|
|
6600
6949
|
return true;
|
|
6601
6950
|
}
|
|
6602
6951
|
if ("additionalFiles" in skill && skill.additionalFiles) {
|
|
6603
6952
|
const additionalFiles = skill.additionalFiles;
|
|
6604
6953
|
for (const [relativePath, expectedContent] of Object.entries(additionalFiles)) {
|
|
6605
|
-
const filePath = (0,
|
|
6606
|
-
if (!(0,
|
|
6954
|
+
const filePath = (0, import_path6.join)(skillDir, relativePath);
|
|
6955
|
+
if (!(0, import_fs6.existsSync)(filePath)) {
|
|
6607
6956
|
return true;
|
|
6608
6957
|
}
|
|
6609
|
-
const installedFileContent = (0,
|
|
6958
|
+
const installedFileContent = (0, import_fs6.readFileSync)(filePath);
|
|
6610
6959
|
if (!installedFileContent.equals(expectedContent)) {
|
|
6611
6960
|
return true;
|
|
6612
6961
|
}
|
|
@@ -6670,24 +7019,24 @@ function warnLegacySkillStructure(toolPath, legacySkillMdPath) {
|
|
|
6670
7019
|
console.error("");
|
|
6671
7020
|
}
|
|
6672
7021
|
function scanEditorFolderForSkills(editorPath, skills, sourceType, warnLegacy = true) {
|
|
6673
|
-
if (!(0,
|
|
7022
|
+
if (!(0, import_fs6.existsSync)(editorPath)) {
|
|
6674
7023
|
return;
|
|
6675
7024
|
}
|
|
6676
|
-
const entries = (0,
|
|
7025
|
+
const entries = (0, import_fs6.readdirSync)(editorPath, { withFileTypes: true });
|
|
6677
7026
|
for (const entry of entries) {
|
|
6678
7027
|
if (EXCLUDED_DIRS2.has(entry.name)) {
|
|
6679
7028
|
continue;
|
|
6680
7029
|
}
|
|
6681
|
-
const fullPath = (0,
|
|
7030
|
+
const fullPath = (0, import_path6.join)(editorPath, entry.name);
|
|
6682
7031
|
if (entry.isDirectory()) {
|
|
6683
|
-
const skillDir = (0,
|
|
6684
|
-
const skillMdPath = (0,
|
|
6685
|
-
const legacySkillMdPath = (0,
|
|
6686
|
-
if (warnLegacy && !(0,
|
|
7032
|
+
const skillDir = (0, import_path6.join)(fullPath, SkillsPathConstants.SKILL_DIR);
|
|
7033
|
+
const skillMdPath = (0, import_path6.join)(skillDir, SkillsPathConstants.SKILL_FILE);
|
|
7034
|
+
const legacySkillMdPath = (0, import_path6.join)(fullPath, SkillsPathConstants.SKILL_FILE);
|
|
7035
|
+
if (warnLegacy && !(0, import_fs6.existsSync)(skillMdPath) && (0, import_fs6.existsSync)(legacySkillMdPath)) {
|
|
6687
7036
|
warnLegacySkillStructure(fullPath, legacySkillMdPath);
|
|
6688
7037
|
}
|
|
6689
|
-
if ((0,
|
|
6690
|
-
const content = (0,
|
|
7038
|
+
if ((0, import_fs6.existsSync)(skillMdPath)) {
|
|
7039
|
+
const content = (0, import_fs6.readFileSync)(skillMdPath, "utf-8");
|
|
6691
7040
|
const frontmatter = parseFrontmatter(content);
|
|
6692
7041
|
if (frontmatter.internal === true) {
|
|
6693
7042
|
continue;
|
|
@@ -6710,15 +7059,15 @@ function scanEditorFolderForSkills(editorPath, skills, sourceType, warnLegacy =
|
|
|
6710
7059
|
function findEditorFolders(basePath, maxDepth = 2) {
|
|
6711
7060
|
const editorFolders = [];
|
|
6712
7061
|
function scan(currentPath, depth) {
|
|
6713
|
-
if (depth > maxDepth || !(0,
|
|
7062
|
+
if (depth > maxDepth || !(0, import_fs6.existsSync)(currentPath)) {
|
|
6714
7063
|
return;
|
|
6715
7064
|
}
|
|
6716
|
-
const entries = (0,
|
|
7065
|
+
const entries = (0, import_fs6.readdirSync)(currentPath, { withFileTypes: true });
|
|
6717
7066
|
for (const entry of entries) {
|
|
6718
7067
|
if (!entry.isDirectory() || EXCLUDED_DIRS2.has(entry.name)) {
|
|
6719
7068
|
continue;
|
|
6720
7069
|
}
|
|
6721
|
-
const fullPath = (0,
|
|
7070
|
+
const fullPath = (0, import_path6.join)(currentPath, entry.name);
|
|
6722
7071
|
if (entry.name === "Editor") {
|
|
6723
7072
|
editorFolders.push(fullPath);
|
|
6724
7073
|
} else {
|
|
@@ -6737,12 +7086,12 @@ function collectProjectSkills(excludedRoots = []) {
|
|
|
6737
7086
|
const skills = [];
|
|
6738
7087
|
const seenNames = /* @__PURE__ */ new Set();
|
|
6739
7088
|
const searchPaths = [
|
|
6740
|
-
(0,
|
|
6741
|
-
(0,
|
|
6742
|
-
(0,
|
|
7089
|
+
(0, import_path6.join)(projectRoot, SkillsPathConstants.ASSETS_DIR),
|
|
7090
|
+
(0, import_path6.join)(projectRoot, SkillsPathConstants.PACKAGES_DIR),
|
|
7091
|
+
(0, import_path6.join)(projectRoot, SkillsPathConstants.LIBRARY_DIR, SkillsPathConstants.PACKAGE_CACHE_DIR)
|
|
6743
7092
|
];
|
|
6744
7093
|
for (const searchPath of searchPaths) {
|
|
6745
|
-
if (!(0,
|
|
7094
|
+
if (!(0, import_fs6.existsSync)(searchPath)) {
|
|
6746
7095
|
continue;
|
|
6747
7096
|
}
|
|
6748
7097
|
const editorFolders = findEditorFolders(searchPath, 3);
|
|
@@ -6773,26 +7122,26 @@ function getAllSkillStatuses(target, global) {
|
|
|
6773
7122
|
}
|
|
6774
7123
|
function installSkill(skill, target, global) {
|
|
6775
7124
|
const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
|
|
6776
|
-
const skillDir = (0,
|
|
6777
|
-
const skillPath = (0,
|
|
6778
|
-
(0,
|
|
6779
|
-
(0,
|
|
7125
|
+
const skillDir = (0, import_path6.join)(baseDir, skill.dirName);
|
|
7126
|
+
const skillPath = (0, import_path6.join)(skillDir, target.skillFileName);
|
|
7127
|
+
(0, import_fs6.mkdirSync)(skillDir, { recursive: true });
|
|
7128
|
+
(0, import_fs6.writeFileSync)(skillPath, skill.content, "utf-8");
|
|
6780
7129
|
if ("additionalFiles" in skill && skill.additionalFiles) {
|
|
6781
7130
|
const additionalFiles = skill.additionalFiles;
|
|
6782
7131
|
for (const [relativePath, content] of Object.entries(additionalFiles)) {
|
|
6783
|
-
const fullPath = (0,
|
|
6784
|
-
(0,
|
|
6785
|
-
(0,
|
|
7132
|
+
const fullPath = (0, import_path6.join)(skillDir, relativePath);
|
|
7133
|
+
(0, import_fs6.mkdirSync)((0, import_path6.dirname)(fullPath), { recursive: true });
|
|
7134
|
+
(0, import_fs6.writeFileSync)(fullPath, content);
|
|
6786
7135
|
}
|
|
6787
7136
|
}
|
|
6788
7137
|
}
|
|
6789
7138
|
function uninstallSkill(skill, target, global) {
|
|
6790
7139
|
const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
|
|
6791
|
-
const skillDir = (0,
|
|
6792
|
-
if (!(0,
|
|
7140
|
+
const skillDir = (0, import_path6.join)(baseDir, skill.dirName);
|
|
7141
|
+
if (!(0, import_fs6.existsSync)(skillDir)) {
|
|
6793
7142
|
return false;
|
|
6794
7143
|
}
|
|
6795
|
-
(0,
|
|
7144
|
+
(0, import_fs6.rmSync)(skillDir, { recursive: true, force: true });
|
|
6796
7145
|
return true;
|
|
6797
7146
|
}
|
|
6798
7147
|
function installAllSkills(target, global) {
|
|
@@ -6806,9 +7155,9 @@ function installAllSkills(target, global) {
|
|
|
6806
7155
|
};
|
|
6807
7156
|
const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
|
|
6808
7157
|
for (const deprecatedName of DEPRECATED_SKILLS) {
|
|
6809
|
-
const deprecatedDir = (0,
|
|
6810
|
-
if ((0,
|
|
6811
|
-
(0,
|
|
7158
|
+
const deprecatedDir = (0, import_path6.join)(baseDir, deprecatedName);
|
|
7159
|
+
if ((0, import_fs6.existsSync)(deprecatedDir)) {
|
|
7160
|
+
(0, import_fs6.rmSync)(deprecatedDir, { recursive: true, force: true });
|
|
6812
7161
|
result.deprecatedRemoved++;
|
|
6813
7162
|
}
|
|
6814
7163
|
}
|
|
@@ -6835,9 +7184,9 @@ function uninstallAllSkills(target, global) {
|
|
|
6835
7184
|
const result = { removed: 0, notFound: 0 };
|
|
6836
7185
|
const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
|
|
6837
7186
|
for (const deprecatedName of DEPRECATED_SKILLS) {
|
|
6838
|
-
const deprecatedDir = (0,
|
|
6839
|
-
if ((0,
|
|
6840
|
-
(0,
|
|
7187
|
+
const deprecatedDir = (0, import_path6.join)(baseDir, deprecatedName);
|
|
7188
|
+
if ((0, import_fs6.existsSync)(deprecatedDir)) {
|
|
7189
|
+
(0, import_fs6.rmSync)(deprecatedDir, { recursive: true, force: true });
|
|
6841
7190
|
result.removed++;
|
|
6842
7191
|
}
|
|
6843
7192
|
}
|
|
@@ -6866,13 +7215,13 @@ function collectAllSkills() {
|
|
|
6866
7215
|
return dedupeSkillsByName([packageSkills, cliOnlySkills, projectSkills]);
|
|
6867
7216
|
}
|
|
6868
7217
|
function collectPackageSkillsFromRoot(packageRoot) {
|
|
6869
|
-
const mcpToolsRoot = (0,
|
|
7218
|
+
const mcpToolsRoot = (0, import_path6.join)(
|
|
6870
7219
|
packageRoot,
|
|
6871
7220
|
SkillsPathConstants.EDITOR_DIR,
|
|
6872
7221
|
SkillsPathConstants.API_DIR,
|
|
6873
7222
|
SkillsPathConstants.MCP_TOOLS_DIR
|
|
6874
7223
|
);
|
|
6875
|
-
if (!(0,
|
|
7224
|
+
if (!(0, import_fs6.existsSync)(mcpToolsRoot)) {
|
|
6876
7225
|
return [];
|
|
6877
7226
|
}
|
|
6878
7227
|
const skills = [];
|
|
@@ -6880,7 +7229,7 @@ function collectPackageSkillsFromRoot(packageRoot) {
|
|
|
6880
7229
|
return skills;
|
|
6881
7230
|
}
|
|
6882
7231
|
function collectCliOnlySkills() {
|
|
6883
|
-
const cliOnlyRoot = (0,
|
|
7232
|
+
const cliOnlyRoot = (0, import_path6.resolve)(
|
|
6884
7233
|
__dirname,
|
|
6885
7234
|
SkillsPathConstants.DIST_PARENT_DIR,
|
|
6886
7235
|
SkillsPathConstants.SRC_DIR,
|
|
@@ -6888,7 +7237,7 @@ function collectCliOnlySkills() {
|
|
|
6888
7237
|
SkillsPathConstants.CLI_ONLY_DIR,
|
|
6889
7238
|
SkillsPathConstants.CLI_ONLY_SUBDIR
|
|
6890
7239
|
);
|
|
6891
|
-
if (!(0,
|
|
7240
|
+
if (!(0, import_fs6.existsSync)(cliOnlyRoot)) {
|
|
6892
7241
|
return [];
|
|
6893
7242
|
}
|
|
6894
7243
|
const skills = [];
|
|
@@ -6907,12 +7256,12 @@ function isExcludedFile(fileName) {
|
|
|
6907
7256
|
return false;
|
|
6908
7257
|
}
|
|
6909
7258
|
function collectSkillFolderFilesRecursive(baseDir, currentDir, additionalFiles) {
|
|
6910
|
-
const entries = (0,
|
|
7259
|
+
const entries = (0, import_fs6.readdirSync)(currentDir, { withFileTypes: true });
|
|
6911
7260
|
for (const entry of entries) {
|
|
6912
7261
|
if (isExcludedFile(entry.name)) {
|
|
6913
7262
|
continue;
|
|
6914
7263
|
}
|
|
6915
|
-
const fullPath = (0,
|
|
7264
|
+
const fullPath = (0, import_path6.join)(currentDir, entry.name);
|
|
6916
7265
|
const relativePath = fullPath.slice(baseDir.length + 1);
|
|
6917
7266
|
if (entry.isDirectory()) {
|
|
6918
7267
|
if (EXCLUDED_DIRS2.has(entry.name)) {
|
|
@@ -6923,12 +7272,12 @@ function collectSkillFolderFilesRecursive(baseDir, currentDir, additionalFiles)
|
|
|
6923
7272
|
if (entry.name === SkillsPathConstants.SKILL_FILE) {
|
|
6924
7273
|
continue;
|
|
6925
7274
|
}
|
|
6926
|
-
additionalFiles[relativePath] = (0,
|
|
7275
|
+
additionalFiles[relativePath] = (0, import_fs6.readFileSync)(fullPath);
|
|
6927
7276
|
}
|
|
6928
7277
|
}
|
|
6929
7278
|
}
|
|
6930
7279
|
function collectSkillFolderFiles(skillDir) {
|
|
6931
|
-
if (!(0,
|
|
7280
|
+
if (!(0, import_fs6.existsSync)(skillDir)) {
|
|
6932
7281
|
return void 0;
|
|
6933
7282
|
}
|
|
6934
7283
|
const additionalFiles = {};
|
|
@@ -6951,13 +7300,13 @@ function dedupeSkillsByName(skillGroups) {
|
|
|
6951
7300
|
}
|
|
6952
7301
|
function resolvePackageRoot(projectRoot) {
|
|
6953
7302
|
const candidates = [];
|
|
6954
|
-
candidates.push((0,
|
|
7303
|
+
candidates.push((0, import_path6.join)(projectRoot, SkillsPathConstants.PACKAGES_DIR, SkillsPathConstants.SRC_DIR));
|
|
6955
7304
|
const manifestPaths = resolveManifestPackagePaths(projectRoot);
|
|
6956
7305
|
for (const manifestPath of manifestPaths) {
|
|
6957
7306
|
candidates.push(manifestPath);
|
|
6958
7307
|
}
|
|
6959
7308
|
for (const packageName of SkillsPathConstants.PACKAGE_NAMES) {
|
|
6960
|
-
candidates.push((0,
|
|
7309
|
+
candidates.push((0, import_path6.join)(projectRoot, SkillsPathConstants.PACKAGES_DIR, packageName));
|
|
6961
7310
|
}
|
|
6962
7311
|
const directRoot = resolveFirstPackageRoot(candidates);
|
|
6963
7312
|
if (directRoot) {
|
|
@@ -6966,15 +7315,15 @@ function resolvePackageRoot(projectRoot) {
|
|
|
6966
7315
|
return resolvePackageCacheRoot(projectRoot);
|
|
6967
7316
|
}
|
|
6968
7317
|
function resolveManifestPackagePaths(projectRoot) {
|
|
6969
|
-
const manifestPath = (0,
|
|
7318
|
+
const manifestPath = (0, import_path6.join)(
|
|
6970
7319
|
projectRoot,
|
|
6971
7320
|
SkillsPathConstants.PACKAGES_DIR,
|
|
6972
7321
|
SkillsPathConstants.MANIFEST_FILE
|
|
6973
7322
|
);
|
|
6974
|
-
if (!(0,
|
|
7323
|
+
if (!(0, import_fs6.existsSync)(manifestPath)) {
|
|
6975
7324
|
return [];
|
|
6976
7325
|
}
|
|
6977
|
-
const manifestContent = (0,
|
|
7326
|
+
const manifestContent = (0, import_fs6.readFileSync)(manifestPath, "utf-8");
|
|
6978
7327
|
let manifestJson;
|
|
6979
7328
|
try {
|
|
6980
7329
|
manifestJson = JSON.parse(manifestContent);
|
|
@@ -7018,10 +7367,10 @@ function resolveDependencyPath(rawPath, projectRoot) {
|
|
|
7018
7367
|
if (normalizedPath.startsWith("//")) {
|
|
7019
7368
|
normalizedPath = normalizedPath.slice(2);
|
|
7020
7369
|
}
|
|
7021
|
-
if ((0,
|
|
7370
|
+
if ((0, import_path6.isAbsolute)(normalizedPath)) {
|
|
7022
7371
|
return normalizedPath;
|
|
7023
7372
|
}
|
|
7024
|
-
return (0,
|
|
7373
|
+
return (0, import_path6.resolve)(projectRoot, normalizedPath);
|
|
7025
7374
|
}
|
|
7026
7375
|
function resolveFirstPackageRoot(candidates) {
|
|
7027
7376
|
for (const candidate of candidates) {
|
|
@@ -7033,15 +7382,15 @@ function resolveFirstPackageRoot(candidates) {
|
|
|
7033
7382
|
return null;
|
|
7034
7383
|
}
|
|
7035
7384
|
function resolvePackageCacheRoot(projectRoot) {
|
|
7036
|
-
const packageCacheDir = (0,
|
|
7385
|
+
const packageCacheDir = (0, import_path6.join)(
|
|
7037
7386
|
projectRoot,
|
|
7038
7387
|
SkillsPathConstants.LIBRARY_DIR,
|
|
7039
7388
|
SkillsPathConstants.PACKAGE_CACHE_DIR
|
|
7040
7389
|
);
|
|
7041
|
-
if (!(0,
|
|
7390
|
+
if (!(0, import_fs6.existsSync)(packageCacheDir)) {
|
|
7042
7391
|
return null;
|
|
7043
7392
|
}
|
|
7044
|
-
const entries = (0,
|
|
7393
|
+
const entries = (0, import_fs6.readdirSync)(packageCacheDir, { withFileTypes: true });
|
|
7045
7394
|
for (const entry of entries) {
|
|
7046
7395
|
if (!entry.isDirectory()) {
|
|
7047
7396
|
continue;
|
|
@@ -7049,7 +7398,7 @@ function resolvePackageCacheRoot(projectRoot) {
|
|
|
7049
7398
|
if (!isTargetPackageCacheDir(entry.name)) {
|
|
7050
7399
|
continue;
|
|
7051
7400
|
}
|
|
7052
|
-
const candidate = (0,
|
|
7401
|
+
const candidate = (0, import_path6.join)(packageCacheDir, entry.name);
|
|
7053
7402
|
const resolvedRoot = resolvePackageRootCandidate(candidate);
|
|
7054
7403
|
if (resolvedRoot) {
|
|
7055
7404
|
return resolvedRoot;
|
|
@@ -7058,26 +7407,26 @@ function resolvePackageCacheRoot(projectRoot) {
|
|
|
7058
7407
|
return null;
|
|
7059
7408
|
}
|
|
7060
7409
|
function resolvePackageRootCandidate(candidate) {
|
|
7061
|
-
if (!(0,
|
|
7410
|
+
if (!(0, import_fs6.existsSync)(candidate)) {
|
|
7062
7411
|
return null;
|
|
7063
7412
|
}
|
|
7064
|
-
const directToolsPath = (0,
|
|
7413
|
+
const directToolsPath = (0, import_path6.join)(
|
|
7065
7414
|
candidate,
|
|
7066
7415
|
SkillsPathConstants.EDITOR_DIR,
|
|
7067
7416
|
SkillsPathConstants.API_DIR,
|
|
7068
7417
|
SkillsPathConstants.MCP_TOOLS_DIR
|
|
7069
7418
|
);
|
|
7070
|
-
if ((0,
|
|
7419
|
+
if ((0, import_fs6.existsSync)(directToolsPath)) {
|
|
7071
7420
|
return candidate;
|
|
7072
7421
|
}
|
|
7073
|
-
const nestedRoot = (0,
|
|
7074
|
-
const nestedToolsPath = (0,
|
|
7422
|
+
const nestedRoot = (0, import_path6.join)(candidate, SkillsPathConstants.PACKAGES_DIR, SkillsPathConstants.SRC_DIR);
|
|
7423
|
+
const nestedToolsPath = (0, import_path6.join)(
|
|
7075
7424
|
nestedRoot,
|
|
7076
7425
|
SkillsPathConstants.EDITOR_DIR,
|
|
7077
7426
|
SkillsPathConstants.API_DIR,
|
|
7078
7427
|
SkillsPathConstants.MCP_TOOLS_DIR
|
|
7079
7428
|
);
|
|
7080
|
-
if ((0,
|
|
7429
|
+
if ((0, import_fs6.existsSync)(nestedToolsPath)) {
|
|
7081
7430
|
return nestedRoot;
|
|
7082
7431
|
}
|
|
7083
7432
|
return null;
|
|
@@ -7103,12 +7452,12 @@ function isUnderExcludedRoots(targetPath, excludedRoots) {
|
|
|
7103
7452
|
return false;
|
|
7104
7453
|
}
|
|
7105
7454
|
function isPathUnder(childPath, parentPath) {
|
|
7106
|
-
const resolvedChild = (0,
|
|
7107
|
-
const resolvedParent = (0,
|
|
7455
|
+
const resolvedChild = (0, import_path6.resolve)(childPath);
|
|
7456
|
+
const resolvedParent = (0, import_path6.resolve)(parentPath);
|
|
7108
7457
|
if (resolvedChild === resolvedParent) {
|
|
7109
7458
|
return true;
|
|
7110
7459
|
}
|
|
7111
|
-
return resolvedChild.startsWith(resolvedParent +
|
|
7460
|
+
return resolvedChild.startsWith(resolvedParent + import_path6.sep);
|
|
7112
7461
|
}
|
|
7113
7462
|
|
|
7114
7463
|
// src/skills/target-config.ts
|
|
@@ -7263,7 +7612,7 @@ Uninstalling uloop skills (${location})...`);
|
|
|
7263
7612
|
}
|
|
7264
7613
|
|
|
7265
7614
|
// src/commands/launch.ts
|
|
7266
|
-
var
|
|
7615
|
+
var import_path7 = require("path");
|
|
7267
7616
|
|
|
7268
7617
|
// node_modules/launch-unity/dist/lib.js
|
|
7269
7618
|
var import_node_child_process = require("node:child_process");
|
|
@@ -7276,7 +7625,7 @@ var import_node_util = require("node:util");
|
|
|
7276
7625
|
var import_promises2 = require("node:fs/promises");
|
|
7277
7626
|
var import_node_fs = require("node:fs");
|
|
7278
7627
|
var import_node_path = require("node:path");
|
|
7279
|
-
var
|
|
7628
|
+
var import_node_assert2 = __toESM(require("node:assert"), 1);
|
|
7280
7629
|
var resolveUnityHubProjectFiles = () => {
|
|
7281
7630
|
if (process.platform === "darwin") {
|
|
7282
7631
|
const home = process.env.HOME;
|
|
@@ -7447,7 +7796,7 @@ var resolveUnityHubProjectsInfoFile = () => {
|
|
|
7447
7796
|
return void 0;
|
|
7448
7797
|
};
|
|
7449
7798
|
var parseCliArgs = (cliArgsString) => {
|
|
7450
|
-
(0,
|
|
7799
|
+
(0, import_node_assert2.default)(cliArgsString !== null && cliArgsString !== void 0, "cliArgsString must not be null");
|
|
7451
7800
|
const trimmed = cliArgsString.trim();
|
|
7452
7801
|
if (trimmed.length === 0) {
|
|
7453
7802
|
return [];
|
|
@@ -7503,7 +7852,7 @@ var groupCliArgs = (args) => {
|
|
|
7503
7852
|
return groups;
|
|
7504
7853
|
};
|
|
7505
7854
|
var getProjectCliArgs = async (projectPath) => {
|
|
7506
|
-
(0,
|
|
7855
|
+
(0, import_node_assert2.default)(projectPath !== null && projectPath !== void 0, "projectPath must not be null");
|
|
7507
7856
|
const infoFilePath = resolveUnityHubProjectsInfoFile();
|
|
7508
7857
|
if (!infoFilePath) {
|
|
7509
7858
|
logDebug("projectsInfo.json path could not be resolved.");
|
|
@@ -7551,6 +7900,8 @@ var PROCESS_LIST_ARGS_MAC = ["-axo", "pid=,command=", "-ww"];
|
|
|
7551
7900
|
var WINDOWS_POWERSHELL = "powershell";
|
|
7552
7901
|
var UNITY_LOCKFILE_NAME = "UnityLockfile";
|
|
7553
7902
|
var TEMP_DIRECTORY_NAME = "Temp";
|
|
7903
|
+
var ASSETS_DIRECTORY_NAME = "Assets";
|
|
7904
|
+
var RECOVERY_DIRECTORY_NAME = "_Recovery";
|
|
7554
7905
|
function getUnityVersion(projectPath) {
|
|
7555
7906
|
const versionFile = (0, import_node_path2.join)(projectPath, "ProjectSettings", "ProjectVersion.txt");
|
|
7556
7907
|
if (!(0, import_node_fs2.existsSync)(versionFile)) {
|
|
@@ -7850,6 +8201,20 @@ async function handleStaleLockfile(projectPath) {
|
|
|
7850
8201
|
}
|
|
7851
8202
|
console.log();
|
|
7852
8203
|
}
|
|
8204
|
+
async function deleteRecoveryDirectory(projectPath) {
|
|
8205
|
+
const recoveryPath = (0, import_node_path2.join)(projectPath, ASSETS_DIRECTORY_NAME, RECOVERY_DIRECTORY_NAME);
|
|
8206
|
+
if (!(0, import_node_fs2.existsSync)(recoveryPath)) {
|
|
8207
|
+
return;
|
|
8208
|
+
}
|
|
8209
|
+
console.log(`Deleting recovery directory: ${recoveryPath}`);
|
|
8210
|
+
try {
|
|
8211
|
+
await (0, import_promises3.rm)(recoveryPath, { recursive: true, force: true });
|
|
8212
|
+
console.log("Deleted recovery directory.");
|
|
8213
|
+
} catch (error) {
|
|
8214
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
8215
|
+
console.warn(`Failed to delete recovery directory: ${message}`);
|
|
8216
|
+
}
|
|
8217
|
+
}
|
|
7853
8218
|
var LOCKFILE_POLL_INTERVAL_MS = 100;
|
|
7854
8219
|
var LOCKFILE_WAIT_TIMEOUT_MS = 5e3;
|
|
7855
8220
|
var KILL_POLL_INTERVAL_MS = 100;
|
|
@@ -7875,7 +8240,7 @@ async function waitForProcessExit(pid, timeoutMs) {
|
|
|
7875
8240
|
if (!isProcessAlive(pid)) {
|
|
7876
8241
|
return true;
|
|
7877
8242
|
}
|
|
7878
|
-
await new Promise((
|
|
8243
|
+
await new Promise((resolve6) => setTimeout(resolve6, KILL_POLL_INTERVAL_MS));
|
|
7879
8244
|
}
|
|
7880
8245
|
return false;
|
|
7881
8246
|
}
|
|
@@ -8044,7 +8409,7 @@ async function waitForLockfile(projectPath) {
|
|
|
8044
8409
|
if ((0, import_node_fs2.existsSync)(lockfilePath)) {
|
|
8045
8410
|
return;
|
|
8046
8411
|
}
|
|
8047
|
-
await new Promise((
|
|
8412
|
+
await new Promise((resolve6) => setTimeout(resolve6, LOCKFILE_POLL_INTERVAL_MS));
|
|
8048
8413
|
}
|
|
8049
8414
|
console.warn("Unity launched, but UnityLockfile was not detected within 5s.");
|
|
8050
8415
|
}
|
|
@@ -8075,7 +8440,7 @@ async function launch(opts) {
|
|
|
8075
8440
|
if (unityArgs.length > 0) {
|
|
8076
8441
|
args.push(...unityArgs);
|
|
8077
8442
|
}
|
|
8078
|
-
return new Promise((
|
|
8443
|
+
return new Promise((resolve6, reject) => {
|
|
8079
8444
|
const child = (0, import_node_child_process.spawn)(unityPath, args, {
|
|
8080
8445
|
stdio: "ignore",
|
|
8081
8446
|
detached: true,
|
|
@@ -8092,7 +8457,7 @@ async function launch(opts) {
|
|
|
8092
8457
|
const handleSpawn = () => {
|
|
8093
8458
|
child.removeListener("error", handleError);
|
|
8094
8459
|
child.unref();
|
|
8095
|
-
|
|
8460
|
+
resolve6();
|
|
8096
8461
|
};
|
|
8097
8462
|
child.once("error", handleError);
|
|
8098
8463
|
child.once("spawn", handleSpawn);
|
|
@@ -8140,6 +8505,9 @@ async function orchestrateLaunch(options) {
|
|
|
8140
8505
|
return { action: "focused", projectPath: resolvedProjectPath, pid: runningProcess.pid };
|
|
8141
8506
|
}
|
|
8142
8507
|
}
|
|
8508
|
+
if (options.deleteRecovery) {
|
|
8509
|
+
await deleteRecoveryDirectory(resolvedProjectPath);
|
|
8510
|
+
}
|
|
8143
8511
|
await handleStaleLockfile(resolvedProjectPath);
|
|
8144
8512
|
const resolved = {
|
|
8145
8513
|
projectPath: resolvedProjectPath,
|
|
@@ -8164,7 +8532,7 @@ async function orchestrateLaunch(options) {
|
|
|
8164
8532
|
function registerLaunchCommand(program3) {
|
|
8165
8533
|
program3.command("launch").description(
|
|
8166
8534
|
"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) => {
|
|
8535
|
+
).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
8536
|
await runLaunchCommand(projectPath, options);
|
|
8169
8537
|
});
|
|
8170
8538
|
}
|
|
@@ -8182,13 +8550,14 @@ function parseMaxDepth(value) {
|
|
|
8182
8550
|
async function runLaunchCommand(projectPath, options) {
|
|
8183
8551
|
const maxDepth = parseMaxDepth(options.maxDepth);
|
|
8184
8552
|
await orchestrateLaunch({
|
|
8185
|
-
projectPath: projectPath ? (0,
|
|
8553
|
+
projectPath: projectPath ? (0, import_path7.resolve)(projectPath) : void 0,
|
|
8186
8554
|
searchRoot: process.cwd(),
|
|
8187
8555
|
searchMaxDepth: maxDepth,
|
|
8188
8556
|
platform: options.platform,
|
|
8189
8557
|
unityArgs: [],
|
|
8190
8558
|
restart: options.restart === true,
|
|
8191
8559
|
quit: options.quit === true,
|
|
8560
|
+
deleteRecovery: options.deleteRecovery === true,
|
|
8192
8561
|
addUnityHub: options.addUnityHub === true,
|
|
8193
8562
|
favoriteUnityHub: options.favorite === true
|
|
8194
8563
|
});
|
|
@@ -8196,8 +8565,24 @@ async function runLaunchCommand(projectPath, options) {
|
|
|
8196
8565
|
|
|
8197
8566
|
// src/commands/focus-window.ts
|
|
8198
8567
|
function registerFocusWindowCommand(program3) {
|
|
8199
|
-
program3.command("focus-window").description("Bring Unity Editor window to front using OS-level commands").action(async () => {
|
|
8200
|
-
|
|
8568
|
+
program3.command("focus-window").description("Bring Unity Editor window to front using OS-level commands").option("--project-path <path>", "Unity project path").action(async (options) => {
|
|
8569
|
+
let projectRoot;
|
|
8570
|
+
if (options.projectPath !== void 0) {
|
|
8571
|
+
try {
|
|
8572
|
+
projectRoot = validateProjectPath(options.projectPath);
|
|
8573
|
+
} catch (error) {
|
|
8574
|
+
console.error(
|
|
8575
|
+
JSON.stringify({
|
|
8576
|
+
Success: false,
|
|
8577
|
+
Message: error instanceof Error ? error.message : String(error)
|
|
8578
|
+
})
|
|
8579
|
+
);
|
|
8580
|
+
process.exit(1);
|
|
8581
|
+
return;
|
|
8582
|
+
}
|
|
8583
|
+
} else {
|
|
8584
|
+
projectRoot = findUnityProjectRoot();
|
|
8585
|
+
}
|
|
8201
8586
|
if (projectRoot === null) {
|
|
8202
8587
|
console.error(
|
|
8203
8588
|
JSON.stringify({
|
|
@@ -8255,11 +8640,11 @@ var program2 = new Command();
|
|
|
8255
8640
|
program2.name("uloop").description("Unity MCP CLI - Direct communication with Unity Editor").version(VERSION, "-v, --version", "Output the version number");
|
|
8256
8641
|
program2.option("--list-commands", "List all command names (for shell completion)");
|
|
8257
8642
|
program2.option("--list-options <cmd>", "List options for a command (for shell completion)");
|
|
8258
|
-
program2.command("list").description("List all available tools from Unity").option("-p, --port <port>", "Unity TCP port").action(async (options) => {
|
|
8259
|
-
await runWithErrorHandling(() => listAvailableTools(options));
|
|
8643
|
+
program2.command("list").description("List all available tools from Unity").option("-p, --port <port>", "Unity TCP port").option("--project-path <path>", "Unity project path").action(async (options) => {
|
|
8644
|
+
await runWithErrorHandling(() => listAvailableTools(extractGlobalOptions(options)));
|
|
8260
8645
|
});
|
|
8261
|
-
program2.command("sync").description("Sync tool definitions from Unity to local cache").option("-p, --port <port>", "Unity TCP port").action(async (options) => {
|
|
8262
|
-
await runWithErrorHandling(() => syncTools(options));
|
|
8646
|
+
program2.command("sync").description("Sync tool definitions from Unity to local cache").option("-p, --port <port>", "Unity TCP port").option("--project-path <path>", "Unity project path").action(async (options) => {
|
|
8647
|
+
await runWithErrorHandling(() => syncTools(extractGlobalOptions(options)));
|
|
8263
8648
|
});
|
|
8264
8649
|
program2.command("completion").description("Setup shell completion").option("--install", "Install completion to shell config file").option("--shell <type>", "Shell type: bash, zsh, or powershell").action((options) => {
|
|
8265
8650
|
handleCompletion(options.install ?? false, options.shell);
|
|
@@ -8267,8 +8652,11 @@ program2.command("completion").description("Setup shell completion").option("--i
|
|
|
8267
8652
|
program2.command("update").description("Update uloop CLI to the latest version").action(() => {
|
|
8268
8653
|
updateCli();
|
|
8269
8654
|
});
|
|
8270
|
-
program2.command("fix").description("Clean up stale lock files that may prevent CLI from connecting").action(() => {
|
|
8271
|
-
|
|
8655
|
+
program2.command("fix").description("Clean up stale lock files that may prevent CLI from connecting").option("--project-path <path>", "Unity project path").action(async (options) => {
|
|
8656
|
+
await runWithErrorHandling(() => {
|
|
8657
|
+
cleanupLockFiles(options.projectPath);
|
|
8658
|
+
return Promise.resolve();
|
|
8659
|
+
});
|
|
8272
8660
|
});
|
|
8273
8661
|
registerSkillsCommand(program2);
|
|
8274
8662
|
registerLaunchCommand(program2);
|
|
@@ -8291,6 +8679,7 @@ function registerToolCommand(tool) {
|
|
|
8291
8679
|
}
|
|
8292
8680
|
}
|
|
8293
8681
|
cmd.option("-p, --port <port>", "Unity TCP port");
|
|
8682
|
+
cmd.option("--project-path <path>", "Unity project path");
|
|
8294
8683
|
cmd.action(async (options) => {
|
|
8295
8684
|
const params = buildParams(options, properties);
|
|
8296
8685
|
if (tool.name === "execute-dynamic-code" && params["Code"]) {
|
|
@@ -8397,7 +8786,8 @@ function convertValue(value, propInfo) {
|
|
|
8397
8786
|
}
|
|
8398
8787
|
function extractGlobalOptions(options) {
|
|
8399
8788
|
return {
|
|
8400
|
-
port: options["port"]
|
|
8789
|
+
port: options["port"],
|
|
8790
|
+
projectPath: options["projectPath"]
|
|
8401
8791
|
};
|
|
8402
8792
|
}
|
|
8403
8793
|
function isConnectionError(message) {
|
|
@@ -8481,7 +8871,7 @@ async function runWithErrorHandling(fn) {
|
|
|
8481
8871
|
}
|
|
8482
8872
|
function detectShell() {
|
|
8483
8873
|
const shell = process.env["SHELL"] || "";
|
|
8484
|
-
const shellName = (0,
|
|
8874
|
+
const shellName = (0, import_path8.basename)(shell).replace(/\.exe$/i, "");
|
|
8485
8875
|
if (shellName === "zsh") {
|
|
8486
8876
|
return "zsh";
|
|
8487
8877
|
}
|
|
@@ -8496,12 +8886,12 @@ function detectShell() {
|
|
|
8496
8886
|
function getShellConfigPath(shell) {
|
|
8497
8887
|
const home = (0, import_os2.homedir)();
|
|
8498
8888
|
if (shell === "zsh") {
|
|
8499
|
-
return (0,
|
|
8889
|
+
return (0, import_path8.join)(home, ".zshrc");
|
|
8500
8890
|
}
|
|
8501
8891
|
if (shell === "powershell") {
|
|
8502
|
-
return (0,
|
|
8892
|
+
return (0, import_path8.join)(home, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
|
|
8503
8893
|
}
|
|
8504
|
-
return (0,
|
|
8894
|
+
return (0, import_path8.join)(home, ".bashrc");
|
|
8505
8895
|
}
|
|
8506
8896
|
function getCompletionScript(shell) {
|
|
8507
8897
|
if (shell === "bash") {
|
|
@@ -8632,18 +9022,18 @@ function updateCli() {
|
|
|
8632
9022
|
});
|
|
8633
9023
|
}
|
|
8634
9024
|
var LOCK_FILES = ["compiling.lock", "domainreload.lock", "serverstarting.lock"];
|
|
8635
|
-
function cleanupLockFiles() {
|
|
8636
|
-
const projectRoot = findUnityProjectRoot();
|
|
9025
|
+
function cleanupLockFiles(projectPath) {
|
|
9026
|
+
const projectRoot = projectPath !== void 0 ? validateProjectPath(projectPath) : findUnityProjectRoot();
|
|
8637
9027
|
if (projectRoot === null) {
|
|
8638
9028
|
console.error("Could not find Unity project root.");
|
|
8639
9029
|
process.exit(1);
|
|
8640
9030
|
}
|
|
8641
|
-
const tempDir = (0,
|
|
9031
|
+
const tempDir = (0, import_path8.join)(projectRoot, "Temp");
|
|
8642
9032
|
let cleaned = 0;
|
|
8643
9033
|
for (const lockFile of LOCK_FILES) {
|
|
8644
|
-
const lockPath = (0,
|
|
8645
|
-
if ((0,
|
|
8646
|
-
(0,
|
|
9034
|
+
const lockPath = (0, import_path8.join)(tempDir, lockFile);
|
|
9035
|
+
if ((0, import_fs7.existsSync)(lockPath)) {
|
|
9036
|
+
(0, import_fs7.unlinkSync)(lockPath);
|
|
8647
9037
|
console.log(`Removed: ${lockFile}`);
|
|
8648
9038
|
cleaned++;
|
|
8649
9039
|
}
|
|
@@ -8678,13 +9068,13 @@ function handleCompletion(install, shellOverride) {
|
|
|
8678
9068
|
return;
|
|
8679
9069
|
}
|
|
8680
9070
|
const configPath = getShellConfigPath(shell);
|
|
8681
|
-
const configDir = (0,
|
|
8682
|
-
if (!(0,
|
|
8683
|
-
(0,
|
|
9071
|
+
const configDir = (0, import_path8.dirname)(configPath);
|
|
9072
|
+
if (!(0, import_fs7.existsSync)(configDir)) {
|
|
9073
|
+
(0, import_fs7.mkdirSync)(configDir, { recursive: true });
|
|
8684
9074
|
}
|
|
8685
9075
|
let content = "";
|
|
8686
|
-
if ((0,
|
|
8687
|
-
content = (0,
|
|
9076
|
+
if ((0, import_fs7.existsSync)(configPath)) {
|
|
9077
|
+
content = (0, import_fs7.readFileSync)(configPath, "utf-8");
|
|
8688
9078
|
content = content.replace(
|
|
8689
9079
|
/\n?# >>> uloop completion >>>[\s\S]*?# <<< uloop completion <<<\n?/g,
|
|
8690
9080
|
""
|
|
@@ -8698,7 +9088,7 @@ ${startMarker}
|
|
|
8698
9088
|
${script}
|
|
8699
9089
|
${endMarker}
|
|
8700
9090
|
`;
|
|
8701
|
-
(0,
|
|
9091
|
+
(0, import_fs7.writeFileSync)(configPath, content + lineToAdd, "utf-8");
|
|
8702
9092
|
} else {
|
|
8703
9093
|
const evalLine = `eval "$(uloop completion --shell ${shell})"`;
|
|
8704
9094
|
const lineToAdd = `
|
|
@@ -8706,7 +9096,7 @@ ${startMarker}
|
|
|
8706
9096
|
${evalLine}
|
|
8707
9097
|
${endMarker}
|
|
8708
9098
|
`;
|
|
8709
|
-
(0,
|
|
9099
|
+
(0, import_fs7.writeFileSync)(configPath, content + lineToAdd, "utf-8");
|
|
8710
9100
|
}
|
|
8711
9101
|
console.log(`Completion installed to ${configPath}`);
|
|
8712
9102
|
if (shell === "powershell") {
|
|
@@ -8760,12 +9150,42 @@ function shouldSkipAutoSync(cmdName, args) {
|
|
|
8760
9150
|
}
|
|
8761
9151
|
return args.some((arg) => NO_SYNC_FLAGS.includes(arg));
|
|
8762
9152
|
}
|
|
9153
|
+
function extractSyncGlobalOptions(args) {
|
|
9154
|
+
const options = {};
|
|
9155
|
+
for (let i = 0; i < args.length; i++) {
|
|
9156
|
+
const arg = args[i];
|
|
9157
|
+
if (arg === "--port" || arg === "-p") {
|
|
9158
|
+
const nextArg = args[i + 1];
|
|
9159
|
+
if (nextArg !== void 0 && !nextArg.startsWith("-")) {
|
|
9160
|
+
options.port = nextArg;
|
|
9161
|
+
}
|
|
9162
|
+
continue;
|
|
9163
|
+
}
|
|
9164
|
+
if (arg.startsWith("--port=")) {
|
|
9165
|
+
options.port = arg.slice("--port=".length);
|
|
9166
|
+
continue;
|
|
9167
|
+
}
|
|
9168
|
+
if (arg === "--project-path") {
|
|
9169
|
+
const nextArg = args[i + 1];
|
|
9170
|
+
if (nextArg !== void 0 && !nextArg.startsWith("-")) {
|
|
9171
|
+
options.projectPath = nextArg;
|
|
9172
|
+
}
|
|
9173
|
+
continue;
|
|
9174
|
+
}
|
|
9175
|
+
if (arg.startsWith("--project-path=")) {
|
|
9176
|
+
options.projectPath = arg.slice("--project-path=".length);
|
|
9177
|
+
continue;
|
|
9178
|
+
}
|
|
9179
|
+
}
|
|
9180
|
+
return options;
|
|
9181
|
+
}
|
|
8763
9182
|
async function main() {
|
|
8764
9183
|
if (handleCompletionOptions()) {
|
|
8765
9184
|
return;
|
|
8766
9185
|
}
|
|
8767
9186
|
const args = process.argv.slice(2);
|
|
8768
9187
|
const cmdName = args.find((arg) => !arg.startsWith("-"));
|
|
9188
|
+
const syncGlobalOptions = extractSyncGlobalOptions(args);
|
|
8769
9189
|
if (!shouldSkipAutoSync(cmdName, args)) {
|
|
8770
9190
|
const cachedVersion = loadToolsCache().version;
|
|
8771
9191
|
if (hasCacheFile() && cachedVersion !== VERSION) {
|
|
@@ -8773,7 +9193,7 @@ async function main() {
|
|
|
8773
9193
|
`\x1B[33mCache outdated (${cachedVersion} \u2192 ${VERSION}). Syncing tools from Unity...\x1B[0m`
|
|
8774
9194
|
);
|
|
8775
9195
|
try {
|
|
8776
|
-
await syncTools(
|
|
9196
|
+
await syncTools(syncGlobalOptions);
|
|
8777
9197
|
console.log("\x1B[32m\u2713 Tools synced successfully.\x1B[0m\n");
|
|
8778
9198
|
} catch (error) {
|
|
8779
9199
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -8795,7 +9215,7 @@ async function main() {
|
|
|
8795
9215
|
if (cmdName && !commandExists(cmdName)) {
|
|
8796
9216
|
console.log(`\x1B[33mUnknown command '${cmdName}'. Syncing tools from Unity...\x1B[0m`);
|
|
8797
9217
|
try {
|
|
8798
|
-
await syncTools(
|
|
9218
|
+
await syncTools(syncGlobalOptions);
|
|
8799
9219
|
const newCache = loadToolsCache();
|
|
8800
9220
|
const tool = newCache.tools.find((t) => t.name === cmdName);
|
|
8801
9221
|
if (tool) {
|