uloop-cli 1.6.1 → 1.6.3
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 -10
- package/README_ja.md +3 -10
- package/dist/cli.bundle.cjs +30 -24
- package/dist/cli.bundle.cjs.map +3 -3
- package/package.json +3 -3
- package/src/cli-constants.ts +5 -0
- package/src/cli.ts +12 -6
- package/src/default-tools.json +1 -1
- package/src/execute-tool.ts +2 -1
- package/src/port-resolver.ts +4 -5
- package/src/project-validator.ts +3 -2
- package/src/skills/skill-definitions/cli-only/uloop-focus-window/Skill/SKILL.md +1 -2
- package/src/skills/skills-manager.ts +3 -2
- package/src/version.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uloop-cli",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.3",
|
|
4
4
|
"//version": "x-release-please-version",
|
|
5
5
|
"description": "CLI tool for Unity Editor communication via Unity CLI Loop",
|
|
6
6
|
"main": "dist/cli.bundle.cjs",
|
|
@@ -57,11 +57,11 @@
|
|
|
57
57
|
"eslint-plugin-prettier": "5.5.5",
|
|
58
58
|
"eslint-plugin-security": "4.0.0",
|
|
59
59
|
"jest": "30.3.0",
|
|
60
|
-
"knip": "6.
|
|
60
|
+
"knip": "6.1.1",
|
|
61
61
|
"prettier": "3.8.1",
|
|
62
62
|
"ts-jest": "29.4.6",
|
|
63
63
|
"typescript": "5.9.3",
|
|
64
|
-
"typescript-eslint": "8.
|
|
64
|
+
"typescript-eslint": "8.58.0"
|
|
65
65
|
},
|
|
66
66
|
"overrides": {
|
|
67
67
|
"minimatch": "10.2.4"
|
package/src/cli.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// and object keys come from tool definitions which are internal trusted data
|
|
9
9
|
/* eslint-disable no-console, security/detect-non-literal-fs-filename, security/detect-object-injection */
|
|
10
10
|
|
|
11
|
+
import { PRODUCT_DISPLAY_NAME, MENU_PATH_SERVER } from './cli-constants';
|
|
11
12
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from 'fs';
|
|
12
13
|
import { join, basename, dirname } from 'path';
|
|
13
14
|
import { homedir } from 'os';
|
|
@@ -133,7 +134,7 @@ program.helpCommand(true);
|
|
|
133
134
|
program
|
|
134
135
|
.command('list')
|
|
135
136
|
.description('List all available tools from Unity')
|
|
136
|
-
.
|
|
137
|
+
.addOption(createHiddenPortOption())
|
|
137
138
|
.option('--project-path <path>', 'Unity project path')
|
|
138
139
|
.action(async (options: CliOptions) => {
|
|
139
140
|
await runWithErrorHandling(() => listAvailableTools(extractGlobalOptions(options)));
|
|
@@ -142,7 +143,7 @@ program
|
|
|
142
143
|
program
|
|
143
144
|
.command('sync')
|
|
144
145
|
.description('Sync tool definitions from Unity to local cache')
|
|
145
|
-
.
|
|
146
|
+
.addOption(createHiddenPortOption())
|
|
146
147
|
.option('--project-path <path>', 'Unity project path')
|
|
147
148
|
.action(async (options: CliOptions) => {
|
|
148
149
|
await runWithErrorHandling(() => syncTools(extractGlobalOptions(options)));
|
|
@@ -210,8 +211,7 @@ function registerToolCommand(tool: ToolDefinition, helpGroup: string): void {
|
|
|
210
211
|
}
|
|
211
212
|
}
|
|
212
213
|
|
|
213
|
-
|
|
214
|
-
cmd.option('-p, --port <port>', 'Unity TCP port');
|
|
214
|
+
cmd.addOption(createHiddenPortOption());
|
|
215
215
|
cmd.option('--project-path <path>', 'Unity project path');
|
|
216
216
|
|
|
217
217
|
cmd.action(async (options: CliOptions) => {
|
|
@@ -364,6 +364,11 @@ function getToolHelpGroup(toolName: string, defaultToolNames: ReadonlySet<string
|
|
|
364
364
|
return defaultToolNames.has(toolName) ? HELP_GROUP_BUILTIN_TOOLS : HELP_GROUP_THIRD_PARTY_TOOLS;
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
+
// Option instances are mutated by commander, so each command needs its own
|
|
368
|
+
function createHiddenPortOption(): Option {
|
|
369
|
+
return new Option('-p, --port <port>', 'Unity TCP port').hideHelp();
|
|
370
|
+
}
|
|
371
|
+
|
|
367
372
|
function extractGlobalOptions(options: Record<string, unknown>): GlobalOptions {
|
|
368
373
|
return {
|
|
369
374
|
port: options['port'] as string | undefined,
|
|
@@ -382,7 +387,8 @@ function printToolDisabledError(cmdName: string): void {
|
|
|
382
387
|
|
|
383
388
|
function printConnectionError(): void {
|
|
384
389
|
console.error('\x1b[31mError: Cannot connect to Unity.\x1b[0m');
|
|
385
|
-
console.error(
|
|
390
|
+
console.error(`Make sure Unity Editor is open and ${PRODUCT_DISPLAY_NAME} server is running.`);
|
|
391
|
+
console.error(`You can start the server from: ${MENU_PATH_SERVER}`);
|
|
386
392
|
console.error('');
|
|
387
393
|
console.error('[For AI] Please report the above to the user.');
|
|
388
394
|
}
|
|
@@ -440,7 +446,7 @@ async function runWithErrorHandling(fn: () => Promise<void>): Promise<void> {
|
|
|
440
446
|
console.error('');
|
|
441
447
|
console.error('Another Unity instance was found, but it belongs to a different project.');
|
|
442
448
|
console.error(
|
|
443
|
-
'Start the Unity Editor for this project, or use --
|
|
449
|
+
'Start the Unity Editor for this project, or use --project-path to specify the target.',
|
|
444
450
|
);
|
|
445
451
|
process.exit(1);
|
|
446
452
|
}
|
package/src/default-tools.json
CHANGED
package/src/execute-tool.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// and lock file paths are constructed from trusted project root detection
|
|
8
8
|
/* eslint-disable no-console, security/detect-object-injection, security/detect-non-literal-fs-filename */
|
|
9
9
|
|
|
10
|
+
import { PRODUCT_DISPLAY_NAME } from './cli-constants';
|
|
10
11
|
import * as readline from 'readline';
|
|
11
12
|
import { existsSync } from 'fs';
|
|
12
13
|
import { join } from 'path';
|
|
@@ -138,7 +139,7 @@ function printVersionWarning(cliVersion: string, serverVersion: string): void {
|
|
|
138
139
|
const isCliOlder = isVersionOlder(cliVersion, serverVersion);
|
|
139
140
|
const updateCommand = isCliOlder
|
|
140
141
|
? `npm install -g uloop-cli@${serverVersion}`
|
|
141
|
-
: `Update
|
|
142
|
+
: `Update ${PRODUCT_DISPLAY_NAME} package to ${cliVersion} via Unity Package Manager`;
|
|
142
143
|
|
|
143
144
|
console.error('\x1b[33m⚠️ Version mismatch detected!\x1b[0m');
|
|
144
145
|
console.error(` uloop-cli version: ${cliVersion}`);
|
package/src/port-resolver.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// File paths are constructed from Unity project root detection, not from user input
|
|
7
7
|
/* eslint-disable security/detect-non-literal-fs-filename */
|
|
8
8
|
|
|
9
|
+
import { PRODUCT_DISPLAY_NAME } from './cli-constants';
|
|
9
10
|
import { readFile } from 'fs/promises';
|
|
10
11
|
import { existsSync } from 'fs';
|
|
11
12
|
import { join, resolve } from 'path';
|
|
@@ -61,7 +62,7 @@ export function validateProjectPath(projectPath: string): string {
|
|
|
61
62
|
|
|
62
63
|
if (!hasUloopInstalled(resolved)) {
|
|
63
64
|
throw new Error(
|
|
64
|
-
|
|
65
|
+
`${PRODUCT_DISPLAY_NAME} is not installed in this project (UserSettings/UnityMcpSettings.json not found): ${resolved}`,
|
|
65
66
|
);
|
|
66
67
|
}
|
|
67
68
|
|
|
@@ -87,9 +88,7 @@ export async function resolveUnityPort(
|
|
|
87
88
|
|
|
88
89
|
const projectRoot = findUnityProjectRoot();
|
|
89
90
|
if (projectRoot === null) {
|
|
90
|
-
throw new Error(
|
|
91
|
-
'Unity project not found. Use --port or --project-path option to specify the target.',
|
|
92
|
-
);
|
|
91
|
+
throw new Error('Unity project not found. Use --project-path option to specify the target.');
|
|
93
92
|
}
|
|
94
93
|
|
|
95
94
|
return await readPortFromSettingsOrThrow(projectRoot);
|
|
@@ -100,7 +99,7 @@ function createSettingsReadError(projectRoot: string): Error {
|
|
|
100
99
|
return new Error(
|
|
101
100
|
`Could not read Unity server port from settings.\n\n` +
|
|
102
101
|
` Settings file: ${settingsPath}\n\n` +
|
|
103
|
-
`Run 'uloop launch -r' to restart Unity
|
|
102
|
+
`Run 'uloop launch -r' to restart Unity.`,
|
|
104
103
|
);
|
|
105
104
|
}
|
|
106
105
|
|
package/src/project-validator.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// Paths come from trusted Unity responses and validated project root, console.error for user warnings
|
|
7
7
|
/* eslint-disable security/detect-non-literal-fs-filename, no-console */
|
|
8
8
|
|
|
9
|
+
import { PRODUCT_DISPLAY_NAME } from './cli-constants';
|
|
9
10
|
import assert from 'node:assert';
|
|
10
11
|
import { realpath } from 'fs/promises';
|
|
11
12
|
import { dirname } from 'path';
|
|
@@ -41,7 +42,7 @@ export async function validateConnectedProject(
|
|
|
41
42
|
try {
|
|
42
43
|
response = await client.sendRequest<GetVersionResponse>('get-version', {});
|
|
43
44
|
} catch (error) {
|
|
44
|
-
// Method not found: old
|
|
45
|
+
// Method not found: old package version without get-version tool
|
|
45
46
|
if (
|
|
46
47
|
error instanceof Error &&
|
|
47
48
|
(error.message.includes(`${JSON_RPC_METHOD_NOT_FOUND}`) ||
|
|
@@ -49,7 +50,7 @@ export async function validateConnectedProject(
|
|
|
49
50
|
/unknown tool/i.test(error.message))
|
|
50
51
|
) {
|
|
51
52
|
console.error(
|
|
52
|
-
|
|
53
|
+
`Warning: Could not verify project identity (get-version not available). Consider updating ${PRODUCT_DISPLAY_NAME} package.`,
|
|
53
54
|
);
|
|
54
55
|
return;
|
|
55
56
|
}
|
|
@@ -21,8 +21,7 @@ None.
|
|
|
21
21
|
|
|
22
22
|
| Option | Description |
|
|
23
23
|
|--------|-------------|
|
|
24
|
-
| `--project-path <path>` | Target a specific Unity project
|
|
25
|
-
| `-p, --port <port>` | Specify Unity TCP port directly (mutually exclusive with `--project-path`). |
|
|
24
|
+
| `--project-path <path>` | Target a specific Unity project. Path resolution follows the same rules as `cd` — absolute paths are used as-is, relative paths are resolved from cwd. |
|
|
26
25
|
|
|
27
26
|
## Examples
|
|
28
27
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// File paths are constructed from home directory and skill names, not from untrusted user input
|
|
8
8
|
/* eslint-disable security/detect-non-literal-fs-filename */
|
|
9
9
|
|
|
10
|
+
import { PRODUCT_DISPLAY_NAME } from '../cli-constants';
|
|
10
11
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, rmSync, readdirSync } from 'fs';
|
|
11
12
|
import { join, dirname, resolve, isAbsolute, sep } from 'path';
|
|
12
13
|
import { homedir } from 'os';
|
|
@@ -84,8 +85,8 @@ function getProjectSkillsDir(target: TargetConfig): string {
|
|
|
84
85
|
}
|
|
85
86
|
if (!status.hasUloop) {
|
|
86
87
|
throw new Error(
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
`${PRODUCT_DISPLAY_NAME} is not installed in this Unity project (${status.path}).\n` +
|
|
89
|
+
`Please install ${PRODUCT_DISPLAY_NAME} package first, then run this command again.`,
|
|
89
90
|
);
|
|
90
91
|
}
|
|
91
92
|
return join(status.path as string, target.projectDir, 'skills');
|
package/src/version.ts
CHANGED