uloop-cli 0.55.2 → 0.56.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uloop-cli",
3
- "version": "0.55.2",
3
+ "version": "0.56.0",
4
4
  "//version": "x-release-please-version",
5
5
  "description": "CLI tool for Unity Editor communication via uLoopMCP",
6
6
  "main": "dist/cli.bundle.cjs",
package/src/cli.ts CHANGED
@@ -18,8 +18,15 @@ import {
18
18
  listAvailableTools,
19
19
  GlobalOptions,
20
20
  syncTools,
21
+ isVersionOlder,
21
22
  } from './execute-tool.js';
22
- import { loadToolsCache, hasCacheFile, ToolDefinition, ToolProperty } from './tool-cache.js';
23
+ import {
24
+ loadToolsCache,
25
+ hasCacheFile,
26
+ ToolDefinition,
27
+ ToolProperty,
28
+ getCachedServerVersion,
29
+ } from './tool-cache.js';
23
30
  import { pascalToKebabCase } from './arg-parser.js';
24
31
  import { registerSkillsCommand } from './skills/skills-command.js';
25
32
  import { VERSION } from './version.js';
@@ -274,12 +281,45 @@ function printConnectionError(): void {
274
281
  console.error('[For AI] Please report the above to the user.');
275
282
  }
276
283
 
284
+ /**
285
+ * Print version mismatch diagnostic information when errors occur.
286
+ * Only prints if versions are mismatched.
287
+ */
288
+ function printVersionMismatchDiagnostic(): void {
289
+ const serverVersion = getCachedServerVersion();
290
+ if (serverVersion === undefined) {
291
+ return;
292
+ }
293
+
294
+ if (serverVersion === VERSION) {
295
+ return;
296
+ }
297
+
298
+ const isCliOlder = isVersionOlder(VERSION, serverVersion);
299
+ const action = isCliOlder ? 'Update' : 'Downgrade';
300
+ const updateCommand = `npm install -g uloop-cli@${serverVersion}`;
301
+
302
+ console.error('');
303
+ console.error('\x1b[33m━━━ Version Mismatch Diagnostic ━━━\x1b[0m');
304
+ console.error('');
305
+ console.error(` CLI version: ${VERSION}`);
306
+ console.error(` Unity package: ${serverVersion}`);
307
+ console.error(' Version mismatch may cause communication errors.');
308
+ console.error('');
309
+ console.error(` To fix: ${action} CLI to match Unity package version`);
310
+ console.error(` ${updateCommand}`);
311
+ console.error('');
312
+ console.error('[For AI] Please ask the user if they would like to run this command.');
313
+ console.error('\x1b[33m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m');
314
+ }
315
+
277
316
  async function runWithErrorHandling(fn: () => Promise<void>): Promise<void> {
278
317
  try {
279
318
  await fn();
280
319
  } catch (error) {
281
320
  const message = error instanceof Error ? error.message : String(error);
282
321
 
322
+ // Unity busy states have clear causes - no version diagnostic needed
283
323
  if (message === 'UNITY_COMPILING') {
284
324
  console.error('\x1b[33m⏳ Unity is compiling scripts.\x1b[0m');
285
325
  console.error('Please wait for compilation to finish and try again.');
@@ -298,14 +338,24 @@ async function runWithErrorHandling(fn: () => Promise<void>): Promise<void> {
298
338
  process.exit(1);
299
339
  }
300
340
 
341
+ // Errors that may be caused by version mismatch - show diagnostic
301
342
  if (message === 'UNITY_NO_RESPONSE') {
302
343
  console.error('\x1b[33m⏳ Unity is busy (no response received).\x1b[0m');
303
344
  console.error('Unity may be compiling, reloading, or starting. Please wait and try again.');
345
+ printVersionMismatchDiagnostic();
304
346
  process.exit(1);
305
347
  }
306
348
 
307
349
  if (isConnectionError(message)) {
308
350
  printConnectionError();
351
+ printVersionMismatchDiagnostic();
352
+ process.exit(1);
353
+ }
354
+
355
+ // Timeout errors
356
+ if (message.includes('Request timed out')) {
357
+ console.error(`\x1b[31mError: ${message}\x1b[0m`);
358
+ printVersionMismatchDiagnostic();
309
359
  process.exit(1);
310
360
  }
311
361
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.55.2",
2
+ "version": "0.56.0",
3
3
  "tools": [
4
4
  {
5
5
  "name": "compile",
@@ -142,6 +142,11 @@
142
142
  "IncludePaths": {
143
143
  "type": "boolean",
144
144
  "description": "Include path information"
145
+ },
146
+ "UseSelection": {
147
+ "type": "boolean",
148
+ "description": "Use selected GameObject(s) as root(s). When true, RootPath is ignored.",
149
+ "default": false
145
150
  }
146
151
  }
147
152
  }
@@ -75,7 +75,7 @@ export class DirectUnityClient {
75
75
  const timeoutId = setTimeout(() => {
76
76
  reject(
77
77
  new Error(
78
- `Request timed out after ${NETWORK_TIMEOUT_MS}ms. Unity may be frozen or busy. Please report this to the user and ask how to proceed. Do NOT kill Unity processes without user permission.`,
78
+ `Request timed out after ${NETWORK_TIMEOUT_MS}ms. Unity may be frozen or busy. [For AI] Please report this to the user and ask how to proceed. Do NOT kill Unity processes without user permission.`,
79
79
  ),
80
80
  );
81
81
  }, NETWORK_TIMEOUT_MS);
@@ -80,7 +80,7 @@ function isRetryableError(error: unknown): boolean {
80
80
  * Returns true if v1 < v2, false otherwise.
81
81
  * Falls back to string comparison if versions are invalid.
82
82
  */
83
- function isVersionOlder(v1: string, v2: string): boolean {
83
+ export function isVersionOlder(v1: string, v2: string): boolean {
84
84
  const parsed1 = semver.valid(v1);
85
85
  const parsed2 = semver.valid(v2);
86
86
 
@@ -321,6 +321,7 @@ export async function syncTools(globalOptions: GlobalOptions): Promise<void> {
321
321
  spinner.update('Syncing tools...');
322
322
  const result = await client.sendRequest<{
323
323
  Tools: UnityToolInfo[];
324
+ Ver?: string;
324
325
  }>('get-tool-details', { IncludeDevelopmentOnly: false });
325
326
 
326
327
  spinner.stop();
@@ -331,6 +332,7 @@ export async function syncTools(globalOptions: GlobalOptions): Promise<void> {
331
332
 
332
333
  const cache: ToolsCache = {
333
334
  version: VERSION,
335
+ serverVersion: result.Ver,
334
336
  updatedAt: new Date().toISOString(),
335
337
  tools: result.Tools.map((tool) => ({
336
338
  name: tool.name,
package/src/tool-cache.ts CHANGED
@@ -33,6 +33,7 @@ export interface ToolDefinition {
33
33
 
34
34
  export interface ToolsCache {
35
35
  version: string;
36
+ serverVersion?: string;
36
37
  updatedAt?: string;
37
38
  tools: ToolDefinition[];
38
39
  }
@@ -105,3 +106,23 @@ export function hasCacheFile(): boolean {
105
106
  export function getCacheFilePath(): string {
106
107
  return getCachePath();
107
108
  }
109
+
110
+ /**
111
+ * Get the Unity server version from cache file.
112
+ * Returns undefined if cache doesn't exist, is corrupted, or serverVersion is missing.
113
+ */
114
+ export function getCachedServerVersion(): string | undefined {
115
+ const cachePath = getCachePath();
116
+
117
+ if (!existsSync(cachePath)) {
118
+ return undefined;
119
+ }
120
+
121
+ try {
122
+ const content = readFileSync(cachePath, 'utf-8');
123
+ const cache = JSON.parse(content) as Partial<ToolsCache>;
124
+ return typeof cache.serverVersion === 'string' ? cache.serverVersion : undefined;
125
+ } catch {
126
+ return undefined;
127
+ }
128
+ }
package/src/version.ts CHANGED
@@ -4,4 +4,4 @@
4
4
  * This file exists to avoid bundling the entire package.json into the CLI bundle.
5
5
  * This version is automatically updated by release-please.
6
6
  */
7
- export const VERSION = '0.55.2'; // x-release-please-version
7
+ export const VERSION = '0.56.0'; // x-release-please-version