uloop-cli 0.44.2 → 0.45.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/dist/cli.bundle.cjs +285 -92
- package/dist/cli.bundle.cjs.map +4 -4
- package/package.json +1 -1
- package/src/arg-parser.ts +3 -0
- package/src/cli.ts +70 -23
- package/src/default-tools.json +1 -1
- package/src/direct-unity-client.ts +3 -0
- package/src/execute-tool.ts +212 -50
- package/src/port-resolver.ts +3 -0
- package/src/project-root.ts +3 -0
- package/src/skills/skill-definitions/uloop-compile/SKILL.md +10 -0
- package/src/skills/skills-command.ts +3 -0
- package/src/skills/skills-manager.ts +3 -0
- package/src/spinner.ts +49 -0
- package/src/tool-cache.ts +3 -0
- package/src/version.ts +1 -1
package/dist/cli.bundle.cjs
CHANGED
|
@@ -3453,8 +3453,8 @@ var require_commander = __commonJS({
|
|
|
3453
3453
|
});
|
|
3454
3454
|
|
|
3455
3455
|
// src/cli.ts
|
|
3456
|
-
var
|
|
3457
|
-
var
|
|
3456
|
+
var import_fs5 = require("fs");
|
|
3457
|
+
var import_path6 = require("path");
|
|
3458
3458
|
var import_os2 = require("os");
|
|
3459
3459
|
var import_child_process = require("child_process");
|
|
3460
3460
|
|
|
@@ -3475,6 +3475,11 @@ var {
|
|
|
3475
3475
|
Help
|
|
3476
3476
|
} = import_index.default;
|
|
3477
3477
|
|
|
3478
|
+
// src/execute-tool.ts
|
|
3479
|
+
var readline = __toESM(require("readline"), 1);
|
|
3480
|
+
var import_fs3 = require("fs");
|
|
3481
|
+
var import_path4 = require("path");
|
|
3482
|
+
|
|
3478
3483
|
// src/direct-unity-client.ts
|
|
3479
3484
|
var net = __toESM(require("net"), 1);
|
|
3480
3485
|
|
|
@@ -3685,7 +3690,7 @@ var import_path3 = require("path");
|
|
|
3685
3690
|
|
|
3686
3691
|
// src/default-tools.json
|
|
3687
3692
|
var default_tools_default = {
|
|
3688
|
-
version: "0.
|
|
3693
|
+
version: "0.45.0",
|
|
3689
3694
|
tools: [
|
|
3690
3695
|
{
|
|
3691
3696
|
name: "compile",
|
|
@@ -4082,9 +4087,96 @@ function getCacheFilePath() {
|
|
|
4082
4087
|
}
|
|
4083
4088
|
|
|
4084
4089
|
// src/version.ts
|
|
4085
|
-
var VERSION = "0.
|
|
4090
|
+
var VERSION = "0.45.0";
|
|
4091
|
+
|
|
4092
|
+
// src/spinner.ts
|
|
4093
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
4094
|
+
var FRAME_INTERVAL_MS = 80;
|
|
4095
|
+
function createSpinner(initialMessage) {
|
|
4096
|
+
if (!process.stderr.isTTY) {
|
|
4097
|
+
return {
|
|
4098
|
+
update: () => {
|
|
4099
|
+
},
|
|
4100
|
+
stop: () => {
|
|
4101
|
+
}
|
|
4102
|
+
};
|
|
4103
|
+
}
|
|
4104
|
+
let frameIndex = 0;
|
|
4105
|
+
let currentMessage = initialMessage;
|
|
4106
|
+
const render = () => {
|
|
4107
|
+
const frame = SPINNER_FRAMES[frameIndex];
|
|
4108
|
+
process.stderr.write(`\r\x1B[K${frame} ${currentMessage}`);
|
|
4109
|
+
frameIndex = (frameIndex + 1) % SPINNER_FRAMES.length;
|
|
4110
|
+
};
|
|
4111
|
+
render();
|
|
4112
|
+
const intervalId = setInterval(render, FRAME_INTERVAL_MS);
|
|
4113
|
+
return {
|
|
4114
|
+
update(message) {
|
|
4115
|
+
currentMessage = message;
|
|
4116
|
+
},
|
|
4117
|
+
stop() {
|
|
4118
|
+
clearInterval(intervalId);
|
|
4119
|
+
process.stderr.write("\r\x1B[K");
|
|
4120
|
+
}
|
|
4121
|
+
};
|
|
4122
|
+
}
|
|
4086
4123
|
|
|
4087
4124
|
// src/execute-tool.ts
|
|
4125
|
+
function suppressStdinEcho() {
|
|
4126
|
+
if (!process.stdin.isTTY) {
|
|
4127
|
+
return () => {
|
|
4128
|
+
};
|
|
4129
|
+
}
|
|
4130
|
+
const rl = readline.createInterface({
|
|
4131
|
+
input: process.stdin,
|
|
4132
|
+
output: process.stdout,
|
|
4133
|
+
terminal: false
|
|
4134
|
+
});
|
|
4135
|
+
process.stdin.setRawMode(true);
|
|
4136
|
+
process.stdin.resume();
|
|
4137
|
+
const onData = (data) => {
|
|
4138
|
+
if (data[0] === 3) {
|
|
4139
|
+
process.exit(130);
|
|
4140
|
+
}
|
|
4141
|
+
};
|
|
4142
|
+
process.stdin.on("data", onData);
|
|
4143
|
+
return () => {
|
|
4144
|
+
process.stdin.off("data", onData);
|
|
4145
|
+
process.stdin.setRawMode(false);
|
|
4146
|
+
process.stdin.pause();
|
|
4147
|
+
rl.close();
|
|
4148
|
+
};
|
|
4149
|
+
}
|
|
4150
|
+
var RETRY_DELAY_MS = 500;
|
|
4151
|
+
var MAX_RETRIES = 3;
|
|
4152
|
+
function sleep(ms) {
|
|
4153
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4154
|
+
}
|
|
4155
|
+
function isRetryableError(error) {
|
|
4156
|
+
if (!(error instanceof Error)) {
|
|
4157
|
+
return false;
|
|
4158
|
+
}
|
|
4159
|
+
const message = error.message;
|
|
4160
|
+
return message.includes("ECONNREFUSED") || message === "UNITY_NO_RESPONSE";
|
|
4161
|
+
}
|
|
4162
|
+
function checkUnityBusyState() {
|
|
4163
|
+
const projectRoot = findUnityProjectRoot();
|
|
4164
|
+
if (projectRoot === null) {
|
|
4165
|
+
return;
|
|
4166
|
+
}
|
|
4167
|
+
const compilingLock = (0, import_path4.join)(projectRoot, "Temp", "compiling.lock");
|
|
4168
|
+
if ((0, import_fs3.existsSync)(compilingLock)) {
|
|
4169
|
+
throw new Error("UNITY_COMPILING");
|
|
4170
|
+
}
|
|
4171
|
+
const domainReloadLock = (0, import_path4.join)(projectRoot, "Temp", "domainreload.lock");
|
|
4172
|
+
if ((0, import_fs3.existsSync)(domainReloadLock)) {
|
|
4173
|
+
throw new Error("UNITY_DOMAIN_RELOAD");
|
|
4174
|
+
}
|
|
4175
|
+
const serverStartingLock = (0, import_path4.join)(projectRoot, "Temp", "serverstarting.lock");
|
|
4176
|
+
if ((0, import_fs3.existsSync)(serverStartingLock)) {
|
|
4177
|
+
throw new Error("UNITY_SERVER_STARTING");
|
|
4178
|
+
}
|
|
4179
|
+
}
|
|
4088
4180
|
async function executeToolCommand(toolName, params, globalOptions) {
|
|
4089
4181
|
let portNumber;
|
|
4090
4182
|
if (globalOptions.port) {
|
|
@@ -4095,14 +4187,38 @@ async function executeToolCommand(toolName, params, globalOptions) {
|
|
|
4095
4187
|
portNumber = parsed;
|
|
4096
4188
|
}
|
|
4097
4189
|
const port = await resolveUnityPort(portNumber);
|
|
4098
|
-
const
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4190
|
+
const restoreStdin = suppressStdinEcho();
|
|
4191
|
+
const spinner = createSpinner("Connecting to Unity...");
|
|
4192
|
+
let lastError;
|
|
4193
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
4194
|
+
checkUnityBusyState();
|
|
4195
|
+
const client = new DirectUnityClient(port);
|
|
4196
|
+
try {
|
|
4197
|
+
await client.connect();
|
|
4198
|
+
spinner.update(`Executing ${toolName}...`);
|
|
4199
|
+
const result = await client.sendRequest(toolName, params);
|
|
4200
|
+
if (result === void 0 || result === null) {
|
|
4201
|
+
throw new Error("UNITY_NO_RESPONSE");
|
|
4202
|
+
}
|
|
4203
|
+
spinner.stop();
|
|
4204
|
+
restoreStdin();
|
|
4205
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4206
|
+
return;
|
|
4207
|
+
} catch (error) {
|
|
4208
|
+
lastError = error;
|
|
4209
|
+
client.disconnect();
|
|
4210
|
+
if (!isRetryableError(error) || attempt >= MAX_RETRIES) {
|
|
4211
|
+
break;
|
|
4212
|
+
}
|
|
4213
|
+
spinner.update("Retrying connection...");
|
|
4214
|
+
await sleep(RETRY_DELAY_MS);
|
|
4215
|
+
} finally {
|
|
4216
|
+
client.disconnect();
|
|
4217
|
+
}
|
|
4105
4218
|
}
|
|
4219
|
+
spinner.stop();
|
|
4220
|
+
restoreStdin();
|
|
4221
|
+
throw lastError;
|
|
4106
4222
|
}
|
|
4107
4223
|
async function listAvailableTools(globalOptions) {
|
|
4108
4224
|
let portNumber;
|
|
@@ -4114,19 +4230,40 @@ async function listAvailableTools(globalOptions) {
|
|
|
4114
4230
|
portNumber = parsed;
|
|
4115
4231
|
}
|
|
4116
4232
|
const port = await resolveUnityPort(portNumber);
|
|
4117
|
-
const
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4233
|
+
const restoreStdin = suppressStdinEcho();
|
|
4234
|
+
const spinner = createSpinner("Connecting to Unity...");
|
|
4235
|
+
let lastError;
|
|
4236
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
4237
|
+
checkUnityBusyState();
|
|
4238
|
+
const client = new DirectUnityClient(port);
|
|
4239
|
+
try {
|
|
4240
|
+
await client.connect();
|
|
4241
|
+
spinner.update("Fetching tool list...");
|
|
4242
|
+
const result = await client.sendRequest("get-tool-details", { IncludeDevelopmentOnly: false });
|
|
4243
|
+
if (!result.Tools || !Array.isArray(result.Tools)) {
|
|
4244
|
+
throw new Error("Unexpected response from Unity: missing Tools array");
|
|
4245
|
+
}
|
|
4246
|
+
spinner.stop();
|
|
4247
|
+
restoreStdin();
|
|
4248
|
+
for (const tool of result.Tools) {
|
|
4249
|
+
console.log(` - ${tool.name}`);
|
|
4250
|
+
}
|
|
4251
|
+
return;
|
|
4252
|
+
} catch (error) {
|
|
4253
|
+
lastError = error;
|
|
4254
|
+
client.disconnect();
|
|
4255
|
+
if (!isRetryableError(error) || attempt >= MAX_RETRIES) {
|
|
4256
|
+
break;
|
|
4257
|
+
}
|
|
4258
|
+
spinner.update("Retrying connection...");
|
|
4259
|
+
await sleep(RETRY_DELAY_MS);
|
|
4260
|
+
} finally {
|
|
4261
|
+
client.disconnect();
|
|
4126
4262
|
}
|
|
4127
|
-
} finally {
|
|
4128
|
-
client.disconnect();
|
|
4129
4263
|
}
|
|
4264
|
+
spinner.stop();
|
|
4265
|
+
restoreStdin();
|
|
4266
|
+
throw lastError;
|
|
4130
4267
|
}
|
|
4131
4268
|
function convertProperties(unityProps) {
|
|
4132
4269
|
const result = {};
|
|
@@ -4150,35 +4287,57 @@ async function syncTools(globalOptions) {
|
|
|
4150
4287
|
portNumber = parsed;
|
|
4151
4288
|
}
|
|
4152
4289
|
const port = await resolveUnityPort(portNumber);
|
|
4153
|
-
const
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4290
|
+
const restoreStdin = suppressStdinEcho();
|
|
4291
|
+
const spinner = createSpinner("Connecting to Unity...");
|
|
4292
|
+
let lastError;
|
|
4293
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
4294
|
+
checkUnityBusyState();
|
|
4295
|
+
const client = new DirectUnityClient(port);
|
|
4296
|
+
try {
|
|
4297
|
+
await client.connect();
|
|
4298
|
+
spinner.update("Syncing tools...");
|
|
4299
|
+
const result = await client.sendRequest("get-tool-details", { IncludeDevelopmentOnly: false });
|
|
4300
|
+
spinner.stop();
|
|
4301
|
+
if (!result.Tools || !Array.isArray(result.Tools)) {
|
|
4302
|
+
restoreStdin();
|
|
4303
|
+
throw new Error("Unexpected response from Unity: missing Tools array");
|
|
4304
|
+
}
|
|
4305
|
+
const cache = {
|
|
4306
|
+
version: VERSION,
|
|
4307
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4308
|
+
tools: result.Tools.map((tool) => ({
|
|
4309
|
+
name: tool.name,
|
|
4310
|
+
description: tool.description,
|
|
4311
|
+
inputSchema: {
|
|
4312
|
+
type: "object",
|
|
4313
|
+
properties: convertProperties(tool.parameterSchema.Properties),
|
|
4314
|
+
required: tool.parameterSchema.Required
|
|
4315
|
+
}
|
|
4316
|
+
}))
|
|
4317
|
+
};
|
|
4318
|
+
saveToolsCache(cache);
|
|
4319
|
+
console.log(`Synced ${cache.tools.length} tools to ${getCacheFilePath()}`);
|
|
4320
|
+
console.log("\nTools:");
|
|
4321
|
+
for (const tool of cache.tools) {
|
|
4322
|
+
console.log(` - ${tool.name}`);
|
|
4323
|
+
}
|
|
4324
|
+
restoreStdin();
|
|
4325
|
+
return;
|
|
4326
|
+
} catch (error) {
|
|
4327
|
+
lastError = error;
|
|
4328
|
+
client.disconnect();
|
|
4329
|
+
if (!isRetryableError(error) || attempt >= MAX_RETRIES) {
|
|
4330
|
+
break;
|
|
4331
|
+
}
|
|
4332
|
+
spinner.update("Retrying connection...");
|
|
4333
|
+
await sleep(RETRY_DELAY_MS);
|
|
4334
|
+
} finally {
|
|
4335
|
+
client.disconnect();
|
|
4178
4336
|
}
|
|
4179
|
-
} finally {
|
|
4180
|
-
client.disconnect();
|
|
4181
4337
|
}
|
|
4338
|
+
spinner.stop();
|
|
4339
|
+
restoreStdin();
|
|
4340
|
+
throw lastError;
|
|
4182
4341
|
}
|
|
4183
4342
|
|
|
4184
4343
|
// src/arg-parser.ts
|
|
@@ -4188,12 +4347,12 @@ function pascalToKebabCase(pascal) {
|
|
|
4188
4347
|
}
|
|
4189
4348
|
|
|
4190
4349
|
// src/skills/skills-manager.ts
|
|
4191
|
-
var
|
|
4192
|
-
var
|
|
4350
|
+
var import_fs4 = require("fs");
|
|
4351
|
+
var import_path5 = require("path");
|
|
4193
4352
|
var import_os = require("os");
|
|
4194
4353
|
|
|
4195
4354
|
// src/skills/skill-definitions/uloop-compile/SKILL.md
|
|
4196
|
-
var SKILL_default =
|
|
4355
|
+
var SKILL_default = '---\nname: uloop-compile\ndescription: Compile Unity project via uloop CLI. Use when you need to: (1) Verify C# code compiles successfully after editing scripts, (2) Check for compile errors or warnings, (3) Validate script changes before running tests.\n---\n\n# uloop compile\n\nExecute Unity project compilation.\n\n## Usage\n\n```bash\nuloop compile [--force-recompile]\n```\n\n## Parameters\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `--force-recompile` | boolean | Force full recompilation (triggers Domain Reload) |\n\n## Examples\n\n```bash\n# Check compilation\nuloop compile\n\n# Force full recompilation\nuloop compile --force-recompile\n```\n\n## Output\n\nReturns JSON:\n- `Success`: boolean\n- `ErrorCount`: number\n- `WarningCount`: number\n\n## Troubleshooting\n\nIf CLI hangs or shows "Unity is busy" errors after compilation, stale lock files may be preventing connection. Run the following to clean them up:\n\n```bash\nuloop fix\n```\n\nThis removes any leftover lock files (`compiling.lock`, `domainreload.lock`, `serverstarting.lock`) from the Unity project\'s Temp directory.\n';
|
|
4197
4356
|
|
|
4198
4357
|
// src/skills/skill-definitions/uloop-get-logs/SKILL.md
|
|
4199
4358
|
var SKILL_default2 = '---\nname: uloop-get-logs\ndescription: Retrieve Unity Console logs via uloop CLI. Use when you need to: (1) Check for errors or warnings after operations, (2) Debug runtime issues in Unity Editor, (3) Investigate unexpected behavior or exceptions.\n---\n\n# uloop get-logs\n\nRetrieve logs from Unity Console.\n\n## Usage\n\n```bash\nuloop get-logs [options]\n```\n\n## Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `--log-type` | string | `All` | Log type filter: `Error`, `Warning`, `Log`, `All` |\n| `--max-count` | integer | `100` | Maximum number of logs to retrieve |\n| `--search-text` | string | - | Text to search within logs |\n| `--include-stack-trace` | boolean | `true` | Include stack trace in output |\n| `--use-regex` | boolean | `false` | Use regex for search |\n| `--search-in-stack-trace` | boolean | `false` | Search within stack trace |\n\n## Examples\n\n```bash\n# Get all logs\nuloop get-logs\n\n# Get only errors\nuloop get-logs --log-type Error\n\n# Search for specific text\nuloop get-logs --search-text "NullReference"\n\n# Regex search\nuloop get-logs --search-text "Missing.*Component" --use-regex\n```\n\n## Output\n\nReturns JSON array of log entries with message, type, and optional stack trace.\n';
|
|
@@ -4270,25 +4429,25 @@ var BUNDLED_SKILLS = [
|
|
|
4270
4429
|
|
|
4271
4430
|
// src/skills/skills-manager.ts
|
|
4272
4431
|
function getGlobalSkillsDir() {
|
|
4273
|
-
return (0,
|
|
4432
|
+
return (0, import_path5.join)((0, import_os.homedir)(), ".claude", "skills");
|
|
4274
4433
|
}
|
|
4275
4434
|
function getProjectSkillsDir() {
|
|
4276
|
-
return (0,
|
|
4435
|
+
return (0, import_path5.join)(process.cwd(), ".claude", "skills");
|
|
4277
4436
|
}
|
|
4278
4437
|
function getSkillPath(skillDirName, global) {
|
|
4279
4438
|
const baseDir = global ? getGlobalSkillsDir() : getProjectSkillsDir();
|
|
4280
|
-
return (0,
|
|
4439
|
+
return (0, import_path5.join)(baseDir, skillDirName, "SKILL.md");
|
|
4281
4440
|
}
|
|
4282
4441
|
function isSkillInstalled(skill, global) {
|
|
4283
4442
|
const skillPath = getSkillPath(skill.dirName, global);
|
|
4284
|
-
return (0,
|
|
4443
|
+
return (0, import_fs4.existsSync)(skillPath);
|
|
4285
4444
|
}
|
|
4286
4445
|
function isSkillOutdated(skill, global) {
|
|
4287
4446
|
const skillPath = getSkillPath(skill.dirName, global);
|
|
4288
|
-
if (!(0,
|
|
4447
|
+
if (!(0, import_fs4.existsSync)(skillPath)) {
|
|
4289
4448
|
return false;
|
|
4290
4449
|
}
|
|
4291
|
-
const installedContent = (0,
|
|
4450
|
+
const installedContent = (0, import_fs4.readFileSync)(skillPath, "utf-8");
|
|
4292
4451
|
return installedContent !== skill.content;
|
|
4293
4452
|
}
|
|
4294
4453
|
function getSkillStatus(skill, global) {
|
|
@@ -4309,18 +4468,18 @@ function getAllSkillStatuses(global) {
|
|
|
4309
4468
|
}
|
|
4310
4469
|
function installSkill(skill, global) {
|
|
4311
4470
|
const baseDir = global ? getGlobalSkillsDir() : getProjectSkillsDir();
|
|
4312
|
-
const skillDir = (0,
|
|
4313
|
-
const skillPath = (0,
|
|
4314
|
-
(0,
|
|
4315
|
-
(0,
|
|
4471
|
+
const skillDir = (0, import_path5.join)(baseDir, skill.dirName);
|
|
4472
|
+
const skillPath = (0, import_path5.join)(skillDir, "SKILL.md");
|
|
4473
|
+
(0, import_fs4.mkdirSync)(skillDir, { recursive: true });
|
|
4474
|
+
(0, import_fs4.writeFileSync)(skillPath, skill.content, "utf-8");
|
|
4316
4475
|
}
|
|
4317
4476
|
function uninstallSkill(skill, global) {
|
|
4318
4477
|
const baseDir = global ? getGlobalSkillsDir() : getProjectSkillsDir();
|
|
4319
|
-
const skillDir = (0,
|
|
4320
|
-
if (!(0,
|
|
4478
|
+
const skillDir = (0, import_path5.join)(baseDir, skill.dirName);
|
|
4479
|
+
if (!(0, import_fs4.existsSync)(skillDir)) {
|
|
4321
4480
|
return false;
|
|
4322
4481
|
}
|
|
4323
|
-
(0,
|
|
4482
|
+
(0, import_fs4.rmSync)(skillDir, { recursive: true, force: true });
|
|
4324
4483
|
return true;
|
|
4325
4484
|
}
|
|
4326
4485
|
function installAllSkills(global) {
|
|
@@ -4438,7 +4597,7 @@ Uninstalling uloop skills (${location})...`);
|
|
|
4438
4597
|
}
|
|
4439
4598
|
|
|
4440
4599
|
// src/cli.ts
|
|
4441
|
-
var BUILTIN_COMMANDS = ["list", "sync", "completion", "update", "skills"];
|
|
4600
|
+
var BUILTIN_COMMANDS = ["list", "sync", "completion", "update", "fix", "skills"];
|
|
4442
4601
|
var program2 = new Command();
|
|
4443
4602
|
program2.name("uloop").description("Unity MCP CLI - Direct communication with Unity Editor").version(VERSION, "-v, --version", "Output the version number");
|
|
4444
4603
|
program2.option("--list-commands", "List all command names (for shell completion)");
|
|
@@ -4455,6 +4614,9 @@ program2.command("completion").description("Setup shell completion").option("--i
|
|
|
4455
4614
|
program2.command("update").description("Update uloop CLI to the latest version").action(() => {
|
|
4456
4615
|
updateCli();
|
|
4457
4616
|
});
|
|
4617
|
+
program2.command("fix").description("Clean up stale lock files that may prevent CLI from connecting").action(() => {
|
|
4618
|
+
cleanupLockFiles();
|
|
4619
|
+
});
|
|
4458
4620
|
registerSkillsCommand(program2);
|
|
4459
4621
|
var toolsCache = loadToolsCache();
|
|
4460
4622
|
for (const tool of toolsCache.tools) {
|
|
@@ -4538,27 +4700,34 @@ function extractGlobalOptions(options) {
|
|
|
4538
4700
|
port: options["port"]
|
|
4539
4701
|
};
|
|
4540
4702
|
}
|
|
4541
|
-
function isDomainReloadLockFilePresent() {
|
|
4542
|
-
const projectRoot = findUnityProjectRoot();
|
|
4543
|
-
if (projectRoot === null) {
|
|
4544
|
-
return false;
|
|
4545
|
-
}
|
|
4546
|
-
const lockPath = (0, import_path5.join)(projectRoot, "Temp", "domainreload.lock");
|
|
4547
|
-
return (0, import_fs4.existsSync)(lockPath);
|
|
4548
|
-
}
|
|
4549
4703
|
async function runWithErrorHandling(fn) {
|
|
4550
4704
|
try {
|
|
4551
4705
|
await fn();
|
|
4552
4706
|
} catch (error) {
|
|
4553
4707
|
const message = error instanceof Error ? error.message : String(error);
|
|
4708
|
+
if (message === "UNITY_COMPILING") {
|
|
4709
|
+
console.error("\x1B[33m\u23F3 Unity is compiling scripts.\x1B[0m");
|
|
4710
|
+
console.error("Please wait for compilation to finish and try again.");
|
|
4711
|
+
process.exit(1);
|
|
4712
|
+
}
|
|
4713
|
+
if (message === "UNITY_DOMAIN_RELOAD") {
|
|
4714
|
+
console.error("\x1B[33m\u23F3 Unity is reloading (Domain Reload in progress).\x1B[0m");
|
|
4715
|
+
console.error("Please wait a moment and try again.");
|
|
4716
|
+
process.exit(1);
|
|
4717
|
+
}
|
|
4718
|
+
if (message === "UNITY_SERVER_STARTING") {
|
|
4719
|
+
console.error("\x1B[33m\u23F3 Unity server is starting.\x1B[0m");
|
|
4720
|
+
console.error("Please wait a moment and try again.");
|
|
4721
|
+
process.exit(1);
|
|
4722
|
+
}
|
|
4723
|
+
if (message === "UNITY_NO_RESPONSE") {
|
|
4724
|
+
console.error("\x1B[33m\u23F3 Unity is busy (no response received).\x1B[0m");
|
|
4725
|
+
console.error("Unity may be compiling, reloading, or starting. Please wait and try again.");
|
|
4726
|
+
process.exit(1);
|
|
4727
|
+
}
|
|
4554
4728
|
if (message.includes("ECONNREFUSED")) {
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
console.error("Please wait a moment and try again.");
|
|
4558
|
-
} else {
|
|
4559
|
-
console.error("\x1B[31mError: Cannot connect to Unity.\x1B[0m");
|
|
4560
|
-
console.error("Make sure Unity is running with uLoopMCP installed.");
|
|
4561
|
-
}
|
|
4729
|
+
console.error("\x1B[31mError: Cannot connect to Unity.\x1B[0m");
|
|
4730
|
+
console.error("Make sure Unity is running with uLoopMCP installed.");
|
|
4562
4731
|
process.exit(1);
|
|
4563
4732
|
}
|
|
4564
4733
|
console.error(`\x1B[31mError: ${message}\x1B[0m`);
|
|
@@ -4567,7 +4736,7 @@ async function runWithErrorHandling(fn) {
|
|
|
4567
4736
|
}
|
|
4568
4737
|
function detectShell() {
|
|
4569
4738
|
const shell = process.env["SHELL"] || "";
|
|
4570
|
-
const shellName = (0,
|
|
4739
|
+
const shellName = (0, import_path6.basename)(shell).replace(/\.exe$/i, "");
|
|
4571
4740
|
if (shellName === "zsh") {
|
|
4572
4741
|
return "zsh";
|
|
4573
4742
|
}
|
|
@@ -4582,12 +4751,12 @@ function detectShell() {
|
|
|
4582
4751
|
function getShellConfigPath(shell) {
|
|
4583
4752
|
const home = (0, import_os2.homedir)();
|
|
4584
4753
|
if (shell === "zsh") {
|
|
4585
|
-
return (0,
|
|
4754
|
+
return (0, import_path6.join)(home, ".zshrc");
|
|
4586
4755
|
}
|
|
4587
4756
|
if (shell === "powershell") {
|
|
4588
|
-
return (0,
|
|
4757
|
+
return (0, import_path6.join)(home, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1");
|
|
4589
4758
|
}
|
|
4590
|
-
return (0,
|
|
4759
|
+
return (0, import_path6.join)(home, ".bashrc");
|
|
4591
4760
|
}
|
|
4592
4761
|
function getCompletionScript(shell) {
|
|
4593
4762
|
if (shell === "bash") {
|
|
@@ -4663,6 +4832,30 @@ function updateCli() {
|
|
|
4663
4832
|
process.exit(1);
|
|
4664
4833
|
});
|
|
4665
4834
|
}
|
|
4835
|
+
var LOCK_FILES = ["compiling.lock", "domainreload.lock", "serverstarting.lock"];
|
|
4836
|
+
function cleanupLockFiles() {
|
|
4837
|
+
const projectRoot = findUnityProjectRoot();
|
|
4838
|
+
if (projectRoot === null) {
|
|
4839
|
+
console.error("Could not find Unity project root.");
|
|
4840
|
+
process.exit(1);
|
|
4841
|
+
}
|
|
4842
|
+
const tempDir = (0, import_path6.join)(projectRoot, "Temp");
|
|
4843
|
+
let cleaned = 0;
|
|
4844
|
+
for (const lockFile of LOCK_FILES) {
|
|
4845
|
+
const lockPath = (0, import_path6.join)(tempDir, lockFile);
|
|
4846
|
+
if ((0, import_fs5.existsSync)(lockPath)) {
|
|
4847
|
+
(0, import_fs5.unlinkSync)(lockPath);
|
|
4848
|
+
console.log(`Removed: ${lockFile}`);
|
|
4849
|
+
cleaned++;
|
|
4850
|
+
}
|
|
4851
|
+
}
|
|
4852
|
+
if (cleaned === 0) {
|
|
4853
|
+
console.log("No lock files found.");
|
|
4854
|
+
} else {
|
|
4855
|
+
console.log(`
|
|
4856
|
+
\u2705 Cleaned up ${cleaned} lock file(s).`);
|
|
4857
|
+
}
|
|
4858
|
+
}
|
|
4666
4859
|
function handleCompletion(install, shellOverride) {
|
|
4667
4860
|
let shell;
|
|
4668
4861
|
if (shellOverride) {
|
|
@@ -4686,13 +4879,13 @@ function handleCompletion(install, shellOverride) {
|
|
|
4686
4879
|
return;
|
|
4687
4880
|
}
|
|
4688
4881
|
const configPath = getShellConfigPath(shell);
|
|
4689
|
-
const configDir = (0,
|
|
4690
|
-
if (!(0,
|
|
4691
|
-
(0,
|
|
4882
|
+
const configDir = (0, import_path6.dirname)(configPath);
|
|
4883
|
+
if (!(0, import_fs5.existsSync)(configDir)) {
|
|
4884
|
+
(0, import_fs5.mkdirSync)(configDir, { recursive: true });
|
|
4692
4885
|
}
|
|
4693
4886
|
let content = "";
|
|
4694
|
-
if ((0,
|
|
4695
|
-
content = (0,
|
|
4887
|
+
if ((0, import_fs5.existsSync)(configPath)) {
|
|
4888
|
+
content = (0, import_fs5.readFileSync)(configPath, "utf-8");
|
|
4696
4889
|
content = content.replace(
|
|
4697
4890
|
/\n?# >>> uloop completion >>>[\s\S]*?# <<< uloop completion <<<\n?/g,
|
|
4698
4891
|
""
|
|
@@ -4706,7 +4899,7 @@ ${startMarker}
|
|
|
4706
4899
|
${script}
|
|
4707
4900
|
${endMarker}
|
|
4708
4901
|
`;
|
|
4709
|
-
(0,
|
|
4902
|
+
(0, import_fs5.writeFileSync)(configPath, content + lineToAdd, "utf-8");
|
|
4710
4903
|
} else {
|
|
4711
4904
|
const evalLine = `eval "$(uloop completion --shell ${shell})"`;
|
|
4712
4905
|
const lineToAdd = `
|
|
@@ -4714,7 +4907,7 @@ ${startMarker}
|
|
|
4714
4907
|
${evalLine}
|
|
4715
4908
|
${endMarker}
|
|
4716
4909
|
`;
|
|
4717
|
-
(0,
|
|
4910
|
+
(0, import_fs5.writeFileSync)(configPath, content + lineToAdd, "utf-8");
|
|
4718
4911
|
}
|
|
4719
4912
|
console.log(`Completion installed to ${configPath}`);
|
|
4720
4913
|
if (shell === "powershell") {
|