@notask/unity-cli-tools 1.0.2 → 1.0.4

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/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## [1.0.4](https://github.com/NoTaskStudios/unity-cli-tools/compare/1.0.3...1.0.4) (2025-04-29)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **Hub:** get changeset for editor version installation ([ab4d9ad](https://github.com/NoTaskStudios/unity-cli-tools/commit/ab4d9adaeb3909bf44de5bdbbdde5e9c3ced297f))
7
+
8
+ ## [1.0.3](https://github.com/NoTaskStudios/unity-cli-tools/compare/1.0.2...1.0.3) (2025-04-28)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * change type naming ([0e32839](https://github.com/NoTaskStudios/unity-cli-tools/commit/0e32839146eaa6072dd5f5c54e01033b9a7e1ab6))
14
+ * **Editor:** fix logging sensitive information ([504d4b6](https://github.com/NoTaskStudios/unity-cli-tools/commit/504d4b6caaaa62278c68f13193d8a46c38bb3df1))
15
+
1
16
  ## [1.0.2](https://github.com/NoTaskStudios/unity-cli-tools/compare/1.0.1...1.0.2) (2025-04-23)
2
17
 
3
18
 
package/README.md CHANGED
@@ -88,6 +88,107 @@ const result = await UnityHub.execUnityHubCommand(["editors", "-r"]);
88
88
  console.log(result.stdout);
89
89
  ```
90
90
 
91
+ ## UnityEditor API Reference
92
+
93
+ UnityEditor provides an interface for automating tasks directly in the Unity Editor:
94
+
95
+ ### Installation and Availability
96
+ ```typescript
97
+ import UnityEditor from "@notask/unity-cli-tools";
98
+
99
+ // Get the executable path and verify installation
100
+ const unityPath = UnityEditor.getUnityExecutablePath("2022.3.15f1");
101
+ const isInstalled = await UnityEditor.isUnityVersionInstalled("2022.3.15f1");
102
+ console.log(`Installed: ${isInstalled}`, unityPath);
103
+ ```
104
+
105
+ ### Executing Raw Editor Commands
106
+ ```typescript
107
+ import { CommandResult } from "@notask/unity-cli-tools";
108
+
109
+ const editorInfo = { version: "2022.3.15f1", path: unityPath };
110
+ const result: CommandResult = await UnityEditor.execUnityEditorCommand(
111
+ editorInfo,
112
+ ["-batchmode", "-quit", "-projectPath", "/path/to/project"]
113
+ );
114
+ console.log(result.stdout);
115
+ ```
116
+
117
+ ### Creating and Opening Projects
118
+ ```typescript
119
+ import { ProjectInfo } from "@notask/unity-cli-tools";
120
+
121
+ const projectInfo: ProjectInfo = {
122
+ projectPath: "/path/to/new/project",
123
+ editorVersion: "2022.3.15f1"
124
+ };
125
+
126
+ await UnityEditor.createProject(projectInfo);
127
+ await UnityEditor.openProject(projectInfo, true, true);
128
+ ```
129
+
130
+ ### Running Tests
131
+ ```typescript
132
+ import { ProjectInfo, TestMode } from "@notask/unity-cli-tools";
133
+
134
+ const projectInfo: ProjectInfo = {
135
+ projectPath: "/path/to/project",
136
+ editorVersion: "2022.3.15f1"
137
+ };
138
+
139
+ const { success, output } = await UnityEditor.runTests(projectInfo, TestMode.EditMode);
140
+ console.log(success ? "Tests passed" : "Tests failed", output);
141
+ ```
142
+
143
+ ### License Management
144
+ ```typescript
145
+ import { ProjectInfo } from "@notask/unity-cli-tools";
146
+
147
+ const projectInfo: ProjectInfo = {
148
+ projectPath: "/path/to/project",
149
+ editorVersion: "2022.3.15f1"
150
+ };
151
+
152
+ await UnityEditor.activateLicense(projectInfo, "XXXX-XXXX-XXXX-XXXX-XXXX", "user@example.com", "password");
153
+ await UnityEditor.returnLicense(projectInfo);
154
+ ```
155
+
156
+ ### Importing and Exporting Packages
157
+ ```typescript
158
+ import { ProjectInfo } from "@notask/unity-cli-tools";
159
+
160
+ const projectInfo: ProjectInfo = {
161
+ projectPath: "/path/to/project",
162
+ editorVersion: "2022.3.15f1"
163
+ };
164
+
165
+ await UnityEditor.exportPackage(
166
+ projectInfo,
167
+ ["Assets/UI", "Assets/Scripts"],
168
+ "/path/to/output/MyPackage.unitypackage"
169
+ );
170
+ await UnityEditor.importPackage(
171
+ projectInfo,
172
+ "/path/to/downloads/OtherPackage.unitypackage"
173
+ );
174
+ ```
175
+
176
+ ### Executing Custom Editor Methods
177
+ ```typescript
178
+ import { ProjectInfo } from "@notask/unity-cli-tools";
179
+
180
+ const projectInfo: ProjectInfo = {
181
+ projectPath: "/path/to/project",
182
+ editorVersion: "2022.3.15f1"
183
+ };
184
+
185
+ const executionResult = await UnityEditor.executeMethod(
186
+ projectInfo,
187
+ "MyCompany.BuildTools.PerformBuild"
188
+ );
189
+ console.log(executionResult);
190
+ ```
191
+
91
192
  ## Available Constants
92
193
 
93
194
  ### UnityModules
package/dist/cjs/index.js CHANGED
@@ -17,7 +17,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.UnityHub = void 0;
20
+ exports.UnityEditor = exports.UnityHub = void 0;
21
21
  var unityHub_ts_1 = require("./unityHub.js");
22
22
  Object.defineProperty(exports, "UnityHub", { enumerable: true, get: function () { return __importDefault(unityHub_ts_1).default; } });
23
+ var unityEditor_ts_1 = require("./unityEditor.js");
24
+ Object.defineProperty(exports, "UnityEditor", { enumerable: true, get: function () { return __importDefault(unityEditor_ts_1).default; } });
23
25
  __exportStar(require("./types/unity.js"), exports);
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.UnityBuildTarget = exports.TestMode = exports.EditorArchitecture = exports.UnityLanguages = exports.UnityModules = void 0;
3
+ exports.UnityBuildTarget = exports.TestMode = exports.EditorArchitecture = exports.UnityEditorLanguages = exports.UnityModules = void 0;
4
4
  var UnityModules;
5
5
  (function (UnityModules) {
6
6
  UnityModules["Documentation"] = "documentation";
@@ -23,14 +23,14 @@ var UnityModules;
23
23
  UnityModules["UWPBuildSupportIL2CPP"] = "uwp-il2cpp";
24
24
  UnityModules["UWPBuildSupportDotNet"] = "uwp-.net";
25
25
  })(UnityModules || (exports.UnityModules = UnityModules = {}));
26
- var UnityLanguages;
27
- (function (UnityLanguages) {
28
- UnityLanguages["Japanese"] = "language-ja";
29
- UnityLanguages["Korean"] = "language-ko";
30
- UnityLanguages["ChineseSimplified"] = "language-zh-hans";
31
- UnityLanguages["ChineseTraditional"] = "language-zh-hant";
32
- UnityLanguages["Chinese"] = "language-zh-cn";
33
- })(UnityLanguages || (exports.UnityLanguages = UnityLanguages = {}));
26
+ var UnityEditorLanguages;
27
+ (function (UnityEditorLanguages) {
28
+ UnityEditorLanguages["Japanese"] = "language-ja";
29
+ UnityEditorLanguages["Korean"] = "language-ko";
30
+ UnityEditorLanguages["ChineseSimplified"] = "language-zh-hans";
31
+ UnityEditorLanguages["ChineseTraditional"] = "language-zh-hant";
32
+ UnityEditorLanguages["Chinese"] = "language-zh-cn";
33
+ })(UnityEditorLanguages || (exports.UnityEditorLanguages = UnityEditorLanguages = {}));
34
34
  var EditorArchitecture;
35
35
  (function (EditorArchitecture) {
36
36
  EditorArchitecture["x86_64"] = "x86_64";
@@ -0,0 +1,295 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const os_1 = __importDefault(require("os"));
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const unity_js_1 = require("./types/unity.js");
10
+ const commandExecutor_js_1 = require("./utils/commandExecutor.js");
11
+ class UnityEditor {
12
+ static UNITY_PATHS = {
13
+ win32: {
14
+ base: "C:/Program Files/Unity/Hub/Editor",
15
+ executable: "Editor/Unity.exe",
16
+ },
17
+ darwin: {
18
+ base: "/Applications/Unity/Hub/Editor",
19
+ executable: "Unity.app/Contents/MacOS/Unity",
20
+ },
21
+ linux: {
22
+ base: "/opt/unity/editor",
23
+ executable: "Editor/Unity",
24
+ },
25
+ };
26
+ static getUnityExecutablePath(version) {
27
+ const platform = os_1.default.platform();
28
+ const unityConfig = UnityEditor.UNITY_PATHS[platform];
29
+ const unityPath = path_1.default.join(unityConfig.base, version, unityConfig.executable);
30
+ return unityPath;
31
+ }
32
+ static async isUnityVersionInstalled(version) {
33
+ try {
34
+ const unityPath = this.getUnityExecutablePath(version);
35
+ return fs_extra_1.default.existsSync(unityPath);
36
+ }
37
+ catch (error) {
38
+ console.error(error);
39
+ return false;
40
+ }
41
+ }
42
+ static async execUnityEditorCommand(editorInfo, args, options = {}) {
43
+ try {
44
+ const unityPath = this.getUnityExecutablePath(editorInfo.version);
45
+ if (!fs_extra_1.default.existsSync(unityPath)) {
46
+ return {
47
+ success: false,
48
+ stdout: "",
49
+ stderr: `Unity executable not found at path: ${unityPath}`,
50
+ exitCode: -1,
51
+ };
52
+ }
53
+ const editorArgs = [...args];
54
+ const redactedArgs = redactSensitiveArgs(editorArgs);
55
+ console.debug(`Executing Unity Editor command: ${unityPath} ${redactedArgs.join(" ")}`);
56
+ return await (0, commandExecutor_js_1.executeCommand)(unityPath, editorArgs, options);
57
+ }
58
+ catch (error) {
59
+ console.error("Error executing Unity Editor command:", error);
60
+ return {
61
+ success: false,
62
+ stdout: "",
63
+ stderr: String(error),
64
+ exitCode: -1,
65
+ };
66
+ }
67
+ }
68
+ static async executeMethod(projectInfo, method, args = [], options = {}) {
69
+ try {
70
+ console.debug(`Executing method ${method} in Unity Editor`);
71
+ const unityPath = this.getUnityExecutablePath(projectInfo.editorVersion);
72
+ const editorArgs = ["-projectPath", projectInfo.projectPath, "-executeMethod", method, ...args];
73
+ const { stdout, stderr } = await this.execUnityEditorCommand({ version: projectInfo.editorVersion, path: unityPath }, editorArgs, options);
74
+ if (stderr) {
75
+ console.error(`Error executing method: ${stderr}`);
76
+ return null;
77
+ }
78
+ return stdout;
79
+ }
80
+ catch (error) {
81
+ console.error("Error executing method:", error);
82
+ return null;
83
+ }
84
+ }
85
+ static async runTests(projectInfo, testPlatform = unity_js_1.TestMode.EditMode, testCategory) {
86
+ try {
87
+ console.debug(`Running ${testPlatform} tests for project ${testCategory ? ` in category ${testCategory}` : ""}`);
88
+ const args = [
89
+ "-batchmode",
90
+ "-quit",
91
+ "-projectPath",
92
+ projectInfo.projectPath,
93
+ "-runTests",
94
+ "-testPlatform",
95
+ testPlatform,
96
+ ];
97
+ if (testCategory) {
98
+ args.push("-testCategory", testCategory);
99
+ }
100
+ const editorInfo = { version: projectInfo.editorVersion };
101
+ const { stdout, stderr } = await this.execUnityEditorCommand(editorInfo, args, {
102
+ reject: false,
103
+ });
104
+ const testsFailed = stdout.includes("Some tests failed") ||
105
+ stdout.includes("Test run failed") ||
106
+ stderr.includes("Test run failed");
107
+ return {
108
+ success: !testsFailed,
109
+ output: stdout,
110
+ };
111
+ }
112
+ catch (error) {
113
+ console.error("Error running tests:", error);
114
+ return {
115
+ success: false,
116
+ output: String(error),
117
+ };
118
+ }
119
+ }
120
+ static async activateLicense(projectInfo, serial, username, password) {
121
+ try {
122
+ console.debug(`Activating Unity license for version ${projectInfo.editorVersion}`);
123
+ const args = ["-quit", "-serial", serial, "-username", username, "-password", password];
124
+ const editorInfo = { version: projectInfo.editorVersion };
125
+ const { stdout, stderr } = await this.execUnityEditorCommand(editorInfo, args, {
126
+ reject: false,
127
+ });
128
+ const activationSuccessful = stdout.includes("successfully activated") ||
129
+ (!stdout.includes("License activation failed") && !stderr.includes("License activation failed"));
130
+ if (activationSuccessful) {
131
+ console.info(`Successfully activated license for Unity ${projectInfo.editorVersion}`);
132
+ return true;
133
+ }
134
+ else {
135
+ console.error(`Failed to activate license: ${stderr || stdout}`);
136
+ return false;
137
+ }
138
+ }
139
+ catch (error) {
140
+ console.error("Error activating license:", error);
141
+ return false;
142
+ }
143
+ }
144
+ static async returnLicense(projectInfo) {
145
+ try {
146
+ console.debug(`Returning Unity license for version ${projectInfo.editorVersion}`);
147
+ const args = ["-quit", "-returnlicense"];
148
+ const editorInfo = { version: projectInfo.editorVersion };
149
+ const { stdout, stderr } = await this.execUnityEditorCommand(editorInfo, args, {
150
+ reject: false,
151
+ });
152
+ const returnSuccessful = stdout.includes("license return succeeded") ||
153
+ (!stdout.includes("Failed to return license") && !stderr.includes("Failed to return license"));
154
+ if (returnSuccessful) {
155
+ console.info(`Successfully returned license for Unity ${projectInfo.editorVersion}`);
156
+ return true;
157
+ }
158
+ else {
159
+ console.error(`Failed to return license: ${stderr || stdout}`);
160
+ return false;
161
+ }
162
+ }
163
+ catch (error) {
164
+ console.error("Error returning license:", error);
165
+ return false;
166
+ }
167
+ }
168
+ static async exportPackage(projectInfo, assetPaths, outputPath) {
169
+ try {
170
+ console.debug(`Exporting package from project`);
171
+ const args = ["-projectPath", projectInfo.projectPath, "-exportPackage", ...assetPaths, outputPath, "-quit"];
172
+ const editorInfo = { version: projectInfo.editorVersion };
173
+ const { stdout, stderr } = await this.execUnityEditorCommand(editorInfo, args, {
174
+ reject: false,
175
+ });
176
+ const exportSuccessful = !stdout.includes("Failed to export package") && !stderr.includes("Failed to export package");
177
+ if (exportSuccessful) {
178
+ console.info(`Successfully exported package to ${outputPath}`);
179
+ return true;
180
+ }
181
+ else {
182
+ console.error(`Failed to export package: ${stderr || stdout}`);
183
+ return false;
184
+ }
185
+ }
186
+ catch (error) {
187
+ console.error("Error exporting package:", error);
188
+ return false;
189
+ }
190
+ }
191
+ static async importPackage(projectInfo, packagePath) {
192
+ try {
193
+ console.debug(`Importing package ${packagePath} to project`);
194
+ const args = ["-projectPath", projectInfo.projectPath, "-importPackage", packagePath, "-quit"];
195
+ const editorInfo = { version: projectInfo.editorVersion };
196
+ const { stdout, stderr } = await this.execUnityEditorCommand(editorInfo, args, {
197
+ reject: false,
198
+ });
199
+ const importSuccessful = !stdout.includes("Failed to import package") && !stderr.includes("Failed to import package");
200
+ if (importSuccessful) {
201
+ console.info(`Successfully imported package ${packagePath}`);
202
+ return true;
203
+ }
204
+ else {
205
+ console.error(`Failed to import package: ${stderr || stdout}`);
206
+ return false;
207
+ }
208
+ }
209
+ catch (error) {
210
+ console.error("Error importing package:", error);
211
+ return false;
212
+ }
213
+ }
214
+ static async createProject(projectInfo, waitForExit = true) {
215
+ try {
216
+ console.debug(`Creating new project at ${projectInfo.projectPath}`);
217
+ const parentDir = path_1.default.dirname(projectInfo.projectPath);
218
+ await fs_extra_1.default.ensureDir(parentDir);
219
+ const args = ["-createProject", projectInfo.projectPath];
220
+ if (waitForExit) {
221
+ args.push("-quit");
222
+ }
223
+ const editorInfo = { version: projectInfo.editorVersion };
224
+ const { stdout, stderr } = await this.execUnityEditorCommand(editorInfo, args, {
225
+ reject: false,
226
+ });
227
+ const creationSuccessful = !stdout.includes("Failed to create project") && !stderr.includes("Failed to create project");
228
+ if (creationSuccessful) {
229
+ console.info(`Successfully created project at ${projectInfo.projectPath}`);
230
+ return true;
231
+ }
232
+ else {
233
+ console.error(`Failed to create project: ${stderr || stdout}`);
234
+ return false;
235
+ }
236
+ }
237
+ catch (error) {
238
+ console.error("Error creating project:", error);
239
+ return false;
240
+ }
241
+ }
242
+ static async openProject(projectInfo, batchmode = false, waitForExit = true) {
243
+ try {
244
+ console.debug(`Opening project at ${projectInfo.projectPath}`);
245
+ const args = ["-projectPath", projectInfo.projectPath];
246
+ if (waitForExit) {
247
+ args.push("-quit");
248
+ }
249
+ if (batchmode) {
250
+ args.push("-batchmode");
251
+ }
252
+ const editorInfo = { version: projectInfo.editorVersion };
253
+ const options = { reject: false };
254
+ const { stdout, stderr } = await this.execUnityEditorCommand(editorInfo, args, options);
255
+ const openingSuccessful = !stdout.includes("Failed to open project") && !stderr.includes("Failed to open project");
256
+ if (openingSuccessful) {
257
+ console.info(`Successfully opened project`);
258
+ return true;
259
+ }
260
+ else {
261
+ console.error(`Failed to open project: ${stderr || stdout}`);
262
+ return false;
263
+ }
264
+ }
265
+ catch (error) {
266
+ console.error("Error opening project:", error);
267
+ return false;
268
+ }
269
+ }
270
+ }
271
+ function redactSensitiveArgs(argv, sensitiveKeys = ["password", "token", "secret"]) {
272
+ const redacted = [...argv];
273
+ for (let i = 0; i < redacted.length; i++) {
274
+ const arg = redacted[i];
275
+ if (arg.startsWith("--") || arg.startsWith("-")) {
276
+ const key = arg.replace(/^--?/, "");
277
+ if (sensitiveKeys.includes(key.toLowerCase())) {
278
+ if (i + 1 < redacted.length && !redacted[i + 1].startsWith("-")) {
279
+ redacted[i + 1] = "[REDACTED]";
280
+ }
281
+ }
282
+ }
283
+ else {
284
+ const match = arg.match(/^--?([^=]+)=(.+)$/);
285
+ if (match) {
286
+ const key = match[1];
287
+ if (sensitiveKeys.includes(key.toLowerCase())) {
288
+ redacted[i] = `--${key}=[REDACTED]`;
289
+ }
290
+ }
291
+ }
292
+ }
293
+ return redacted;
294
+ }
295
+ exports.default = UnityEditor;
@@ -8,6 +8,7 @@ const os_1 = __importDefault(require("os"));
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const unity_js_1 = require("./types/unity.js");
10
10
  const commandExecutor_js_1 = require("./utils/commandExecutor.js");
11
+ const unity_changeset_1 = require("unity-changeset");
11
12
  class UnityHub {
12
13
  static CONFIG_PATHS = {
13
14
  win32: {
@@ -27,7 +28,7 @@ class UnityHub {
27
28
  },
28
29
  };
29
30
  static Modules = unity_js_1.UnityModules;
30
- static Languages = unity_js_1.UnityLanguages;
31
+ static Languages = unity_js_1.UnityEditorLanguages;
31
32
  static platform = os_1.default.platform();
32
33
  static hubPath = this.getUnityHubPath();
33
34
  static getUnityHubPath() {
@@ -150,12 +151,12 @@ class UnityHub {
150
151
  throw error;
151
152
  }
152
153
  }
153
- static async addEditor(version, changeset, modules = [], architecture = unity_js_1.EditorArchitecture.x86_64) {
154
+ static async addEditor(version, modules = [], architecture = unity_js_1.EditorArchitecture.x86_64) {
154
155
  try {
155
- console.debug(`Installing Unity ${version} ${(changeset ?? "") ? `(changeset: ${changeset})` : ""}`);
156
+ const data = await (0, unity_changeset_1.getUnityChangeset)(version);
156
157
  const args = ["install", "-v", version];
157
- if (changeset) {
158
- args.push("--changeset", changeset);
158
+ if (data) {
159
+ args.push("--changeset", data.changeset);
159
160
  }
160
161
  if (modules.length > 0) {
161
162
  args.push("--module");
@@ -1,2 +1,3 @@
1
1
  export { default as UnityHub } from "./unityHub.ts";
2
+ export { default as UnityEditor } from "./unityEditor.ts";
2
3
  export * from "./types/unity.ts";
package/dist/esm/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export { default as UnityHub } from "./unityHub.js";
2
+ export { default as UnityEditor } from "./unityEditor.js";
2
3
  export * from "./types/unity.js";
@@ -36,7 +36,7 @@ export declare enum UnityModules {
36
36
  UWPBuildSupportIL2CPP = "uwp-il2cpp",
37
37
  UWPBuildSupportDotNet = "uwp-.net"
38
38
  }
39
- export declare enum UnityLanguages {
39
+ export declare enum UnityEditorLanguages {
40
40
  Japanese = "language-ja",
41
41
  Korean = "language-ko",
42
42
  ChineseSimplified = "language-zh-hans",
@@ -47,19 +47,14 @@ export declare enum EditorArchitecture {
47
47
  x86_64 = "x86_64",
48
48
  arm64 = "arm64"
49
49
  }
50
- export type ModuleId = UnityModules | UnityLanguages;
50
+ export type ModuleId = UnityModules | UnityEditorLanguages;
51
51
  export type UnityInstallations = Record<string, string>;
52
52
  export interface ProjectInfo {
53
- path: string;
54
- editorVersion: string;
55
53
  projectName: string;
54
+ projectPath: string;
55
+ editorVersion: string;
56
56
  scenes?: string[];
57
57
  }
58
- export interface ProjectSettings {
59
- companyName?: string;
60
- productName?: string;
61
- bundleVersion?: string;
62
- }
63
58
  export declare enum TestMode {
64
59
  EditMode = "editmode",
65
60
  PlayMode = "playmode"
@@ -81,11 +76,3 @@ export declare enum UnityBuildTarget {
81
76
  PS5 = "PS5",
82
77
  VisionOS = "VisionOS"
83
78
  }
84
- export interface ParsedVersion {
85
- major: number;
86
- minor: number;
87
- patch: number;
88
- type: string;
89
- revision: number;
90
- original: string;
91
- }
@@ -20,14 +20,14 @@ export var UnityModules;
20
20
  UnityModules["UWPBuildSupportIL2CPP"] = "uwp-il2cpp";
21
21
  UnityModules["UWPBuildSupportDotNet"] = "uwp-.net";
22
22
  })(UnityModules || (UnityModules = {}));
23
- export var UnityLanguages;
24
- (function (UnityLanguages) {
25
- UnityLanguages["Japanese"] = "language-ja";
26
- UnityLanguages["Korean"] = "language-ko";
27
- UnityLanguages["ChineseSimplified"] = "language-zh-hans";
28
- UnityLanguages["ChineseTraditional"] = "language-zh-hant";
29
- UnityLanguages["Chinese"] = "language-zh-cn";
30
- })(UnityLanguages || (UnityLanguages = {}));
23
+ export var UnityEditorLanguages;
24
+ (function (UnityEditorLanguages) {
25
+ UnityEditorLanguages["Japanese"] = "language-ja";
26
+ UnityEditorLanguages["Korean"] = "language-ko";
27
+ UnityEditorLanguages["ChineseSimplified"] = "language-zh-hans";
28
+ UnityEditorLanguages["ChineseTraditional"] = "language-zh-hant";
29
+ UnityEditorLanguages["Chinese"] = "language-zh-cn";
30
+ })(UnityEditorLanguages || (UnityEditorLanguages = {}));
31
31
  export var EditorArchitecture;
32
32
  (function (EditorArchitecture) {
33
33
  EditorArchitecture["x86_64"] = "x86_64";
@@ -0,0 +1,19 @@
1
+ import { ProjectInfo, TestMode, UnityBuildTarget, UnityEditorInfo } from "./types/unity.js";
2
+ import { CommandOptions, CommandResult } from "./utils/commandExecutor.js";
3
+ declare class UnityEditor {
4
+ static getUnityExecutablePath(version: string): string;
5
+ static isUnityVersionInstalled(version: string): Promise<boolean>;
6
+ static execUnityEditorCommand(editorInfo: UnityEditorInfo, args: string[], options?: CommandOptions): Promise<CommandResult>;
7
+ static executeMethod(projectInfo: ProjectInfo, method: string, args?: string[], options?: CommandOptions): Promise<any>;
8
+ static runTests(projectInfo: ProjectInfo, testPlatform?: TestMode | UnityBuildTarget, testCategory?: string): Promise<{
9
+ success: boolean;
10
+ output: string;
11
+ }>;
12
+ static activateLicense(projectInfo: ProjectInfo, serial: string, username: string, password: string): Promise<boolean>;
13
+ static returnLicense(projectInfo: ProjectInfo): Promise<boolean>;
14
+ static exportPackage(projectInfo: ProjectInfo, assetPaths: string[], outputPath: string): Promise<boolean>;
15
+ static importPackage(projectInfo: ProjectInfo, packagePath: string): Promise<boolean>;
16
+ static createProject(projectInfo: ProjectInfo, waitForExit?: boolean): Promise<boolean>;
17
+ static openProject(projectInfo: ProjectInfo, batchmode?: boolean, waitForExit?: boolean): Promise<boolean>;
18
+ }
19
+ export default UnityEditor;
@@ -0,0 +1,290 @@
1
+ import os from "os";
2
+ import fs from "fs-extra";
3
+ import path from "path";
4
+ import { TestMode } from "./types/unity.js";
5
+ import { executeCommand } from "./utils/commandExecutor.js";
6
+ class UnityEditor {
7
+ static UNITY_PATHS = {
8
+ win32: {
9
+ base: "C:/Program Files/Unity/Hub/Editor",
10
+ executable: "Editor/Unity.exe",
11
+ },
12
+ darwin: {
13
+ base: "/Applications/Unity/Hub/Editor",
14
+ executable: "Unity.app/Contents/MacOS/Unity",
15
+ },
16
+ linux: {
17
+ base: "/opt/unity/editor",
18
+ executable: "Editor/Unity",
19
+ },
20
+ };
21
+ static getUnityExecutablePath(version) {
22
+ const platform = os.platform();
23
+ const unityConfig = UnityEditor.UNITY_PATHS[platform];
24
+ const unityPath = path.join(unityConfig.base, version, unityConfig.executable);
25
+ return unityPath;
26
+ }
27
+ static async isUnityVersionInstalled(version) {
28
+ try {
29
+ const unityPath = this.getUnityExecutablePath(version);
30
+ return fs.existsSync(unityPath);
31
+ }
32
+ catch (error) {
33
+ console.error(error);
34
+ return false;
35
+ }
36
+ }
37
+ static async execUnityEditorCommand(editorInfo, args, options = {}) {
38
+ try {
39
+ const unityPath = this.getUnityExecutablePath(editorInfo.version);
40
+ if (!fs.existsSync(unityPath)) {
41
+ return {
42
+ success: false,
43
+ stdout: "",
44
+ stderr: `Unity executable not found at path: ${unityPath}`,
45
+ exitCode: -1,
46
+ };
47
+ }
48
+ const editorArgs = [...args];
49
+ const redactedArgs = redactSensitiveArgs(editorArgs);
50
+ console.debug(`Executing Unity Editor command: ${unityPath} ${redactedArgs.join(" ")}`);
51
+ return await executeCommand(unityPath, editorArgs, options);
52
+ }
53
+ catch (error) {
54
+ console.error("Error executing Unity Editor command:", error);
55
+ return {
56
+ success: false,
57
+ stdout: "",
58
+ stderr: String(error),
59
+ exitCode: -1,
60
+ };
61
+ }
62
+ }
63
+ static async executeMethod(projectInfo, method, args = [], options = {}) {
64
+ try {
65
+ console.debug(`Executing method ${method} in Unity Editor`);
66
+ const unityPath = this.getUnityExecutablePath(projectInfo.editorVersion);
67
+ const editorArgs = ["-projectPath", projectInfo.projectPath, "-executeMethod", method, ...args];
68
+ const { stdout, stderr } = await this.execUnityEditorCommand({ version: projectInfo.editorVersion, path: unityPath }, editorArgs, options);
69
+ if (stderr) {
70
+ console.error(`Error executing method: ${stderr}`);
71
+ return null;
72
+ }
73
+ return stdout;
74
+ }
75
+ catch (error) {
76
+ console.error("Error executing method:", error);
77
+ return null;
78
+ }
79
+ }
80
+ static async runTests(projectInfo, testPlatform = TestMode.EditMode, testCategory) {
81
+ try {
82
+ console.debug(`Running ${testPlatform} tests for project ${testCategory ? ` in category ${testCategory}` : ""}`);
83
+ const args = [
84
+ "-batchmode",
85
+ "-quit",
86
+ "-projectPath",
87
+ projectInfo.projectPath,
88
+ "-runTests",
89
+ "-testPlatform",
90
+ testPlatform,
91
+ ];
92
+ if (testCategory) {
93
+ args.push("-testCategory", testCategory);
94
+ }
95
+ const editorInfo = { version: projectInfo.editorVersion };
96
+ const { stdout, stderr } = await this.execUnityEditorCommand(editorInfo, args, {
97
+ reject: false,
98
+ });
99
+ const testsFailed = stdout.includes("Some tests failed") ||
100
+ stdout.includes("Test run failed") ||
101
+ stderr.includes("Test run failed");
102
+ return {
103
+ success: !testsFailed,
104
+ output: stdout,
105
+ };
106
+ }
107
+ catch (error) {
108
+ console.error("Error running tests:", error);
109
+ return {
110
+ success: false,
111
+ output: String(error),
112
+ };
113
+ }
114
+ }
115
+ static async activateLicense(projectInfo, serial, username, password) {
116
+ try {
117
+ console.debug(`Activating Unity license for version ${projectInfo.editorVersion}`);
118
+ const args = ["-quit", "-serial", serial, "-username", username, "-password", password];
119
+ const editorInfo = { version: projectInfo.editorVersion };
120
+ const { stdout, stderr } = await this.execUnityEditorCommand(editorInfo, args, {
121
+ reject: false,
122
+ });
123
+ const activationSuccessful = stdout.includes("successfully activated") ||
124
+ (!stdout.includes("License activation failed") && !stderr.includes("License activation failed"));
125
+ if (activationSuccessful) {
126
+ console.info(`Successfully activated license for Unity ${projectInfo.editorVersion}`);
127
+ return true;
128
+ }
129
+ else {
130
+ console.error(`Failed to activate license: ${stderr || stdout}`);
131
+ return false;
132
+ }
133
+ }
134
+ catch (error) {
135
+ console.error("Error activating license:", error);
136
+ return false;
137
+ }
138
+ }
139
+ static async returnLicense(projectInfo) {
140
+ try {
141
+ console.debug(`Returning Unity license for version ${projectInfo.editorVersion}`);
142
+ const args = ["-quit", "-returnlicense"];
143
+ const editorInfo = { version: projectInfo.editorVersion };
144
+ const { stdout, stderr } = await this.execUnityEditorCommand(editorInfo, args, {
145
+ reject: false,
146
+ });
147
+ const returnSuccessful = stdout.includes("license return succeeded") ||
148
+ (!stdout.includes("Failed to return license") && !stderr.includes("Failed to return license"));
149
+ if (returnSuccessful) {
150
+ console.info(`Successfully returned license for Unity ${projectInfo.editorVersion}`);
151
+ return true;
152
+ }
153
+ else {
154
+ console.error(`Failed to return license: ${stderr || stdout}`);
155
+ return false;
156
+ }
157
+ }
158
+ catch (error) {
159
+ console.error("Error returning license:", error);
160
+ return false;
161
+ }
162
+ }
163
+ static async exportPackage(projectInfo, assetPaths, outputPath) {
164
+ try {
165
+ console.debug(`Exporting package from project`);
166
+ const args = ["-projectPath", projectInfo.projectPath, "-exportPackage", ...assetPaths, outputPath, "-quit"];
167
+ const editorInfo = { version: projectInfo.editorVersion };
168
+ const { stdout, stderr } = await this.execUnityEditorCommand(editorInfo, args, {
169
+ reject: false,
170
+ });
171
+ const exportSuccessful = !stdout.includes("Failed to export package") && !stderr.includes("Failed to export package");
172
+ if (exportSuccessful) {
173
+ console.info(`Successfully exported package to ${outputPath}`);
174
+ return true;
175
+ }
176
+ else {
177
+ console.error(`Failed to export package: ${stderr || stdout}`);
178
+ return false;
179
+ }
180
+ }
181
+ catch (error) {
182
+ console.error("Error exporting package:", error);
183
+ return false;
184
+ }
185
+ }
186
+ static async importPackage(projectInfo, packagePath) {
187
+ try {
188
+ console.debug(`Importing package ${packagePath} to project`);
189
+ const args = ["-projectPath", projectInfo.projectPath, "-importPackage", packagePath, "-quit"];
190
+ const editorInfo = { version: projectInfo.editorVersion };
191
+ const { stdout, stderr } = await this.execUnityEditorCommand(editorInfo, args, {
192
+ reject: false,
193
+ });
194
+ const importSuccessful = !stdout.includes("Failed to import package") && !stderr.includes("Failed to import package");
195
+ if (importSuccessful) {
196
+ console.info(`Successfully imported package ${packagePath}`);
197
+ return true;
198
+ }
199
+ else {
200
+ console.error(`Failed to import package: ${stderr || stdout}`);
201
+ return false;
202
+ }
203
+ }
204
+ catch (error) {
205
+ console.error("Error importing package:", error);
206
+ return false;
207
+ }
208
+ }
209
+ static async createProject(projectInfo, waitForExit = true) {
210
+ try {
211
+ console.debug(`Creating new project at ${projectInfo.projectPath}`);
212
+ const parentDir = path.dirname(projectInfo.projectPath);
213
+ await fs.ensureDir(parentDir);
214
+ const args = ["-createProject", projectInfo.projectPath];
215
+ if (waitForExit) {
216
+ args.push("-quit");
217
+ }
218
+ const editorInfo = { version: projectInfo.editorVersion };
219
+ const { stdout, stderr } = await this.execUnityEditorCommand(editorInfo, args, {
220
+ reject: false,
221
+ });
222
+ const creationSuccessful = !stdout.includes("Failed to create project") && !stderr.includes("Failed to create project");
223
+ if (creationSuccessful) {
224
+ console.info(`Successfully created project at ${projectInfo.projectPath}`);
225
+ return true;
226
+ }
227
+ else {
228
+ console.error(`Failed to create project: ${stderr || stdout}`);
229
+ return false;
230
+ }
231
+ }
232
+ catch (error) {
233
+ console.error("Error creating project:", error);
234
+ return false;
235
+ }
236
+ }
237
+ static async openProject(projectInfo, batchmode = false, waitForExit = true) {
238
+ try {
239
+ console.debug(`Opening project at ${projectInfo.projectPath}`);
240
+ const args = ["-projectPath", projectInfo.projectPath];
241
+ if (waitForExit) {
242
+ args.push("-quit");
243
+ }
244
+ if (batchmode) {
245
+ args.push("-batchmode");
246
+ }
247
+ const editorInfo = { version: projectInfo.editorVersion };
248
+ const options = { reject: false };
249
+ const { stdout, stderr } = await this.execUnityEditorCommand(editorInfo, args, options);
250
+ const openingSuccessful = !stdout.includes("Failed to open project") && !stderr.includes("Failed to open project");
251
+ if (openingSuccessful) {
252
+ console.info(`Successfully opened project`);
253
+ return true;
254
+ }
255
+ else {
256
+ console.error(`Failed to open project: ${stderr || stdout}`);
257
+ return false;
258
+ }
259
+ }
260
+ catch (error) {
261
+ console.error("Error opening project:", error);
262
+ return false;
263
+ }
264
+ }
265
+ }
266
+ function redactSensitiveArgs(argv, sensitiveKeys = ["password", "token", "secret"]) {
267
+ const redacted = [...argv];
268
+ for (let i = 0; i < redacted.length; i++) {
269
+ const arg = redacted[i];
270
+ if (arg.startsWith("--") || arg.startsWith("-")) {
271
+ const key = arg.replace(/^--?/, "");
272
+ if (sensitiveKeys.includes(key.toLowerCase())) {
273
+ if (i + 1 < redacted.length && !redacted[i + 1].startsWith("-")) {
274
+ redacted[i + 1] = "[REDACTED]";
275
+ }
276
+ }
277
+ }
278
+ else {
279
+ const match = arg.match(/^--?([^=]+)=(.+)$/);
280
+ if (match) {
281
+ const key = match[1];
282
+ if (sensitiveKeys.includes(key.toLowerCase())) {
283
+ redacted[i] = `--${key}=[REDACTED]`;
284
+ }
285
+ }
286
+ }
287
+ }
288
+ return redacted;
289
+ }
290
+ export default UnityEditor;
@@ -1,21 +1,17 @@
1
- import { EditorArchitecture, ModuleId, UnityInstallations, UnityLanguages, UnityModules } from "./types/unity.js";
1
+ import { EditorArchitecture, ModuleId, UnityInstallations, UnityEditorLanguages, UnityModules } from "./types/unity.js";
2
2
  import { CommandOptions, CommandResult } from "./utils/commandExecutor.js";
3
3
  declare class UnityHub {
4
4
  private static CONFIG_PATHS;
5
5
  static readonly Modules: typeof UnityModules;
6
- static readonly Languages: typeof UnityLanguages;
7
- private static platform;
8
- private static hubPath;
9
- private static getUnityHubPath;
10
- private static getProjectsPath;
11
- private static getProjectDirPath;
6
+ static readonly Languages: typeof UnityEditorLanguages;
7
+ static getUnityHubPath(): string;
12
8
  static isUnityHubAvailable(): Promise<boolean>;
13
9
  static execUnityHubCommand(args: string[], options?: CommandOptions): Promise<CommandResult>;
14
10
  static getInstallPath(): Promise<string>;
15
11
  static setInstallPath(path: string): Promise<void>;
16
12
  static getUnityInstallations(filter?: string): Promise<UnityInstallations>;
17
13
  static addModule(editorVersion: string, modules: ModuleId[], childModules?: boolean): Promise<void>;
18
- static addEditor(version: string, changeset?: string, modules?: ModuleId[], architecture?: EditorArchitecture): Promise<void>;
14
+ static addEditor(version: string, modules?: ModuleId[], architecture?: EditorArchitecture): Promise<void>;
19
15
  static getProjects(): Promise<{
20
16
  name: string;
21
17
  path: string;
@@ -1,8 +1,9 @@
1
1
  import fs from "fs-extra";
2
2
  import os from "os";
3
3
  import path from "path";
4
- import { EditorArchitecture, UnityLanguages, UnityModules, } from "./types/unity.js";
4
+ import { EditorArchitecture, UnityEditorLanguages, UnityModules, } from "./types/unity.js";
5
5
  import { executeCommand } from "./utils/commandExecutor.js";
6
+ import { getUnityChangeset } from "unity-changeset";
6
7
  class UnityHub {
7
8
  static CONFIG_PATHS = {
8
9
  win32: {
@@ -22,7 +23,7 @@ class UnityHub {
22
23
  },
23
24
  };
24
25
  static Modules = UnityModules;
25
- static Languages = UnityLanguages;
26
+ static Languages = UnityEditorLanguages;
26
27
  static platform = os.platform();
27
28
  static hubPath = this.getUnityHubPath();
28
29
  static getUnityHubPath() {
@@ -145,12 +146,12 @@ class UnityHub {
145
146
  throw error;
146
147
  }
147
148
  }
148
- static async addEditor(version, changeset, modules = [], architecture = EditorArchitecture.x86_64) {
149
+ static async addEditor(version, modules = [], architecture = EditorArchitecture.x86_64) {
149
150
  try {
150
- console.debug(`Installing Unity ${version} ${(changeset ?? "") ? `(changeset: ${changeset})` : ""}`);
151
+ const data = await getUnityChangeset(version);
151
152
  const args = ["install", "-v", version];
152
- if (changeset) {
153
- args.push("--changeset", changeset);
153
+ if (data) {
154
+ args.push("--changeset", data.changeset);
154
155
  }
155
156
  if (modules.length > 0) {
156
157
  args.push("--module");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notask/unity-cli-tools",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "main": "dist/cjs/index.js",
5
5
  "module": "dist/esm/index.js",
6
6
  "types": "dist/esm/index.d.ts",
@@ -21,7 +21,7 @@
21
21
  "url": "https://github.com/NoTaskStudios/unity-cli-tools.git"
22
22
  },
23
23
  "scripts": {
24
- "clean": "rimraf dist dist-cjs",
24
+ "clean": "rimraf dist",
25
25
  "build": "npm run clean && npm run build:esm && npm run build:cjs",
26
26
  "build:esm": "tsc --project tsconfig.json",
27
27
  "build:cjs": "tsc --project tsconfig.cjs.json && node scripts/write-cjs-package.cjs",
@@ -44,7 +44,8 @@
44
44
  "description": "A tools for Unity command line development.",
45
45
  "dependencies": {
46
46
  "execa": "^9.5.2",
47
- "fs-extra": "^11.3.0"
47
+ "fs-extra": "^11.3.0",
48
+ "unity-changeset": "2.5.0"
48
49
  },
49
50
  "devDependencies": {
50
51
  "@eslint/js": "9.24.0",