unity-mcp-cli 0.87.0 → 0.89.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 +60 -2
- package/dist/commands/install-extension.d.ts +2 -0
- package/dist/commands/install-extension.js +99 -0
- package/dist/commands/install-extension.js.map +1 -0
- package/dist/commands/install-plugin.js +20 -0
- package/dist/commands/install-plugin.js.map +1 -1
- package/dist/commands/login.js +47 -2
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/run-tool-builder.js +19 -3
- package/dist/commands/run-tool-builder.js.map +1 -1
- package/dist/commands/setup-skills.js +1 -1
- package/dist/commands/setup-skills.js.map +1 -1
- package/dist/commands/status.js +1 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/wait-for-ready.js +4 -4
- package/dist/commands/wait-for-ready.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/install-extension.d.ts +25 -0
- package/dist/lib/install-extension.js +182 -0
- package/dist/lib/install-extension.js.map +1 -0
- package/dist/lib/run-tool.js +79 -41
- package/dist/lib/run-tool.js.map +1 -1
- package/dist/lib/types.d.ts +92 -4
- package/dist/lib.d.ts +4 -1
- package/dist/lib.js +5 -0
- package/dist/lib.js.map +1 -1
- package/dist/utils/cloud-credentials.d.ts +43 -0
- package/dist/utils/cloud-credentials.js +84 -0
- package/dist/utils/cloud-credentials.js.map +1 -0
- package/dist/utils/cloud-login.d.ts +29 -13
- package/dist/utils/cloud-login.js +198 -17
- package/dist/utils/cloud-login.js.map +1 -1
- package/dist/utils/config.d.ts +15 -21
- package/dist/utils/config.js +8 -26
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/connection.d.ts +8 -5
- package/dist/utils/connection.js +7 -3
- package/dist/utils/connection.js.map +1 -1
- package/dist/utils/extensions-catalog.d.ts +40 -0
- package/dist/utils/extensions-catalog.js +197 -0
- package/dist/utils/extensions-catalog.js.map +1 -0
- package/dist/utils/manifest.d.ts +38 -0
- package/dist/utils/manifest.js +50 -8
- package/dist/utils/manifest.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import { EXTENSIONS_CATALOG, findExtension, hasVersion, } from '../utils/extensions-catalog.js';
|
|
3
|
+
import { addPackageToManifest, resolveLatestPackageVersion } from '../utils/manifest.js';
|
|
4
|
+
import { silentLogger } from './logger.js';
|
|
5
|
+
import { emitProgress } from './progress.js';
|
|
6
|
+
import { requireUnityProject } from './validation.js';
|
|
7
|
+
/**
|
|
8
|
+
* Install (or update) a Unity-MCP extension into a consumer Unity project, as a
|
|
9
|
+
* REAL installer that is behaviourally identical to the in-editor window's
|
|
10
|
+
* `ExtensionPanel`:
|
|
11
|
+
*
|
|
12
|
+
* 1. Resolve `extensionId` to a descriptor in the SHARED catalogue
|
|
13
|
+
* (`Unity-MCP-Plugin/Packages/com.ivanmurzak.unity.mcp/extensions.catalog.json`,
|
|
14
|
+
* mirrored here by `EXTENSIONS_CATALOG`).
|
|
15
|
+
* 2. Validate that the target path hosts a Unity project (`Packages/manifest.json`).
|
|
16
|
+
* 3. Resolve the version to install: the explicit `version` override, else the
|
|
17
|
+
* catalogue pin, else OpenUPM's `dist-tags.latest` fetched live. Every shipped
|
|
18
|
+
* catalogue entry is unpinned, so the live fetch is the normal path.
|
|
19
|
+
* 4. Read-modify-write `Packages/manifest.json`: ensure the OpenUPM scoped registry
|
|
20
|
+
* and its required scopes, then add or version-bump the package dependency.
|
|
21
|
+
* 5. Tell the caller Unity must resolve packages (the CLI cannot call
|
|
22
|
+
* `UnityEditor.PackageManager.Client.Resolve()` — only the editor can).
|
|
23
|
+
*
|
|
24
|
+
* Library-safe: no stdout noise, no `process.exit`, no throws past the public
|
|
25
|
+
* boundary; returns a `{ kind: 'success' | 'failure' }` union. Idempotent: a re-run
|
|
26
|
+
* that finds the dependency at an equal-or-newer version reports
|
|
27
|
+
* `already-up-to-date` and makes no write. Mirrors `installPlugin`'s shape exactly
|
|
28
|
+
* so the app can adopt it the same way.
|
|
29
|
+
*/
|
|
30
|
+
export async function installExtension(opts) {
|
|
31
|
+
const warnings = [];
|
|
32
|
+
const nextSteps = [];
|
|
33
|
+
const extensionId = opts?.extensionId ?? '';
|
|
34
|
+
try {
|
|
35
|
+
const catalog = opts.catalog ?? EXTENSIONS_CATALOG;
|
|
36
|
+
const resolved = findExtension(extensionId, catalog);
|
|
37
|
+
if (resolved === null) {
|
|
38
|
+
return {
|
|
39
|
+
kind: 'failure',
|
|
40
|
+
success: false,
|
|
41
|
+
extensionId,
|
|
42
|
+
warnings,
|
|
43
|
+
nextSteps,
|
|
44
|
+
error: new Error(unknownExtensionMessage(extensionId, catalog)),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const validated = requireUnityProject(opts?.unityProjectPath);
|
|
48
|
+
if (!validated.ok) {
|
|
49
|
+
return {
|
|
50
|
+
kind: 'failure',
|
|
51
|
+
success: false,
|
|
52
|
+
extensionId,
|
|
53
|
+
packageId: resolved.packageId,
|
|
54
|
+
manifestPath: validated.manifestPath,
|
|
55
|
+
warnings,
|
|
56
|
+
nextSteps,
|
|
57
|
+
error: validated.error,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const { projectPath } = validated;
|
|
61
|
+
emitProgress(opts.onProgress, {
|
|
62
|
+
phase: 'start',
|
|
63
|
+
message: `Installing extension ${resolved.packageId} into ${projectPath}`,
|
|
64
|
+
});
|
|
65
|
+
// Apply the optional `version` override (drives both the pin written and, via
|
|
66
|
+
// `force`, whether a downgrade is permitted).
|
|
67
|
+
const descriptor = applyVersionOverride(resolved, opts.version, warnings);
|
|
68
|
+
const isExplicitVersion = (opts.version ?? '').trim() !== '';
|
|
69
|
+
let version;
|
|
70
|
+
if (hasVersion(descriptor)) {
|
|
71
|
+
// Non-null only for an explicit override or a (currently unused) catalogue pin.
|
|
72
|
+
version = descriptor.version;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
version = await resolveLatestPackageVersion(descriptor.packageId, silentLogger, '--extension-version');
|
|
76
|
+
emitProgress(opts.onProgress, {
|
|
77
|
+
phase: 'dependencies-resolved',
|
|
78
|
+
message: `Resolved latest ${descriptor.packageId} version: ${version}`,
|
|
79
|
+
version,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const before = readInstalledVersion(validated.manifestPath, descriptor.packageId);
|
|
83
|
+
const result = addPackageToManifest(projectPath, descriptor.packageId, version, isExplicitVersion, silentLogger);
|
|
84
|
+
// `addPackageToManifest` refuses to downgrade unless `force`; surface that as a
|
|
85
|
+
// warning rather than silently reporting the requested version.
|
|
86
|
+
if (result.resolvedVersion !== version && !isExplicitVersion) {
|
|
87
|
+
warnings.push(`${descriptor.packageId} is already at version ${result.resolvedVersion} (>= ${version}). ` +
|
|
88
|
+
'Skipping version update. Pass an explicit `version` to force a specific value.');
|
|
89
|
+
}
|
|
90
|
+
emitProgress(opts.onProgress, {
|
|
91
|
+
phase: 'manifest-patched',
|
|
92
|
+
message: result.modified
|
|
93
|
+
? `Updated ${result.manifestPath}`
|
|
94
|
+
: 'manifest.json is already up to date.',
|
|
95
|
+
manifestPath: result.manifestPath,
|
|
96
|
+
});
|
|
97
|
+
// Derive the outcome from what was actually on disk before the write, NOT from
|
|
98
|
+
// `modified` alone: `modified` is also true when only the scoped registry had to
|
|
99
|
+
// be added, which is not an "added extension".
|
|
100
|
+
const outcome = before === null
|
|
101
|
+
? 'added'
|
|
102
|
+
: result.resolvedVersion === before
|
|
103
|
+
? 'already-up-to-date'
|
|
104
|
+
: 'updated';
|
|
105
|
+
const message = outcome === 'added'
|
|
106
|
+
? `Added ${descriptor.packageId} ${result.resolvedVersion}. Unity will resolve the package on next focus.`
|
|
107
|
+
: outcome === 'updated'
|
|
108
|
+
? `Updated ${descriptor.packageId} from ${before} to ${result.resolvedVersion}.`
|
|
109
|
+
: `${descriptor.name} is already installed and up to date (${result.resolvedVersion}).`;
|
|
110
|
+
if (outcome !== 'already-up-to-date') {
|
|
111
|
+
nextSteps.push('Open (or focus) the Unity Editor so the Package Manager resolves the new dependency.');
|
|
112
|
+
}
|
|
113
|
+
emitProgress(opts.onProgress, { phase: 'done', message: 'Extension install complete.' });
|
|
114
|
+
return {
|
|
115
|
+
kind: 'success',
|
|
116
|
+
success: true,
|
|
117
|
+
outcome,
|
|
118
|
+
changed: outcome !== 'already-up-to-date',
|
|
119
|
+
extensionId,
|
|
120
|
+
packageId: descriptor.packageId,
|
|
121
|
+
fromVersion: before,
|
|
122
|
+
toVersion: result.resolvedVersion,
|
|
123
|
+
manifestPath: result.manifestPath,
|
|
124
|
+
message,
|
|
125
|
+
warnings,
|
|
126
|
+
nextSteps,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
return {
|
|
131
|
+
kind: 'failure',
|
|
132
|
+
success: false,
|
|
133
|
+
extensionId,
|
|
134
|
+
warnings,
|
|
135
|
+
nextSteps,
|
|
136
|
+
error: err instanceof Error ? err : new Error(String(err)),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Read the version currently pinned for `packageId` in the project manifest, or
|
|
142
|
+
* `null` when the dependency is absent. Used to classify the outcome as
|
|
143
|
+
* added / updated / already-up-to-date, which `addPackageToManifest`'s
|
|
144
|
+
* `{ modified }` flag cannot express on its own.
|
|
145
|
+
*
|
|
146
|
+
* Deliberately forgiving: any read/parse problem yields `null` (treated as
|
|
147
|
+
* "not installed"). The subsequent `addPackageToManifest` call performs the
|
|
148
|
+
* authoritative read and throws a precise error if the manifest is unusable, so
|
|
149
|
+
* swallowing here cannot mask a real failure — it only avoids duplicating the
|
|
150
|
+
* error path.
|
|
151
|
+
*/
|
|
152
|
+
function readInstalledVersion(manifestPath, packageId) {
|
|
153
|
+
try {
|
|
154
|
+
const raw = fs.readFileSync(manifestPath, 'utf-8');
|
|
155
|
+
const parsed = JSON.parse(raw);
|
|
156
|
+
const current = parsed?.dependencies?.[packageId];
|
|
157
|
+
return typeof current === 'string' && current.trim() !== '' ? current : null;
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/** Return a descriptor with the `version` override applied (empty/whitespace override is ignored). */
|
|
164
|
+
function applyVersionOverride(descriptor, version, warnings) {
|
|
165
|
+
const v = (version ?? '').trim();
|
|
166
|
+
if (v === '')
|
|
167
|
+
return descriptor;
|
|
168
|
+
if (descriptor.version !== null && descriptor.version !== v) {
|
|
169
|
+
warnings.push(`version ${v} overrides the catalogue pin ${descriptor.packageId}@${descriptor.version} for this install.`);
|
|
170
|
+
}
|
|
171
|
+
return { ...descriptor, version: v };
|
|
172
|
+
}
|
|
173
|
+
/** A clear "unknown extension" error that lists what IS installable (or says the catalogue is empty). */
|
|
174
|
+
function unknownExtensionMessage(id, catalog) {
|
|
175
|
+
if (catalog.length === 0) {
|
|
176
|
+
return (`Unknown extension "${id}". The Unity-MCP extension catalogue is currently empty, ` +
|
|
177
|
+
'so there is nothing to install.');
|
|
178
|
+
}
|
|
179
|
+
const available = catalog.map((d) => d.packageId).join(', ');
|
|
180
|
+
return `Unknown extension "${id}". Available extensions: ${available}.`;
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=install-extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-extension.js","sourceRoot":"","sources":["../../src/lib/install-extension.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/run-tool.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// - Errors are returned in `{ kind: 'failure', success: false, ... }`,
|
|
6
6
|
// never thrown past the public boundary.
|
|
7
7
|
import { readConfig, resolveConnectionFromConfig, isCloudMode } from '../utils/config.js';
|
|
8
|
+
import { readCloudAccessToken, refreshCloudAccessToken } from '../utils/cloud-credentials.js';
|
|
8
9
|
import { generatePortFromDirectory } from '../utils/port.js';
|
|
9
10
|
import { requireProjectPath } from './validation.js';
|
|
10
11
|
const DEFAULT_TIMEOUT_MS = 60000;
|
|
@@ -30,22 +31,10 @@ async function invokeTool(routePrefix, opts) {
|
|
|
30
31
|
const validationFailure = validateOptions(opts);
|
|
31
32
|
if (validationFailure)
|
|
32
33
|
return validationFailure;
|
|
33
|
-
const resolved = resolveConnection(opts);
|
|
34
|
-
if (resolved.kind === 'failure')
|
|
35
|
-
return resolved;
|
|
36
|
-
const { url, token } = resolved;
|
|
37
|
-
const body = serializeInput(opts.input);
|
|
38
|
-
if ('error' in body) {
|
|
39
|
-
return makeFailure({
|
|
40
|
-
endpoint: '',
|
|
41
|
-
reason: 'invalid-input',
|
|
42
|
-
message: body.error.message,
|
|
43
|
-
error: body.error,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
const endpoint = `${url}${routePrefix}/${encodeURIComponent(opts.toolName)}`;
|
|
47
34
|
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
48
35
|
const timeoutMs = typeof opts.timeoutMs === 'number' && opts.timeoutMs > 0 ? opts.timeoutMs : DEFAULT_TIMEOUT_MS;
|
|
36
|
+
// Wire the abort/timeout plumbing BEFORE the first await so an external abort issued right
|
|
37
|
+
// after the call is never lost (connection resolution below may itself await a token refresh).
|
|
49
38
|
const controller = new AbortController();
|
|
50
39
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
51
40
|
const externalAbort = () => controller.abort();
|
|
@@ -55,35 +44,76 @@ async function invokeTool(routePrefix, opts) {
|
|
|
55
44
|
else
|
|
56
45
|
opts.signal.addEventListener('abort', externalAbort, { once: true });
|
|
57
46
|
}
|
|
58
|
-
|
|
59
|
-
if (token)
|
|
60
|
-
headers['Authorization'] = `Bearer ${token}`;
|
|
47
|
+
let endpoint = '';
|
|
61
48
|
try {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const text = await safeReadText(response);
|
|
69
|
-
const data = parseJsonOrText(text);
|
|
70
|
-
if (!response.ok) {
|
|
49
|
+
const resolved = await resolveConnection(opts);
|
|
50
|
+
if (resolved.kind === 'failure')
|
|
51
|
+
return resolved;
|
|
52
|
+
const { url, token } = resolved;
|
|
53
|
+
const body = serializeInput(opts.input);
|
|
54
|
+
if ('error' in body) {
|
|
71
55
|
return makeFailure({
|
|
56
|
+
endpoint: '',
|
|
57
|
+
reason: 'invalid-input',
|
|
58
|
+
message: body.error.message,
|
|
59
|
+
error: body.error,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
endpoint = `${url}${routePrefix}/${encodeURIComponent(opts.toolName)}`;
|
|
63
|
+
// Reactive-refresh loop (unified-machine-auth 04 §3 rule 1): when the Bearer came from the
|
|
64
|
+
// shared machine credential store and the server answers 401 — revocation or clock skew the
|
|
65
|
+
// proactive expiry check could not see — refresh the plugin family once under the
|
|
66
|
+
// cross-process lock and retry the call with the rotated token. At most ONE reactive attempt
|
|
67
|
+
// per invocation; an explicit --token / --url override is never refreshed. Both attempts
|
|
68
|
+
// share one timeout.
|
|
69
|
+
let bearer = token;
|
|
70
|
+
let attemptedReactiveRefresh = false;
|
|
71
|
+
for (;;) {
|
|
72
|
+
// Mirror fetch's contract for an ALREADY-aborted signal (an external abort may land while
|
|
73
|
+
// connection resolution above is awaiting): reject up front instead of relying on the
|
|
74
|
+
// 'abort' event, which has already fired.
|
|
75
|
+
if (controller.signal.aborted) {
|
|
76
|
+
throw new DOMException('The operation was aborted', 'AbortError');
|
|
77
|
+
}
|
|
78
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
79
|
+
if (bearer)
|
|
80
|
+
headers['Authorization'] = `Bearer ${bearer}`;
|
|
81
|
+
const response = await fetchImpl(endpoint, {
|
|
82
|
+
method: 'POST',
|
|
83
|
+
headers,
|
|
84
|
+
body: body.json,
|
|
85
|
+
signal: controller.signal,
|
|
86
|
+
});
|
|
87
|
+
const text = await safeReadText(response);
|
|
88
|
+
const data = parseJsonOrText(text);
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
if (response.status === 401 &&
|
|
91
|
+
resolved.tokenFromCloudStore &&
|
|
92
|
+
!attemptedReactiveRefresh) {
|
|
93
|
+
attemptedReactiveRefresh = true;
|
|
94
|
+
const fresh = await (opts.refreshCloudToken ?? refreshCloudAccessToken)();
|
|
95
|
+
if (fresh) {
|
|
96
|
+
bearer = fresh;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return makeFailure({
|
|
101
|
+
endpoint,
|
|
102
|
+
reason: 'http-error',
|
|
103
|
+
httpStatus: response.status,
|
|
104
|
+
data,
|
|
105
|
+
message: response.statusText || `HTTP ${response.status}`,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
const success = {
|
|
109
|
+
kind: 'success',
|
|
110
|
+
success: true,
|
|
72
111
|
endpoint,
|
|
73
|
-
reason: 'http-error',
|
|
74
112
|
httpStatus: response.status,
|
|
75
113
|
data,
|
|
76
|
-
|
|
77
|
-
|
|
114
|
+
};
|
|
115
|
+
return success;
|
|
78
116
|
}
|
|
79
|
-
const success = {
|
|
80
|
-
kind: 'success',
|
|
81
|
-
success: true,
|
|
82
|
-
endpoint,
|
|
83
|
-
httpStatus: response.status,
|
|
84
|
-
data,
|
|
85
|
-
};
|
|
86
|
-
return success;
|
|
87
117
|
}
|
|
88
118
|
catch (err) {
|
|
89
119
|
return classifyFetchError(err, endpoint, timeoutMs);
|
|
@@ -119,9 +149,14 @@ function validateOptions(opts) {
|
|
|
119
149
|
}
|
|
120
150
|
return null;
|
|
121
151
|
}
|
|
122
|
-
function resolveConnection(opts) {
|
|
152
|
+
async function resolveConnection(opts) {
|
|
123
153
|
if (opts.url) {
|
|
124
|
-
return {
|
|
154
|
+
return {
|
|
155
|
+
kind: 'success',
|
|
156
|
+
url: opts.url.replace(/\/$/, ''),
|
|
157
|
+
token: opts.token,
|
|
158
|
+
tokenFromCloudStore: false,
|
|
159
|
+
};
|
|
125
160
|
}
|
|
126
161
|
// `unityProjectPath` is library-only — does NOT require an `Assets/`
|
|
127
162
|
// folder, unlike the CLI's `resolveAndValidateProjectPath`. The
|
|
@@ -138,7 +173,9 @@ function resolveConnection(opts) {
|
|
|
138
173
|
const projectPath = validated.projectPath;
|
|
139
174
|
const config = readConfig(projectPath);
|
|
140
175
|
const fromConfig = config
|
|
141
|
-
? resolveConnectionFromConfig(config, {
|
|
176
|
+
? await resolveConnectionFromConfig(config, {
|
|
177
|
+
readCloudToken: opts.readCloudToken ?? readCloudAccessToken,
|
|
178
|
+
})
|
|
142
179
|
: { url: undefined, token: undefined };
|
|
143
180
|
const url = fromConfig.url
|
|
144
181
|
? fromConfig.url.replace(/\/$/, '')
|
|
@@ -154,7 +191,8 @@ function resolveConnection(opts) {
|
|
|
154
191
|
message: 'Not logged in to ai-game.dev. Run `unity-mcp-cli login` to sign in, or pass an explicit --token / --url.',
|
|
155
192
|
});
|
|
156
193
|
}
|
|
157
|
-
|
|
194
|
+
const tokenFromCloudStore = !!config && isCloudMode(config) && !opts.token && !!token;
|
|
195
|
+
return { kind: 'success', url, token, tokenFromCloudStore };
|
|
158
196
|
}
|
|
159
197
|
function serializeInput(input) {
|
|
160
198
|
if (input === undefined || input === null)
|
package/dist/lib/run-tool.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-tool.js","sourceRoot":"","sources":["../../src/lib/run-tool.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,EAAE;AACF,yDAAyD;AACzD,mEAAmE;AACnE,uEAAuE;AACvE,2CAA2C;AAE3C,OAAO,EAAE,UAAU,EAAE,2BAA2B,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC1F,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AASrD,MAAM,kBAAkB,GAAG,KAAM,CAAC;AAOlC;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAoB;IAChD,OAAO,UAAU,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAoB;IACtD,OAAO,UAAU,CAAC,mBAAmB,EAAE,IAAI,CAAC,CAAC;AAC/C,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,WAAmB,EAAE,IAAoB;IACjE,MAAM,iBAAiB,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IAChD,IAAI,iBAAiB;QAAE,OAAO,iBAAiB,CAAC;IAEhD,MAAM,
|
|
1
|
+
{"version":3,"file":"run-tool.js","sourceRoot":"","sources":["../../src/lib/run-tool.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ExtensionDescriptor } from '../utils/extensions-catalog.js';
|
|
1
2
|
/**
|
|
2
3
|
* Discriminated union describing every progress event the library can
|
|
3
4
|
* emit to the optional `onProgress` callback.
|
|
@@ -120,6 +121,84 @@ export interface InstallFailure {
|
|
|
120
121
|
error: Error;
|
|
121
122
|
}
|
|
122
123
|
export type InstallResult = InstallSuccess | InstallFailure;
|
|
124
|
+
/**
|
|
125
|
+
* What `installExtension` actually did. Distinguished from `changed` because a
|
|
126
|
+
* caller usually wants to say "installed" vs "updated" vs "nothing to do" in its
|
|
127
|
+
* UI, and `changed` alone cannot tell the first two apart.
|
|
128
|
+
*/
|
|
129
|
+
export type InstallExtensionOutcome = 'added' | 'updated' | 'already-up-to-date';
|
|
130
|
+
export interface InstallExtensionOptions {
|
|
131
|
+
/** Absolute or relative path to the Unity project's root. */
|
|
132
|
+
unityProjectPath: string;
|
|
133
|
+
/**
|
|
134
|
+
* Extension to install — either the OpenUPM package id
|
|
135
|
+
* (`com.ivanmurzak.unity.mcp.tilemap`) or the catalogue display name
|
|
136
|
+
* (`Tilemap`). Matched case-insensitively, package id first.
|
|
137
|
+
*/
|
|
138
|
+
extensionId: string;
|
|
139
|
+
/**
|
|
140
|
+
* Version to install. When omitted, OpenUPM's `dist-tags.latest` is resolved
|
|
141
|
+
* live at install time — which is the normal path, because every catalogue
|
|
142
|
+
* entry is unpinned (`version: null`). Supplying a value also permits a
|
|
143
|
+
* downgrade, mirroring `installPlugin`'s explicit-version semantics.
|
|
144
|
+
*/
|
|
145
|
+
version?: string;
|
|
146
|
+
/**
|
|
147
|
+
* Catalogue override, for tests and for callers that carry their own list.
|
|
148
|
+
* Defaults to the built-in `EXTENSIONS_CATALOG`.
|
|
149
|
+
*/
|
|
150
|
+
catalog?: readonly ExtensionDescriptor[];
|
|
151
|
+
/**
|
|
152
|
+
* Optional progress callback — fires for `start`, `dependencies-resolved`
|
|
153
|
+
* (when the version was auto-resolved), `manifest-patched`, and `done`.
|
|
154
|
+
*/
|
|
155
|
+
onProgress?: ProgressCallback;
|
|
156
|
+
}
|
|
157
|
+
/** Successful `installExtension` outcome. Narrow with `kind === 'success'`. */
|
|
158
|
+
export interface InstallExtensionSuccess {
|
|
159
|
+
kind: 'success';
|
|
160
|
+
/** Always `true` for the success variant. */
|
|
161
|
+
success: true;
|
|
162
|
+
/** What happened — see {@link InstallExtensionOutcome}. */
|
|
163
|
+
outcome: InstallExtensionOutcome;
|
|
164
|
+
/** `true` when `manifest.json` was written. `false` for `already-up-to-date`. */
|
|
165
|
+
changed: boolean;
|
|
166
|
+
/** The `extensionId` as supplied by the caller. */
|
|
167
|
+
extensionId: string;
|
|
168
|
+
/** The resolved OpenUPM package id that was written to the manifest. */
|
|
169
|
+
packageId: string;
|
|
170
|
+
/** Version present before the call, or `null` when the extension was absent. */
|
|
171
|
+
fromVersion: string | null;
|
|
172
|
+
/** Version present after the call. */
|
|
173
|
+
toVersion: string;
|
|
174
|
+
/** Absolute path to the `Packages/manifest.json` that was inspected / written. */
|
|
175
|
+
manifestPath: string;
|
|
176
|
+
/** Human-readable summary the caller may surface directly. */
|
|
177
|
+
message: string;
|
|
178
|
+
/** Non-fatal warnings collected during the run. */
|
|
179
|
+
warnings: string[];
|
|
180
|
+
/** Suggested next steps for the caller to surface to a human user. */
|
|
181
|
+
nextSteps: string[];
|
|
182
|
+
}
|
|
183
|
+
/** Failed `installExtension` outcome. Narrow with `kind === 'failure'`. */
|
|
184
|
+
export interface InstallExtensionFailure {
|
|
185
|
+
kind: 'failure';
|
|
186
|
+
/** Always `false` for the failure variant. */
|
|
187
|
+
success: false;
|
|
188
|
+
/** The `extensionId` as supplied by the caller. */
|
|
189
|
+
extensionId: string;
|
|
190
|
+
/** Resolved package id, when catalogue lookup succeeded before the failure. */
|
|
191
|
+
packageId?: string;
|
|
192
|
+
/** Manifest path may be known even on failure (e.g. a validation failure that reached it). */
|
|
193
|
+
manifestPath?: string;
|
|
194
|
+
/** Non-fatal warnings collected before the failure. */
|
|
195
|
+
warnings: string[];
|
|
196
|
+
/** Suggested next steps the caller may surface to a human user. */
|
|
197
|
+
nextSteps: string[];
|
|
198
|
+
/** The captured error. Never thrown past this boundary. */
|
|
199
|
+
error: Error;
|
|
200
|
+
}
|
|
201
|
+
export type InstallExtensionResult = InstallExtensionSuccess | InstallExtensionFailure;
|
|
123
202
|
export interface RemovePluginOptions {
|
|
124
203
|
unityProjectPath: string;
|
|
125
204
|
onProgress?: ProgressCallback;
|
|
@@ -558,11 +637,20 @@ export interface RunToolOptions {
|
|
|
558
637
|
fetchImpl?: typeof fetch;
|
|
559
638
|
/**
|
|
560
639
|
* Optional injection point for the Cloud-mode Bearer credential read from the shared machine
|
|
561
|
-
* credential store
|
|
562
|
-
*
|
|
563
|
-
*
|
|
640
|
+
* credential store. Only consulted when the resolved project config is in Cloud mode and neither
|
|
641
|
+
* `url` nor `token` was supplied. Defaults to cli-core's `MachineCredentialProvider` (proactive
|
|
642
|
+
* refresh under the cross-process lock — never a raw on-disk read); tests inject a deterministic
|
|
643
|
+
* value. Sync or async both work.
|
|
644
|
+
*/
|
|
645
|
+
readCloudToken?: () => Promise<string | undefined> | string | undefined;
|
|
646
|
+
/**
|
|
647
|
+
* Optional injection point for the REACTIVE Cloud-mode refresh: invoked at most once per call
|
|
648
|
+
* when the server answers 401 to a machine-store Bearer (revocation / clock skew). Returns the
|
|
649
|
+
* rotated access token, or `undefined` when the credential family is dead (the call then fails
|
|
650
|
+
* with the original 401). Defaults to cli-core's `MachineCredentialProvider.refresh`. Never
|
|
651
|
+
* consulted for an explicit `token` / `url` override.
|
|
564
652
|
*/
|
|
565
|
-
|
|
653
|
+
refreshCloudToken?: () => Promise<string | undefined> | string | undefined;
|
|
566
654
|
}
|
|
567
655
|
/** Successful `runTool` / `runSystemTool` outcome. Narrow with `kind === 'success'`. */
|
|
568
656
|
export interface RunToolSuccess {
|
package/dist/lib.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
export { installPlugin } from './lib/install-plugin.js';
|
|
2
|
+
export { installExtension } from './lib/install-extension.js';
|
|
2
3
|
export { removePlugin } from './lib/remove-plugin.js';
|
|
3
4
|
export { configure } from './lib/configure.js';
|
|
4
5
|
export { setupMcp, listAgentIds } from './lib/setup-mcp.js';
|
|
5
6
|
export { openProject } from './lib/open.js';
|
|
6
7
|
export { createProject } from './lib/create-project.js';
|
|
7
8
|
export { runTool, runSystemTool } from './lib/run-tool.js';
|
|
8
|
-
export
|
|
9
|
+
export { EXTENSIONS_CATALOG, findExtension, hasVersion, } from './utils/extensions-catalog.js';
|
|
10
|
+
export type { ExtensionDescriptor, ExtensionTool, } from './utils/extensions-catalog.js';
|
|
11
|
+
export type { ProgressEvent, ProgressCallback, ResultKind, InstallPluginOptions, InstallResult, InstallSuccess, InstallFailure, InstallExtensionOptions, InstallExtensionResult, InstallExtensionSuccess, InstallExtensionFailure, InstallExtensionOutcome, RemovePluginOptions, RemoveResult, RemoveSuccess, RemoveFailure, ConfigureOptions, ConfigureResult, ConfigureSuccess, ConfigureFailure, ConfigureSnapshot, FeatureAction, McpFeatureSnapshot, SetupMcpOptions, SetupMcpResult, SetupMcpSuccess, SetupMcpFailure, McpTransport, OpenProjectOptions, OpenProjectResult, OpenProjectSuccess, OpenProjectFailure, OpenProjectAuthOption, OpenProjectTransport, CreateProjectOptions, CreateProjectResult, CreateProjectSuccess, CreateProjectFailure, CreateProjectEditorInfo, RunToolOptions, RunToolResult, RunToolSuccess, RunToolFailure, RunToolFailureReason, RunSystemToolOptions, RunSystemToolResult, RunSystemToolSuccess, RunSystemToolFailure, } from './lib/types.js';
|
package/dist/lib.js
CHANGED
|
@@ -16,10 +16,15 @@
|
|
|
16
16
|
// Consumers: `import { installPlugin } from 'unity-mcp-cli'` (maps to
|
|
17
17
|
// this file via the `exports` field in package.json).
|
|
18
18
|
export { installPlugin } from './lib/install-plugin.js';
|
|
19
|
+
export { installExtension } from './lib/install-extension.js';
|
|
19
20
|
export { removePlugin } from './lib/remove-plugin.js';
|
|
20
21
|
export { configure } from './lib/configure.js';
|
|
21
22
|
export { setupMcp, listAgentIds } from './lib/setup-mcp.js';
|
|
22
23
|
export { openProject } from './lib/open.js';
|
|
23
24
|
export { createProject } from './lib/create-project.js';
|
|
24
25
|
export { runTool, runSystemTool } from './lib/run-tool.js';
|
|
26
|
+
// The extension catalogue is part of the public library surface: a consumer that
|
|
27
|
+
// renders an "install an extension" list (the desktop app) needs the same ten
|
|
28
|
+
// entries the CLI installs from, and must not re-declare them.
|
|
29
|
+
export { EXTENSIONS_CATALOG, findExtension, hasVersion, } from './utils/extensions-catalog.js';
|
|
25
30
|
//# sourceMappingURL=lib.js.map
|
package/dist/lib.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,qDAAqD;AACrD,iEAAiE;AACjE,sEAAsE;AACtE,oDAAoD;AACpD,yEAAyE;AACzE,0EAA0E;AAC1E,0EAA0E;AAC1E,uEAAuE;AACvE,uEAAuE;AACvE,iEAAiE;AACjE,oEAAoE;AACpE,2BAA2B;AAC3B,EAAE;AACF,sEAAsE;AACtE,sDAAsD;AAEtD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"lib.js","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,qDAAqD;AACrD,iEAAiE;AACjE,sEAAsE;AACtE,oDAAoD;AACpD,yEAAyE;AACzE,0EAA0E;AAC1E,0EAA0E;AAC1E,uEAAuE;AACvE,uEAAuE;AACvE,iEAAiE;AACjE,oEAAoE;AACpE,2BAA2B;AAC3B,EAAE;AACF,sEAAsE;AACtE,sDAAsD;AAEtD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAE3D,iFAAiF;AACjF,8EAA8E;AAC9E,+DAA+D;AAC/D,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,UAAU,GACX,MAAM,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { MachineCredentialProvider, MachineCredentialStore } from '@baizor/gamedev-cli-core';
|
|
2
|
+
/**
|
|
3
|
+
* The CLI's single seam onto cli-core's `MachineCredentialProvider` (unified-machine-auth 02/04,
|
|
4
|
+
* task d2 / W2). Every Cloud-mode Bearer the CLI presents comes through here — the provider owns
|
|
5
|
+
* proactive refresh (inside the 60 s expiry skew), reactive refresh (driven by a hub 401), the
|
|
6
|
+
* cross-process credential lock, and the family-aware machine-store view. The CLI never reads
|
|
7
|
+
* `accessToken` raw off disk: a raw read returns a token that may be seconds from expiry (or past
|
|
8
|
+
* it) with nobody refreshing, which is exactly the defect this module replaces
|
|
9
|
+
* (the pre-d2 `readMachineStoreCloudToken`).
|
|
10
|
+
*/
|
|
11
|
+
/** Injectable construction options — tests point the provider at a temp store + a fake AS. */
|
|
12
|
+
export interface CloudCredentialProviderOptions {
|
|
13
|
+
/** The credential store to serve from; defaults to the shared per-machine store. */
|
|
14
|
+
store?: MachineCredentialStore;
|
|
15
|
+
/** Authorization-server base for the refresh endpoint; defaults to the hosted cloud. */
|
|
16
|
+
serverBaseUrl?: string;
|
|
17
|
+
/** Injectable `fetch` for the refresher (tests). */
|
|
18
|
+
fetchImpl?: typeof fetch;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Build a `MachineCredentialProvider` wired the way this CLI consumes it:
|
|
22
|
+
* `HttpTokenRefresher` against the AS root, and `unity-mcp-cli` as the component-default client
|
|
23
|
+
* id — used ONLY for `families.legacy` (a stored family's own `clientId` always wins, 04 §3).
|
|
24
|
+
*/
|
|
25
|
+
export declare function createCloudCredentialProvider(options?: CloudCredentialProviderOptions): MachineCredentialProvider;
|
|
26
|
+
/** TEST-ONLY: drop the cached default provider (e.g. after re-pointing HOME). */
|
|
27
|
+
export declare function resetCloudCredentialProviderForTests(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Read a valid plugin-plane access token for a Cloud-mode call, PROACTIVELY refreshing under the
|
|
30
|
+
* cross-process lock when the stored token is within the expiry skew. Returns `undefined` when the
|
|
31
|
+
* machine is effectively not signed in — no credential, a dead family, an unreadable store, or a
|
|
32
|
+
* lock that stayed contended — so callers surface their actionable "not logged in" error instead
|
|
33
|
+
* of issuing a silent unauthenticated request (defect E / D11). The precise reason is logged via
|
|
34
|
+
* `verbose()` (never token bytes).
|
|
35
|
+
*/
|
|
36
|
+
export declare function readCloudAccessToken(options?: CloudCredentialProviderOptions): Promise<string | undefined>;
|
|
37
|
+
/**
|
|
38
|
+
* REACTIVELY refresh the plugin-plane family now — the hub answered 401 while the local expiry
|
|
39
|
+
* still looked fine (revocation, clock skew). Runs the same locked critical section as the
|
|
40
|
+
* proactive path. Returns the fresh access token, or `undefined` when the family is dead /
|
|
41
|
+
* signed out (the caller falls back to its "not logged in" error).
|
|
42
|
+
*/
|
|
43
|
+
export declare function refreshCloudAccessToken(options?: CloudCredentialProviderOptions): Promise<string | undefined>;
|