unity-mcp-cli 0.59.0 → 0.61.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/README.md +13 -17
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +33 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/open.js +19 -0
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/setup-skills.js +85 -31
- package/dist/commands/setup-skills.js.map +1 -1
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.js +77 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/auth.d.ts +28 -0
- package/dist/utils/auth.js +111 -0
- package/dist/utils/auth.js.map +1 -0
- package/dist/utils/browser.d.ts +5 -0
- package/dist/utils/browser.js +32 -0
- package/dist/utils/browser.js.map +1 -0
- package/dist/utils/cloud-login.d.ts +7 -0
- package/dist/utils/cloud-login.js +56 -0
- package/dist/utils/cloud-login.js.map +1 -0
- package/dist/utils/config.d.ts +1 -0
- package/dist/utils/config.js +1 -0
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/manifest.js +3 -12
- package/dist/utils/manifest.js.map +1 -1
- package/dist/utils/semver.d.ts +4 -0
- package/dist/utils/semver.js +25 -0
- package/dist/utils/semver.js.map +1 -0
- package/dist/utils/update-check.d.ts +19 -0
- package/dist/utils/update-check.js +92 -0
- package/dist/utils/update-check.js.map +1 -0
- package/docs/README.es.md +22 -26
- package/docs/README.ja.md +22 -26
- package/docs/README.zh-CN.md +22 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -66,14 +66,14 @@ unity-mcp-cli create-project ./MyUnityProject # │ codex
|
|
|
66
66
|
# 2. Install "AI Game Developer" in Unity project # │ gemini │
|
|
67
67
|
unity-mcp-cli install-plugin ./MyUnityProject # │ github-copilot-cli │
|
|
68
68
|
# │ kilo-code │
|
|
69
|
-
# 3.
|
|
70
|
-
unity-mcp-cli
|
|
69
|
+
# 3. Login to cloud server # │ open-code │
|
|
70
|
+
unity-mcp-cli login ./MyUnityProject # │ rider-junie │
|
|
71
71
|
# │ unity-ai │
|
|
72
|
-
#
|
|
73
|
-
unity-mcp-cli
|
|
72
|
+
# 4. Open Unity project (auto-connects and generates skills) │ vs-copilot │
|
|
73
|
+
unity-mcp-cli open ./MyUnityProject # │ vscode-copilot │
|
|
74
74
|
# └────────────────────┘
|
|
75
|
-
#
|
|
76
|
-
unity-mcp-cli
|
|
75
|
+
# 5. Wait for Unity Editor to be ready
|
|
76
|
+
unity-mcp-cli wait-for-ready ./MyUnityProject
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
Or run any command instantly with `npx` — no global installation required:
|
|
@@ -89,6 +89,7 @@ npx unity-mcp-cli install-plugin /path/to/unity/project
|
|
|
89
89
|
# Contents
|
|
90
90
|
|
|
91
91
|
- [Quick Start](#quick-start)
|
|
92
|
+
- [Contents](#contents)
|
|
92
93
|
- [Commands](#commands)
|
|
93
94
|
- [`configure`](#configure)
|
|
94
95
|
- [`create-project`](#create-project)
|
|
@@ -506,21 +507,16 @@ unity-mcp-cli install-plugin ./MyAIGame
|
|
|
506
507
|
# 3. Enable all MCP tools
|
|
507
508
|
unity-mcp-cli configure ./MyAIGame --enable-all-tools
|
|
508
509
|
|
|
509
|
-
# 4.
|
|
510
|
-
unity-mcp-cli
|
|
510
|
+
# 4. Login to cloud server (authenticates and saves token)
|
|
511
|
+
unity-mcp-cli login ./MyAIGame
|
|
511
512
|
|
|
512
|
-
# 5.
|
|
513
|
-
unity-mcp-cli
|
|
513
|
+
# 5. Open the project (auto-connects and generates skills for claude-code)
|
|
514
|
+
unity-mcp-cli open ./MyAIGame
|
|
514
515
|
|
|
515
|
-
# 6.
|
|
516
|
-
unity-mcp-cli open ./MyAIGame \
|
|
517
|
-
--url http://localhost:8080 \
|
|
518
|
-
--keep-connected
|
|
519
|
-
|
|
520
|
-
# 7. Wait for Unity Editor and MCP server to be ready
|
|
516
|
+
# 6. Wait for Unity Editor and MCP server to be ready
|
|
521
517
|
unity-mcp-cli wait-for-ready ./MyAIGame
|
|
522
518
|
|
|
523
|
-
#
|
|
519
|
+
# 7. Run tests to verify everything works
|
|
524
520
|
unity-mcp-cli run-tool tests-run ./MyAIGame --input '{"testMode":"EditMode"}'
|
|
525
521
|
```
|
|
526
522
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Copyright (c) 2024 Ivan Murzak. All rights reserved.
|
|
2
|
+
// Licensed under the Apache License, Version 2.0.
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import * as ui from '../utils/ui.js';
|
|
5
|
+
import { verbose } from '../utils/ui.js';
|
|
6
|
+
import { resolveProjectPath } from '../utils/connection.js';
|
|
7
|
+
import { getOrCreateConfig, CLOUD_SERVER_BASE_URL } from '../utils/config.js';
|
|
8
|
+
import { runCloudLogin } from '../utils/cloud-login.js';
|
|
9
|
+
export const loginCommand = new Command('login')
|
|
10
|
+
.description('Authenticate with the Unity-MCP cloud server')
|
|
11
|
+
.argument('[path]', 'Unity project path (defaults to cwd)')
|
|
12
|
+
.option('--force', 'Re-authenticate even if already logged in')
|
|
13
|
+
.action(async (positionalPath, options) => {
|
|
14
|
+
const projectPath = resolveProjectPath(positionalPath, options);
|
|
15
|
+
verbose(`Project path: ${projectPath}`);
|
|
16
|
+
const config = getOrCreateConfig(projectPath);
|
|
17
|
+
if (config.cloudToken && !options.force) {
|
|
18
|
+
ui.success('Already authenticated with cloud server.');
|
|
19
|
+
ui.info('Use --force to re-authenticate.');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
ui.heading('Cloud Authentication');
|
|
23
|
+
ui.label('Server', CLOUD_SERVER_BASE_URL);
|
|
24
|
+
ui.divider();
|
|
25
|
+
const token = await runCloudLogin(projectPath);
|
|
26
|
+
if (token) {
|
|
27
|
+
ui.success('Authentication complete. Cloud token saved to project config.');
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,kDAAkD;AAElD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAOxD,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,8CAA8C,CAAC;KAC3D,QAAQ,CAAC,QAAQ,EAAE,sCAAsC,CAAC;KAC1D,MAAM,CAAC,SAAS,EAAE,2CAA2C,CAAC;KAC9D,MAAM,CACL,KAAK,EACH,cAAkC,EAClC,OAAqB,EACrB,EAAE;IACF,MAAM,WAAW,GAAG,kBAAkB,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IAChE,OAAO,CAAC,iBAAiB,WAAW,EAAE,CAAC,CAAC;IAExC,MAAM,MAAM,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAE9C,IAAI,MAAM,CAAC,UAAU,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACxC,EAAE,CAAC,OAAO,CAAC,0CAA0C,CAAC,CAAC;QACvD,EAAE,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QAC3C,OAAO;IACT,CAAC;IAED,EAAE,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACnC,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,qBAAqB,CAAC,CAAC;IAC1C,EAAE,CAAC,OAAO,EAAE,CAAC;IAEb,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,WAAW,CAAC,CAAC;IAC/C,IAAI,KAAK,EAAE,CAAC;QACV,EAAE,CAAC,OAAO,CAAC,+DAA+D,CAAC,CAAC;IAC9E,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CACF,CAAC"}
|
package/dist/commands/open.js
CHANGED
|
@@ -5,6 +5,7 @@ import { findEditorPath, getProjectEditorVersion, launchEditor, printEditorNotFo
|
|
|
5
5
|
import { findUnityProcess } from '../utils/unity-process.js';
|
|
6
6
|
import * as ui from '../utils/ui.js';
|
|
7
7
|
import { verbose } from '../utils/ui.js';
|
|
8
|
+
import { readConfig, isCloudMode, writeConfig } from '../utils/config.js';
|
|
8
9
|
export const openCommand = new Command('open')
|
|
9
10
|
.description('Open a Unity project in Unity Editor, optionally passing MCP connection env vars when connection options (--url, --token, etc.) are provided. Use --no-connect to suppress all MCP env vars.')
|
|
10
11
|
.argument('[path]', 'Path to the Unity project')
|
|
@@ -56,6 +57,24 @@ export const openCommand = new Command('open')
|
|
|
56
57
|
}
|
|
57
58
|
spinner.success('Unity Editor located');
|
|
58
59
|
verbose(`Editor path: ${editorPath}`);
|
|
60
|
+
// Auto-detect Cloud mode: if project has cloudToken, ensure keep-connected
|
|
61
|
+
// so the Unity plugin connects to the cloud server on startup.
|
|
62
|
+
// Also enable auto-generate skills for claude-code by default.
|
|
63
|
+
{
|
|
64
|
+
const config = readConfig(projectPath);
|
|
65
|
+
if (config && isCloudMode(config) && config.cloudToken) {
|
|
66
|
+
if (!options.keepConnected) {
|
|
67
|
+
options.keepConnected = true;
|
|
68
|
+
verbose('Cloud mode with token detected — auto-enabling keep-connected');
|
|
69
|
+
}
|
|
70
|
+
const skillAutoGenerate = { ...(config.skillAutoGenerate ?? {}) };
|
|
71
|
+
if (!skillAutoGenerate['claude-code']) {
|
|
72
|
+
skillAutoGenerate['claude-code'] = true;
|
|
73
|
+
writeConfig(projectPath, { ...config, skillAutoGenerate });
|
|
74
|
+
verbose('Auto-enabled skill generation for claude-code');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
59
78
|
// Build environment variables for MCP connection (unless --no-connect)
|
|
60
79
|
const useConnect = options.connect !== false;
|
|
61
80
|
let env;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open.js","sourceRoot":"","sources":["../../src/commands/open.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAC1H,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"open.js","sourceRoot":"","sources":["../../src/commands/open.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,9 +4,35 @@ import * as ui from '../utils/ui.js';
|
|
|
4
4
|
import { verbose } from '../utils/ui.js';
|
|
5
5
|
import { resolveAndValidateProjectPath, resolveConnection } from '../utils/connection.js';
|
|
6
6
|
import { getAgentById, getAgentIds, listAgentTable } from '../utils/agents.js';
|
|
7
|
+
import { readConfig, isCloudMode } from '../utils/config.js';
|
|
8
|
+
import { runCloudLogin } from '../utils/cloud-login.js';
|
|
7
9
|
function listAgentsWithSkills() {
|
|
8
10
|
listAgentTable('AI Agents \u2014 Skills Support', 'Skills Path', (a) => a.skillsPath ?? '\u2014');
|
|
9
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* POST to the skill-generate endpoint and return the response.
|
|
14
|
+
*/
|
|
15
|
+
async function callGenerateSkills(endpoint, token, body, timeoutMs) {
|
|
16
|
+
const headers = {
|
|
17
|
+
'Content-Type': 'application/json',
|
|
18
|
+
};
|
|
19
|
+
if (token) {
|
|
20
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
21
|
+
}
|
|
22
|
+
const controller = new AbortController();
|
|
23
|
+
const fetchTimeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
24
|
+
try {
|
|
25
|
+
return await fetch(endpoint, {
|
|
26
|
+
method: 'POST',
|
|
27
|
+
headers,
|
|
28
|
+
body,
|
|
29
|
+
signal: controller.signal,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
clearTimeout(fetchTimeout);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
10
36
|
export const setupSkillsCommand = new Command('setup-skills')
|
|
11
37
|
.description('Generate skill files for an AI agent')
|
|
12
38
|
.argument('[agent-id]', 'Agent to generate skills for (use --list to see all)')
|
|
@@ -42,17 +68,11 @@ export const setupSkillsCommand = new Command('setup-skills')
|
|
|
42
68
|
const skillsPath = path.join(projectPath, agent.skillsPath);
|
|
43
69
|
verbose(`Skills path: ${skillsPath}`);
|
|
44
70
|
// Resolve server connection
|
|
45
|
-
|
|
71
|
+
let { url: serverUrl, token } = resolveConnection(projectPath, options);
|
|
46
72
|
// Call the MCP server to generate skills
|
|
47
73
|
const endpoint = `${serverUrl}/api/system-tools/unity-skill-generate`;
|
|
48
74
|
verbose(`Endpoint: ${endpoint}`);
|
|
49
|
-
const
|
|
50
|
-
'Content-Type': 'application/json',
|
|
51
|
-
};
|
|
52
|
-
if (token) {
|
|
53
|
-
headers['Authorization'] = `Bearer ${token}`;
|
|
54
|
-
}
|
|
55
|
-
const body = JSON.stringify({ path: skillsPath });
|
|
75
|
+
const body = JSON.stringify({ path: agent.skillsPath });
|
|
56
76
|
ui.heading('Generate Skills');
|
|
57
77
|
ui.label('Agent', agent.name);
|
|
58
78
|
ui.label('Skills path', skillsPath);
|
|
@@ -64,15 +84,49 @@ export const setupSkillsCommand = new Command('setup-skills')
|
|
|
64
84
|
process.exit(1);
|
|
65
85
|
}
|
|
66
86
|
const spinner = ui.startSpinner(`Generating skills for ${agent.name}...`);
|
|
67
|
-
const controller = new AbortController();
|
|
68
|
-
const fetchTimeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
69
87
|
try {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
88
|
+
let response = await callGenerateSkills(endpoint, token, body, timeoutMs);
|
|
89
|
+
// Handle 401 in Cloud mode
|
|
90
|
+
if (response.status === 401) {
|
|
91
|
+
await response.text();
|
|
92
|
+
spinner.stop();
|
|
93
|
+
const config = readConfig(projectPath);
|
|
94
|
+
const cloud = config != null && isCloudMode(config);
|
|
95
|
+
const hadToken = !!token;
|
|
96
|
+
if (cloud && !options.token && !hadToken) {
|
|
97
|
+
ui.info('Cloud authentication required. Starting login...');
|
|
98
|
+
console.log();
|
|
99
|
+
const newToken = await runCloudLogin(projectPath);
|
|
100
|
+
if (!newToken) {
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
// Token saved. Unity Editor needs to connect with it.
|
|
104
|
+
ui.info('Unity Editor must connect to the cloud server with this token.');
|
|
105
|
+
ui.info('If Unity was already running, restart it to pick up the new token:');
|
|
106
|
+
console.log();
|
|
107
|
+
console.log(` unity-mcp-cli open ${positionalPath ?? '.'}`);
|
|
108
|
+
console.log(` unity-mcp-cli wait-for-ready ${positionalPath ?? '.'}`);
|
|
109
|
+
console.log(` unity-mcp-cli setup-skills ${agentId} ${positionalPath ?? '.'}`);
|
|
110
|
+
console.log();
|
|
111
|
+
process.exit(0);
|
|
112
|
+
}
|
|
113
|
+
else if (cloud && hadToken) {
|
|
114
|
+
// Token exists but was rejected — Unity Editor isn't connected
|
|
115
|
+
ui.error('Cloud server rejected the token. Unity Editor may not be connected yet.');
|
|
116
|
+
ui.info('Make sure Unity Editor is running and connected to the cloud server.');
|
|
117
|
+
ui.info('Try the following:');
|
|
118
|
+
console.log();
|
|
119
|
+
console.log(` unity-mcp-cli open ${positionalPath ?? '.'}`);
|
|
120
|
+
console.log(` unity-mcp-cli wait-for-ready ${positionalPath ?? '.'}`);
|
|
121
|
+
console.log(` unity-mcp-cli setup-skills ${agentId} ${positionalPath ?? '.'}`);
|
|
122
|
+
console.log();
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
ui.error('HTTP 401: Unauthorized. Check your --token value.');
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
76
130
|
if (!response.ok) {
|
|
77
131
|
spinner.stop();
|
|
78
132
|
const text = await response.text();
|
|
@@ -92,22 +146,22 @@ export const setupSkillsCommand = new Command('setup-skills')
|
|
|
92
146
|
}
|
|
93
147
|
catch (err) {
|
|
94
148
|
spinner.stop();
|
|
95
|
-
|
|
96
|
-
const isTimeout = err instanceof Error && err.name === 'AbortError';
|
|
97
|
-
const isConnectionRefused = message.includes('ECONNREFUSED') || message.includes('fetch failed');
|
|
98
|
-
if (isTimeout) {
|
|
99
|
-
ui.error(`Request timed out after ${timeoutMs / 1000} seconds.`);
|
|
100
|
-
}
|
|
101
|
-
else if (isConnectionRefused) {
|
|
102
|
-
ui.error('MCP Server is not running. Please start Unity Editor with the Unity-MCP plugin installed, then retry.');
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
ui.error(`Failed to generate skills: ${message}`);
|
|
106
|
-
}
|
|
149
|
+
handleFetchError(err, timeoutMs);
|
|
107
150
|
process.exit(1);
|
|
108
151
|
}
|
|
109
|
-
finally {
|
|
110
|
-
clearTimeout(fetchTimeout);
|
|
111
|
-
}
|
|
112
152
|
});
|
|
153
|
+
function handleFetchError(err, timeoutMs) {
|
|
154
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
155
|
+
const isTimeout = err instanceof Error && err.name === 'AbortError';
|
|
156
|
+
const isConnectionRefused = message.includes('ECONNREFUSED') || message.includes('fetch failed');
|
|
157
|
+
if (isTimeout) {
|
|
158
|
+
ui.error(`Request timed out after ${timeoutMs / 1000} seconds.`);
|
|
159
|
+
}
|
|
160
|
+
else if (isConnectionRefused) {
|
|
161
|
+
ui.error('MCP Server is not running. Please start Unity Editor with the Unity-MCP plugin installed, then retry.');
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
ui.error(`Failed to generate skills: ${message}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
113
167
|
//# sourceMappingURL=setup-skills.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-skills.js","sourceRoot":"","sources":["../../src/commands/setup-skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,6BAA6B,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"setup-skills.js","sourceRoot":"","sources":["../../src/commands/setup-skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,6BAA6B,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC1F,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AASxD,SAAS,oBAAoB;IAC3B,cAAc,CAAC,iCAAiC,EAAE,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,QAAQ,CAAC,CAAC;AACpG,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,kBAAkB,CAC/B,QAAgB,EAChB,KAAyB,EACzB,IAAY,EACZ,SAAiB;IAEjB,MAAM,OAAO,GAA2B;QACtC,cAAc,EAAE,kBAAkB;KACnC,CAAC;IACF,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,KAAK,EAAE,CAAC;IAC/C,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,YAAY,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAErE,IAAI,CAAC;QACH,OAAO,MAAM,KAAK,CAAC,QAAQ,EAAE;YAC3B,MAAM,EAAE,MAAM;YACd,OAAO;YACP,IAAI;YACJ,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,YAAY,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,OAAO,CAAC,cAAc,CAAC;KAC1D,WAAW,CAAC,sCAAsC,CAAC;KACnD,QAAQ,CAAC,YAAY,EAAE,sDAAsD,CAAC;KAC9E,QAAQ,CAAC,QAAQ,EAAE,sCAAsC,CAAC;KAC1D,MAAM,CAAC,aAAa,EAAE,qBAAqB,CAAC;KAC5C,MAAM,CAAC,iBAAiB,EAAE,qBAAqB,CAAC;KAChD,MAAM,CAAC,QAAQ,EAAE,4CAA4C,CAAC;KAC9D,MAAM,CAAC,gBAAgB,EAAE,kDAAkD,EAAE,OAAO,CAAC;KACrF,MAAM,CACL,KAAK,EACH,OAA2B,EAC3B,cAAkC,EAClC,OAA2B,EAC3B,EAAE;IACF,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,oBAAoB,EAAE,CAAC;QACvB,OAAO;IACT,CAAC;IAED,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,EAAE,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QAChD,EAAE,CAAC,IAAI,CAAC,wBAAwB,WAAW,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,EAAE,CAAC,KAAK,CAAC,mBAAmB,OAAO,GAAG,CAAC,CAAC;QACxC,EAAE,CAAC,IAAI,CAAC,wBAAwB,WAAW,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;QACtB,EAAE,CAAC,KAAK,CAAC,UAAU,KAAK,CAAC,IAAI,4BAA4B,CAAC,CAAC;QAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,0DAA0D;IAC1D,MAAM,WAAW,GAAG,6BAA6B,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IAC3E,OAAO,CAAC,iBAAiB,WAAW,EAAE,CAAC,CAAC;IAExC,iCAAiC;IACjC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC5D,OAAO,CAAC,gBAAgB,UAAU,EAAE,CAAC,CAAC;IAEtC,4BAA4B;IAC5B,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,iBAAiB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAExE,yCAAyC;IACzC,MAAM,QAAQ,GAAG,GAAG,SAAS,wCAAwC,CAAC;IACtE,OAAO,CAAC,aAAa,QAAQ,EAAE,CAAC,CAAC;IAEjC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IAExD,EAAE,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC9B,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9B,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IACpC,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC9B,EAAE,CAAC,OAAO,EAAE,CAAC;IAEb,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,EAAE,EAAE,CAAC,CAAC;IAC3D,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QAClD,EAAE,CAAC,KAAK,CAAC,2BAA2B,OAAO,CAAC,OAAO,+CAA+C,CAAC,CAAC;QACpG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAC7B,yBAAyB,KAAK,CAAC,IAAI,KAAK,CACzC,CAAC;IAEF,IAAI,CAAC;QACH,IAAI,QAAQ,GAAG,MAAM,kBAAkB,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;QAE1E,2BAA2B;QAC3B,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,EAAE,CAAC;YAEf,MAAM,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;YACvC,MAAM,KAAK,GAAG,MAAM,IAAI,IAAI,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;YACpD,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC;YAEzB,IAAI,KAAK,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACzC,EAAE,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;gBAC5D,OAAO,CAAC,GAAG,EAAE,CAAC;gBACd,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,WAAW,CAAC,CAAC;gBAClD,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;gBAED,sDAAsD;gBACtD,EAAE,CAAC,IAAI,CAAC,gEAAgE,CAAC,CAAC;gBAC1E,EAAE,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAC;gBAC9E,OAAO,CAAC,GAAG,EAAE,CAAC;gBACd,OAAO,CAAC,GAAG,CAAC,wBAAwB,cAAc,IAAI,GAAG,EAAE,CAAC,CAAC;gBAC7D,OAAO,CAAC,GAAG,CAAC,kCAAkC,cAAc,IAAI,GAAG,EAAE,CAAC,CAAC;gBACvE,OAAO,CAAC,GAAG,CAAC,gCAAgC,OAAO,IAAI,cAAc,IAAI,GAAG,EAAE,CAAC,CAAC;gBAChF,OAAO,CAAC,GAAG,EAAE,CAAC;gBACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;iBAAM,IAAI,KAAK,IAAI,QAAQ,EAAE,CAAC;gBAC7B,+DAA+D;gBAC/D,EAAE,CAAC,KAAK,CAAC,yEAAyE,CAAC,CAAC;gBACpF,EAAE,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC;gBAChF,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;gBAC9B,OAAO,CAAC,GAAG,EAAE,CAAC;gBACd,OAAO,CAAC,GAAG,CAAC,wBAAwB,cAAc,IAAI,GAAG,EAAE,CAAC,CAAC;gBAC7D,OAAO,CAAC,GAAG,CAAC,kCAAkC,cAAc,IAAI,GAAG,EAAE,CAAC,CAAC;gBACvE,OAAO,CAAC,GAAG,CAAC,gCAAgC,OAAO,IAAI,cAAc,IAAI,GAAG,EAAE,CAAC,CAAC;gBAChF,OAAO,CAAC,GAAG,EAAE,CAAC;gBACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;iBAAM,CAAC;gBACN,EAAE,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC;gBAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YAEnC,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC5B,EAAE,CAAC,KAAK,CACN,+GAA+G,CAChH,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,EAAE,CAAC,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;gBAC5D,IAAI,IAAI,EAAE,CAAC;oBACT,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAChB,CAAC;YACH,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,CAAC,OAAO,CAAC,wBAAwB,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACtD,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,EAAE,CAAC;QACf,gBAAgB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CACF,CAAC;AAEJ,SAAS,gBAAgB,CAAC,GAAY,EAAE,SAAiB;IACvD,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,MAAM,SAAS,GAAG,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,CAAC;IACpE,MAAM,mBAAmB,GACvB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IAEvE,IAAI,SAAS,EAAE,CAAC;QACd,EAAE,CAAC,KAAK,CAAC,2BAA2B,SAAS,GAAG,IAAI,WAAW,CAAC,CAAC;IACnE,CAAC;SAAM,IAAI,mBAAmB,EAAE,CAAC;QAC/B,EAAE,CAAC,KAAK,CACN,uGAAuG,CACxG,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,EAAE,CAAC,KAAK,CAAC,8BAA8B,OAAO,EAAE,CAAC,CAAC;IACpD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
import { platform } from 'os';
|
|
4
|
+
import * as ui from '../utils/ui.js';
|
|
5
|
+
import { fetchLatestVersion, formatUpdateAvailable, isRunningViaNpx } from '../utils/update-check.js';
|
|
6
|
+
import { isNewerVersion } from '../utils/semver.js';
|
|
7
|
+
const PACKAGE_NAME = 'unity-mcp-cli';
|
|
8
|
+
function npmCommand() {
|
|
9
|
+
return platform() === 'win32' ? 'npm.cmd' : 'npm';
|
|
10
|
+
}
|
|
11
|
+
function runNpmInstall(packageSpec) {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
const child = spawn(npmCommand(), ['install', '-g', packageSpec], {
|
|
14
|
+
stdio: 'inherit',
|
|
15
|
+
});
|
|
16
|
+
child.on('error', reject);
|
|
17
|
+
child.on('close', (code) => resolve(code ?? 1));
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export function createUpdateCommand(currentVersion) {
|
|
21
|
+
return new Command('update')
|
|
22
|
+
.description('Update unity-mcp-cli to the latest version')
|
|
23
|
+
.option('--check', 'Only check for updates without installing')
|
|
24
|
+
.action(async (options) => {
|
|
25
|
+
if (isRunningViaNpx()) {
|
|
26
|
+
ui.info('Running via npx — it always fetches the latest published version.');
|
|
27
|
+
ui.info('No update action needed.');
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
const spinner = ui.startSpinner('Checking for updates...');
|
|
31
|
+
let latest;
|
|
32
|
+
try {
|
|
33
|
+
latest = await fetchLatestVersion();
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
spinner.error('Failed to check for updates');
|
|
37
|
+
ui.error(err.message || String(err));
|
|
38
|
+
process.exit(1);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (!isNewerVersion(currentVersion, latest)) {
|
|
42
|
+
spinner.success(`Already up to date (v${currentVersion})`);
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
spinner.success(formatUpdateAvailable(currentVersion, latest));
|
|
46
|
+
console.log();
|
|
47
|
+
// --check mode: exit 2 = outdated (distinct from exit 1 = error)
|
|
48
|
+
if (options.check) {
|
|
49
|
+
process.exit(2);
|
|
50
|
+
}
|
|
51
|
+
ui.info(`Installing ${PACKAGE_NAME}@${latest}...`);
|
|
52
|
+
console.log();
|
|
53
|
+
try {
|
|
54
|
+
const exitCode = await runNpmInstall(`${PACKAGE_NAME}@${latest}`);
|
|
55
|
+
if (exitCode !== 0) {
|
|
56
|
+
console.log();
|
|
57
|
+
ui.error('Update failed.');
|
|
58
|
+
if (platform() === 'win32') {
|
|
59
|
+
ui.info('Try running the terminal as Administrator.');
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
ui.info(`Try: sudo npm install -g ${PACKAGE_NAME}@latest`);
|
|
63
|
+
}
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
console.log();
|
|
69
|
+
ui.error(`Could not run npm: ${err.message}`);
|
|
70
|
+
ui.info('Make sure npm is installed and in your PATH.');
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
console.log();
|
|
74
|
+
ui.success(`Updated to v${latest}`);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { createProjectCommand } from './commands/create-project.js';
|
|
|
4
4
|
import { installUnityCommand } from './commands/install-unity.js';
|
|
5
5
|
import { openCommand } from './commands/open.js';
|
|
6
6
|
import { installPluginCommand } from './commands/install-plugin.js';
|
|
7
|
+
import { loginCommand } from './commands/login.js';
|
|
7
8
|
import { configureCommand } from './commands/configure.js';
|
|
8
9
|
import { removePluginCommand } from './commands/remove-plugin.js';
|
|
9
10
|
import { runToolCommand } from './commands/run-tool.js';
|
|
@@ -11,8 +12,10 @@ import { runSystemToolCommand } from './commands/run-system-tool.js';
|
|
|
11
12
|
import { setupMcpCommand } from './commands/setup-mcp.js';
|
|
12
13
|
import { setupSkillsCommand } from './commands/setup-skills.js';
|
|
13
14
|
import { statusCommand } from './commands/status.js';
|
|
15
|
+
import { createUpdateCommand } from './commands/update.js';
|
|
14
16
|
import { waitForReadyCommand } from './commands/wait-for-ready.js';
|
|
15
17
|
import { configureStyledHelp, error as uiError, setVerbose } from './utils/ui.js';
|
|
18
|
+
import { checkForUpdate, isRunningViaNpx, printUpdateNotification } from './utils/update-check.js';
|
|
16
19
|
const require = createRequire(import.meta.url);
|
|
17
20
|
const pkg = require('../package.json');
|
|
18
21
|
const program = new Command();
|
|
@@ -27,6 +30,7 @@ const subcommands = [
|
|
|
27
30
|
createProjectCommand,
|
|
28
31
|
installPluginCommand,
|
|
29
32
|
installUnityCommand,
|
|
33
|
+
loginCommand,
|
|
30
34
|
openCommand,
|
|
31
35
|
removePluginCommand,
|
|
32
36
|
runToolCommand,
|
|
@@ -34,6 +38,7 @@ const subcommands = [
|
|
|
34
38
|
setupMcpCommand,
|
|
35
39
|
setupSkillsCommand,
|
|
36
40
|
statusCommand,
|
|
41
|
+
createUpdateCommand(pkg.version),
|
|
37
42
|
waitForReadyCommand,
|
|
38
43
|
];
|
|
39
44
|
for (const cmd of subcommands) {
|
|
@@ -54,7 +59,16 @@ program.hook('preAction', (_thisCommand, actionCommand) => {
|
|
|
54
59
|
program.action(() => {
|
|
55
60
|
program.outputHelp();
|
|
56
61
|
});
|
|
57
|
-
|
|
62
|
+
// Start update check in background (non-blocking, parallel with command execution)
|
|
63
|
+
const updateCheckPromise = isRunningViaNpx() ? Promise.resolve(null) : checkForUpdate(pkg.version);
|
|
64
|
+
program.parseAsync()
|
|
65
|
+
.then(async () => {
|
|
66
|
+
const update = await updateCheckPromise;
|
|
67
|
+
if (update) {
|
|
68
|
+
printUpdateNotification(update.current, update.latest);
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
.catch((err) => {
|
|
58
72
|
uiError(err.message || String(err));
|
|
59
73
|
process.exit(1);
|
|
60
74
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,KAAK,IAAI,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface DeviceAuthorizeResponse {
|
|
2
|
+
device_code: string;
|
|
3
|
+
user_code: string;
|
|
4
|
+
verification_uri: string;
|
|
5
|
+
verification_uri_complete: string;
|
|
6
|
+
expires_in: number;
|
|
7
|
+
interval: number;
|
|
8
|
+
}
|
|
9
|
+
export type DeviceAuthResult = {
|
|
10
|
+
success: true;
|
|
11
|
+
accessToken: string;
|
|
12
|
+
} | {
|
|
13
|
+
success: false;
|
|
14
|
+
reason: 'expired' | 'denied' | 'error';
|
|
15
|
+
message: string;
|
|
16
|
+
};
|
|
17
|
+
export interface DeviceAuthCallbacks {
|
|
18
|
+
onUserCode: (userCode: string, verificationUrl: string) => void;
|
|
19
|
+
onPolling?: () => void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Run the RFC 8628 Device Authorization Grant flow against the given server.
|
|
23
|
+
*
|
|
24
|
+
* 1. POST /api/auth/device/authorize → get device_code + user_code
|
|
25
|
+
* 2. Invoke onUserCode so the caller can display instructions / open browser
|
|
26
|
+
* 3. Poll /api/auth/device/token until success, denial, or expiry
|
|
27
|
+
*/
|
|
28
|
+
export declare function deviceAuthFlow(baseUrl: string, clientLabel: string, callbacks: DeviceAuthCallbacks, minIntervalMs?: number): Promise<DeviceAuthResult>;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// Copyright (c) 2024 Ivan Murzak. All rights reserved.
|
|
2
|
+
// Licensed under the Apache License, Version 2.0.
|
|
3
|
+
import { verbose } from './ui.js';
|
|
4
|
+
// ─── Flow ────────────────────────────────────────────────────────────────────
|
|
5
|
+
/**
|
|
6
|
+
* Run the RFC 8628 Device Authorization Grant flow against the given server.
|
|
7
|
+
*
|
|
8
|
+
* 1. POST /api/auth/device/authorize → get device_code + user_code
|
|
9
|
+
* 2. Invoke onUserCode so the caller can display instructions / open browser
|
|
10
|
+
* 3. Poll /api/auth/device/token until success, denial, or expiry
|
|
11
|
+
*/
|
|
12
|
+
export async function deviceAuthFlow(baseUrl, clientLabel, callbacks, minIntervalMs) {
|
|
13
|
+
const authorizeUrl = `${baseUrl}/api/auth/device/authorize`;
|
|
14
|
+
verbose(`POST ${authorizeUrl}`);
|
|
15
|
+
const initResponse = await fetchWithTimeout(authorizeUrl, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: { 'Content-Type': 'application/json' },
|
|
18
|
+
body: JSON.stringify({ client_label: clientLabel }),
|
|
19
|
+
}, 30000);
|
|
20
|
+
if (!initResponse.ok) {
|
|
21
|
+
const text = await initResponse.text();
|
|
22
|
+
return {
|
|
23
|
+
success: false,
|
|
24
|
+
reason: 'error',
|
|
25
|
+
message: `Failed to initiate device auth (HTTP ${initResponse.status}): ${text}`,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const auth = (await initResponse.json());
|
|
29
|
+
verbose(`Device code received, user code: ${auth.user_code}, expires in ${auth.expires_in}s`);
|
|
30
|
+
callbacks.onUserCode(auth.user_code, auth.verification_uri_complete);
|
|
31
|
+
callbacks.onPolling?.();
|
|
32
|
+
const tokenUrl = `${baseUrl}/api/auth/device/token`;
|
|
33
|
+
const deadline = Date.now() + auth.expires_in * 1000;
|
|
34
|
+
const effectiveMinInterval = minIntervalMs ?? 5000;
|
|
35
|
+
let interval = Math.max(auth.interval * 1000, effectiveMinInterval);
|
|
36
|
+
while (Date.now() < deadline) {
|
|
37
|
+
await sleep(interval);
|
|
38
|
+
if (Date.now() >= deadline)
|
|
39
|
+
break;
|
|
40
|
+
verbose(`Polling ${tokenUrl} (interval=${interval / 1000}s)`);
|
|
41
|
+
const pollResponse = await fetchWithTimeout(tokenUrl, {
|
|
42
|
+
method: 'POST',
|
|
43
|
+
headers: { 'Content-Type': 'application/json' },
|
|
44
|
+
body: JSON.stringify({
|
|
45
|
+
device_code: auth.device_code,
|
|
46
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
47
|
+
}),
|
|
48
|
+
}, 15000);
|
|
49
|
+
if (pollResponse.ok) {
|
|
50
|
+
const data = (await pollResponse.json());
|
|
51
|
+
return { success: true, accessToken: data.access_token };
|
|
52
|
+
}
|
|
53
|
+
let errorData;
|
|
54
|
+
try {
|
|
55
|
+
errorData = (await pollResponse.json());
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return {
|
|
59
|
+
success: false,
|
|
60
|
+
reason: 'error',
|
|
61
|
+
message: `Unexpected response from token endpoint (HTTP ${pollResponse.status})`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
verbose(`Poll response: ${errorData.error} — ${errorData.error_description ?? ''}`);
|
|
65
|
+
switch (errorData.error) {
|
|
66
|
+
case 'authorization_pending':
|
|
67
|
+
break;
|
|
68
|
+
case 'slow_down':
|
|
69
|
+
interval = Math.min(interval + 5000, 30000);
|
|
70
|
+
verbose(`Slowing down, new interval: ${interval / 1000}s`);
|
|
71
|
+
break;
|
|
72
|
+
case 'expired_token':
|
|
73
|
+
return {
|
|
74
|
+
success: false,
|
|
75
|
+
reason: 'expired',
|
|
76
|
+
message: errorData.error_description ?? 'Device code expired. Please try again.',
|
|
77
|
+
};
|
|
78
|
+
case 'access_denied':
|
|
79
|
+
return {
|
|
80
|
+
success: false,
|
|
81
|
+
reason: 'denied',
|
|
82
|
+
message: errorData.error_description ?? 'Authorization was denied.',
|
|
83
|
+
};
|
|
84
|
+
default:
|
|
85
|
+
return {
|
|
86
|
+
success: false,
|
|
87
|
+
reason: 'error',
|
|
88
|
+
message: errorData.error_description ?? `Unexpected error: ${errorData.error}`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
success: false,
|
|
94
|
+
reason: 'expired',
|
|
95
|
+
message: 'Device code expired. Please try again.',
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function sleep(ms) {
|
|
99
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
100
|
+
}
|
|
101
|
+
async function fetchWithTimeout(url, options, timeoutMs) {
|
|
102
|
+
const controller = new AbortController();
|
|
103
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
104
|
+
try {
|
|
105
|
+
return await fetch(url, { ...options, signal: controller.signal });
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
clearTimeout(timer);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/utils/auth.ts"],"names":[],"mappings":"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"}
|