launch-unity 0.6.1 → 0.6.2

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.ja.md CHANGED
@@ -18,7 +18,7 @@ npx launch-unity
18
18
  ## 使用例
19
19
  ```bash
20
20
  # NPX(推奨 / インストール不要)
21
- npx launch-unity # カレントディレクトリを開く(ビルドターゲット未指定時はプロジェクトの現在のビルドターゲットを使用)
21
+ npx launch-unity # カレントディレクトリから3階層下までUnityプロジェクトを探索して開く
22
22
  npx launch-unity /path/to/Proj # プロジェクトを指定
23
23
  npx launch-unity /path Android # ビルドターゲットを指定
24
24
  npx -y launch-unity # npx の「Ok to proceed?」確認をスキップ
@@ -31,11 +31,6 @@ npx launch-unity /path Android -- -executeMethod My.Build.Entry
31
31
  launch-unity
32
32
  launch-unity /path/to/MyUnityProject Android
33
33
  launch-unity . -- -buildTarget iOS -projectPath . # 上書きも可能
34
-
35
- # プロジェクトを開いている Unity を終了
36
- quit-unity # カレントディレクトリのプロジェクトの Unity を終了
37
- quit-unity /path/to/Proj # 指定プロジェクトの Unity を終了
38
- quit-unity . --timeout 20000 --force
39
34
  ```
40
35
 
41
36
  指定した Unity プロジェクトの `ProjectSettings/ProjectVersion.txt` から必要な Unity Editor のバージョンを読み取り、
@@ -61,17 +56,6 @@ Unity Hub でインストール済みの該当バージョンを起動する mac
61
56
  - macOS / Windows: Unity Hub のデフォルトインストールパスを前提にサポート。
62
57
  - Linux: 未対応です。対応 PR を歓迎します。
63
58
 
64
- ## quit-unity 使い方(詳細)
65
- ```bash
66
- # 基本構文
67
- quit-unity [PROJECT_PATH] [--timeout <ms>] [--force]
68
-
69
- # フラグ
70
- # -t, --timeout <ms> 正常終了を待つ時間(既定: 15000ms)
71
- # -f, --force タイムアウト後に強制終了
72
- # -h, --help ヘルプ
73
- ```
74
-
75
59
  ## セキュリティ
76
60
 
77
61
  このプロジェクトはサプライチェーン攻撃対策を実施しています:
package/README.md CHANGED
@@ -18,7 +18,7 @@ npx launch-unity
18
18
  ## Usage Examples
19
19
  ```bash
20
20
  # NPX (recommended, zero install)
21
- npx launch-unity # Open the current directory (if PLATFORM is omitted, uses the project's current build target)
21
+ npx launch-unity # Search up to 3 levels deep for a Unity project and open it
22
22
  npx launch-unity /path/to/Proj # Open a specific project
23
23
  npx launch-unity /path Android # Specify build target
24
24
  npx -y launch-unity # Skip npx "Ok to proceed?" prompt
@@ -31,11 +31,6 @@ npx launch-unity /path Android -- -executeMethod My.Build.Entry
31
31
  launch-unity
32
32
  launch-unity /path/to/MyUnityProject Android
33
33
  launch-unity . -- -buildTarget iOS -projectPath . # You can override
34
-
35
- # Quit the Unity instance holding a project open
36
- quit-unity # Quit Unity for current directory project
37
- quit-unity /path/to/Proj # Quit Unity for a specific project
38
- quit-unity . --timeout 20000 --force
39
34
  ```
40
35
 
41
36
  A TypeScript CLI for macOS and Windows that reads the required Unity Editor version from
@@ -63,14 +58,6 @@ launch-unity [PROJECT_PATH] [PLATFORM]
63
58
 
64
59
  # Flags
65
60
  # -h, --help Show help
66
-
67
- # Quit syntax
68
- quit-unity [PROJECT_PATH] [--timeout <ms>] [--force]
69
-
70
- # Flags (quit-unity)
71
- # -t, --timeout <ms> Time to wait for graceful quit (default: 15000)
72
- # -f, --force Force kill if not exited within timeout
73
- # -h, --help Show help
74
61
  ```
75
62
 
76
63
 
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "launch-unity",
3
- "version": "0.6.1",
3
+ "version": "0.6.2",
4
4
  "description": "Open a Unity project with the matching Editor version (macOS/Windows)",
5
5
  "type": "module",
6
6
  "main": "dist/launch.js",
7
7
  "bin": {
8
- "launch-unity": "dist/launch.js",
9
- "quit-unity": "dist/quit.js"
8
+ "launch-unity": "dist/launch.js"
10
9
  },
11
10
  "scripts": {
12
11
  "build": "tsc -p tsconfig.json",
package/dist/quit.js DELETED
@@ -1,186 +0,0 @@
1
- #!/usr/bin/env node
2
- /*
3
- quit-unity: Quit the Unity Editor instance that has the specified project open.
4
- Platforms: macOS, Windows
5
- */
6
- import { existsSync, readFileSync } from "node:fs";
7
- import { rm } from "node:fs/promises";
8
- import { join, resolve } from "node:path";
9
- const TEMP_DIRECTORY_NAME = "Temp";
10
- function parseArgs(argv) {
11
- const defaultProjectPath = process.cwd();
12
- const defaultTimeoutMs = 15000;
13
- const defaultForce = false;
14
- const args = argv.slice(2);
15
- let projectPath = defaultProjectPath;
16
- let timeoutMs = defaultTimeoutMs;
17
- let force = defaultForce;
18
- for (let i = 0; i < args.length; i++) {
19
- const arg = args[i] ?? "";
20
- if (arg === "--help" || arg === "-h") {
21
- printHelp();
22
- process.exit(0);
23
- }
24
- if (arg === "--force" || arg === "-f") {
25
- force = true;
26
- continue;
27
- }
28
- if (arg === "--timeout" || arg === "-t") {
29
- const value = args[i + 1];
30
- if (!value || value.startsWith("-")) {
31
- console.error("Error: --timeout requires a millisecond value");
32
- process.exit(1);
33
- }
34
- const parsedValue = Number(value);
35
- const parsed = parsedValue;
36
- if (!Number.isFinite(parsed) || parsed < 0) {
37
- console.error("Error: --timeout must be a non-negative number (milliseconds)");
38
- process.exit(1);
39
- }
40
- timeoutMs = parsed;
41
- i++;
42
- continue;
43
- }
44
- if (arg.startsWith("-")) {
45
- // Unknown flags are ignored to keep CLI permissive
46
- continue;
47
- }
48
- // First positional = project path
49
- projectPath = resolve(arg);
50
- }
51
- return { projectPath, timeoutMs, force };
52
- }
53
- function printHelp() {
54
- const help = `
55
- Usage: quit-unity [PROJECT_PATH] [--timeout <ms>] [--force]
56
-
57
- Quit the Unity Editor instance that has PROJECT_PATH open.
58
-
59
- Arguments:
60
- PROJECT_PATH Optional. Defaults to current directory
61
-
62
- Flags:
63
- -t, --timeout <ms> Time to wait for graceful quit (default: 15000)
64
- -f, --force Force kill if not exited within timeout
65
- -h, --help Show this help message
66
- `;
67
- process.stdout.write(help);
68
- }
69
- function ensureProjectPath(projectPath) {
70
- if (!existsSync(projectPath)) {
71
- console.error(`Error: Project directory not found: ${projectPath}`);
72
- process.exit(1);
73
- }
74
- }
75
- function readPidFromEditorInstance(projectPath) {
76
- const editorInstancePath = join(projectPath, "Library", "EditorInstance.json");
77
- if (!existsSync(editorInstancePath))
78
- return null;
79
- try {
80
- const content = readFileSync(editorInstancePath, "utf8");
81
- const data = JSON.parse(content);
82
- const candidateKeys = [
83
- "process_id",
84
- "processId",
85
- "processID",
86
- "pid",
87
- "PID",
88
- ];
89
- for (const key of candidateKeys) {
90
- const value = data[key];
91
- if (typeof value === "number" && Number.isFinite(value))
92
- return value;
93
- if (typeof value === "string" && /^\d+$/.test(value))
94
- return Number(value);
95
- }
96
- }
97
- catch {
98
- // fallthrough
99
- }
100
- return null;
101
- }
102
- function isProcessAlive(pid) {
103
- try {
104
- // signal 0: does not actually send a signal, just tests for existence/permissions
105
- process.kill(pid, 0);
106
- return true;
107
- }
108
- catch {
109
- return false;
110
- }
111
- }
112
- async function waitForExit(pid, timeoutMs) {
113
- const start = Date.now();
114
- const stepIntervalMs = 200;
115
- const stepMs = stepIntervalMs;
116
- while (Date.now() - start < timeoutMs) {
117
- if (!isProcessAlive(pid))
118
- return true;
119
- await new Promise((r) => setTimeout(r, stepMs));
120
- }
121
- return !isProcessAlive(pid);
122
- }
123
- async function quitByPid(pid, force, timeoutMs) {
124
- // Try graceful first
125
- try {
126
- process.kill(pid, "SIGTERM");
127
- }
128
- catch {
129
- // If process already exited, consider it success
130
- if (!isProcessAlive(pid))
131
- return true;
132
- // If we cannot send the signal and the process is alive, escalate when force is true
133
- if (!force)
134
- return false;
135
- }
136
- const graceful = await waitForExit(pid, timeoutMs);
137
- if (graceful)
138
- return true;
139
- if (!force)
140
- return false;
141
- // Force kill
142
- try {
143
- process.kill(pid, "SIGKILL");
144
- }
145
- catch {
146
- // ignore
147
- }
148
- // Give a short moment after force
149
- return await waitForExit(pid, 2000);
150
- }
151
- async function removeTempDirectory(projectPath) {
152
- const tempDirectoryPath = join(projectPath, TEMP_DIRECTORY_NAME);
153
- if (!existsSync(tempDirectoryPath))
154
- return;
155
- try {
156
- await rm(tempDirectoryPath, { recursive: true, force: true });
157
- console.log(`Deleted Temp directory: ${tempDirectoryPath}`);
158
- }
159
- catch (error) {
160
- const message = error instanceof Error ? error.message : String(error);
161
- console.warn(`Failed to delete Temp directory: ${message}`);
162
- }
163
- }
164
- async function main() {
165
- const options = parseArgs(process.argv);
166
- ensureProjectPath(options.projectPath);
167
- const pid = readPidFromEditorInstance(options.projectPath);
168
- if (pid === null) {
169
- console.error("Error: Could not find Unity PID. Is this project currently open in Unity? (Missing Library/EditorInstance.json)");
170
- process.exit(1);
171
- return;
172
- }
173
- console.log(`Attempting to quit Unity (pid: ${pid}) for project: ${options.projectPath}`);
174
- const ok = await quitByPid(pid, options.force, options.timeoutMs);
175
- if (!ok) {
176
- console.error(`Failed to quit Unity (pid: ${pid}) within ${options.timeoutMs}ms.${options.force ? "" : " Try --force."}`);
177
- process.exit(1);
178
- return;
179
- }
180
- console.log("Unity has exited.");
181
- await removeTempDirectory(options.projectPath);
182
- }
183
- main().catch((error) => {
184
- console.error(error);
185
- process.exit(1);
186
- });