unity-mcp-cli 0.70.0 → 0.72.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/CHANGELOG.md +31 -0
- package/README.md +14 -1
- package/dist/commands/open.d.ts +13 -0
- package/dist/commands/open.js +55 -0
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/run-system-tool.d.ts +1 -2
- package/dist/commands/run-system-tool.js +11 -130
- package/dist/commands/run-system-tool.js.map +1 -1
- package/dist/commands/run-tool-builder.d.ts +25 -0
- package/dist/commands/run-tool-builder.js +125 -0
- package/dist/commands/run-tool-builder.js.map +1 -0
- package/dist/commands/run-tool.d.ts +1 -2
- package/dist/commands/run-tool.js +11 -130
- package/dist/commands/run-tool.js.map +1 -1
- package/dist/lib/open.d.ts +48 -1
- package/dist/lib/open.js +158 -0
- package/dist/lib/open.js.map +1 -1
- package/dist/lib/run-tool.d.ts +15 -0
- package/dist/lib/run-tool.js +228 -0
- package/dist/lib/run-tool.js.map +1 -0
- package/dist/lib/types.d.ts +158 -2
- package/dist/lib.d.ts +2 -1
- package/dist/lib.js +1 -0
- package/dist/lib.js.map +1 -1
- package/dist/utils/launch-error-dismiss.d.ts +159 -0
- package/dist/utils/launch-error-dismiss.js +440 -0
- package/dist/utils/launch-error-dismiss.js.map +1 -0
- package/dist/utils/unity-editor.js +33 -6
- package/dist/utils/unity-editor.js.map +1 -1
- package/dist/utils/unity-hub.js +20 -4
- package/dist/utils/unity-hub.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// Library-safe `runTool` / `runSystemTool` implementations.
|
|
2
|
+
//
|
|
3
|
+
// Constraints (same contract as the rest of `lib/*.ts`):
|
|
4
|
+
// - No commander, no spinners, no process.exit, no console output.
|
|
5
|
+
// - Errors are returned in `{ kind: 'failure', success: false, ... }`,
|
|
6
|
+
// never thrown past the public boundary.
|
|
7
|
+
import { readConfig, resolveConnectionFromConfig } from '../utils/config.js';
|
|
8
|
+
import { generatePortFromDirectory } from '../utils/port.js';
|
|
9
|
+
import { requireProjectPath } from './validation.js';
|
|
10
|
+
const DEFAULT_TIMEOUT_MS = 60000;
|
|
11
|
+
/**
|
|
12
|
+
* Invoke a regular MCP tool over the Unity plugin's HTTP API.
|
|
13
|
+
*
|
|
14
|
+
* URL/token resolution priority: explicit override → project config →
|
|
15
|
+
* deterministic localhost port. POSTs to `/api/tools/{name}`. No
|
|
16
|
+
* console output, no `process.exit`; errors are returned in the
|
|
17
|
+
* `kind: 'failure'` variant.
|
|
18
|
+
*/
|
|
19
|
+
export async function runTool(opts) {
|
|
20
|
+
return invokeTool('/api/tools', opts);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Invoke a system tool (internal tool not exposed to MCP clients) over
|
|
24
|
+
* the Unity plugin's HTTP API. POSTs to `/api/system-tools/{name}`.
|
|
25
|
+
*/
|
|
26
|
+
export async function runSystemTool(opts) {
|
|
27
|
+
return invokeTool('/api/system-tools', opts);
|
|
28
|
+
}
|
|
29
|
+
async function invokeTool(routePrefix, opts) {
|
|
30
|
+
const validationFailure = validateOptions(opts);
|
|
31
|
+
if (validationFailure)
|
|
32
|
+
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
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
48
|
+
const timeoutMs = typeof opts.timeoutMs === 'number' && opts.timeoutMs > 0 ? opts.timeoutMs : DEFAULT_TIMEOUT_MS;
|
|
49
|
+
const controller = new AbortController();
|
|
50
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
51
|
+
const externalAbort = () => controller.abort();
|
|
52
|
+
if (opts.signal) {
|
|
53
|
+
if (opts.signal.aborted)
|
|
54
|
+
controller.abort();
|
|
55
|
+
else
|
|
56
|
+
opts.signal.addEventListener('abort', externalAbort, { once: true });
|
|
57
|
+
}
|
|
58
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
59
|
+
if (token)
|
|
60
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
61
|
+
try {
|
|
62
|
+
const response = await fetchImpl(endpoint, {
|
|
63
|
+
method: 'POST',
|
|
64
|
+
headers,
|
|
65
|
+
body: body.json,
|
|
66
|
+
signal: controller.signal,
|
|
67
|
+
});
|
|
68
|
+
const text = await safeReadText(response);
|
|
69
|
+
const data = parseJsonOrText(text);
|
|
70
|
+
if (!response.ok) {
|
|
71
|
+
return makeFailure({
|
|
72
|
+
endpoint,
|
|
73
|
+
reason: 'http-error',
|
|
74
|
+
httpStatus: response.status,
|
|
75
|
+
data,
|
|
76
|
+
message: response.statusText || `HTTP ${response.status}`,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
const success = {
|
|
80
|
+
kind: 'success',
|
|
81
|
+
success: true,
|
|
82
|
+
endpoint,
|
|
83
|
+
httpStatus: response.status,
|
|
84
|
+
data,
|
|
85
|
+
};
|
|
86
|
+
return success;
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
return classifyFetchError(err, endpoint, timeoutMs);
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
clearTimeout(timer);
|
|
93
|
+
opts.signal?.removeEventListener('abort', externalAbort);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function validateOptions(opts) {
|
|
97
|
+
if (!opts || typeof opts !== 'object') {
|
|
98
|
+
return makeFailure({
|
|
99
|
+
endpoint: '',
|
|
100
|
+
reason: 'invalid-input',
|
|
101
|
+
message: 'options object is required.',
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (typeof opts.toolName !== 'string' || opts.toolName.trim().length === 0) {
|
|
105
|
+
return makeFailure({
|
|
106
|
+
endpoint: '',
|
|
107
|
+
reason: 'invalid-input',
|
|
108
|
+
message: 'toolName is required and must be a non-empty string.',
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
const hasUrl = typeof opts.url === 'string' && opts.url.length > 0;
|
|
112
|
+
const hasProjectPath = typeof opts.unityProjectPath === 'string' && opts.unityProjectPath.trim().length > 0;
|
|
113
|
+
if (!hasUrl && !hasProjectPath) {
|
|
114
|
+
return makeFailure({
|
|
115
|
+
endpoint: '',
|
|
116
|
+
reason: 'invalid-input',
|
|
117
|
+
message: 'Either unityProjectPath or url must be provided.',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
function resolveConnection(opts) {
|
|
123
|
+
if (opts.url) {
|
|
124
|
+
return { kind: 'success', url: opts.url.replace(/\/$/, ''), token: opts.token };
|
|
125
|
+
}
|
|
126
|
+
// `unityProjectPath` is library-only — does NOT require an `Assets/`
|
|
127
|
+
// folder, unlike the CLI's `resolveAndValidateProjectPath`. The
|
|
128
|
+
// deterministic-port fallback works against the path string alone.
|
|
129
|
+
const validated = requireProjectPath(opts.unityProjectPath);
|
|
130
|
+
if (!validated.ok) {
|
|
131
|
+
return makeFailure({
|
|
132
|
+
endpoint: '',
|
|
133
|
+
reason: 'invalid-input',
|
|
134
|
+
message: validated.error.message,
|
|
135
|
+
error: validated.error,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
const projectPath = validated.projectPath;
|
|
139
|
+
const config = readConfig(projectPath);
|
|
140
|
+
const fromConfig = config
|
|
141
|
+
? resolveConnectionFromConfig(config)
|
|
142
|
+
: { url: undefined, token: undefined };
|
|
143
|
+
const url = fromConfig.url
|
|
144
|
+
? fromConfig.url.replace(/\/$/, '')
|
|
145
|
+
: `http://localhost:${generatePortFromDirectory(projectPath)}`;
|
|
146
|
+
return { kind: 'success', url, token: opts.token ?? fromConfig.token };
|
|
147
|
+
}
|
|
148
|
+
function serializeInput(input) {
|
|
149
|
+
if (input === undefined || input === null)
|
|
150
|
+
return { json: '{}' };
|
|
151
|
+
if (typeof input === 'string') {
|
|
152
|
+
// Validate the round-trip so the server never sees malformed bodies.
|
|
153
|
+
try {
|
|
154
|
+
JSON.parse(input);
|
|
155
|
+
return { json: input };
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
return {
|
|
159
|
+
error: new Error(`input string is not valid JSON: ${err instanceof Error ? err.message : String(err)}`),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (typeof input !== 'object') {
|
|
164
|
+
return {
|
|
165
|
+
error: new Error('input must be a plain object, JSON string, undefined, or null.'),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
return { json: JSON.stringify(input) };
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
return {
|
|
173
|
+
error: new Error(`input could not be serialized to JSON: ${err instanceof Error ? err.message : String(err)}`),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async function safeReadText(response) {
|
|
178
|
+
try {
|
|
179
|
+
return await response.text();
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return '';
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function parseJsonOrText(text) {
|
|
186
|
+
if (text.length === 0)
|
|
187
|
+
return undefined;
|
|
188
|
+
try {
|
|
189
|
+
return JSON.parse(text);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
return text;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function getCause(err) {
|
|
196
|
+
if (!(err instanceof Error) || !('cause' in err))
|
|
197
|
+
return undefined;
|
|
198
|
+
return err.cause;
|
|
199
|
+
}
|
|
200
|
+
function classifyFetchError(err, endpoint, timeoutMs) {
|
|
201
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
202
|
+
return makeFailure({
|
|
203
|
+
endpoint,
|
|
204
|
+
reason: 'timeout',
|
|
205
|
+
message: `Tool call timed out after ${timeoutMs}ms.`,
|
|
206
|
+
error: err,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
210
|
+
const causeCode = getCause(err)?.code;
|
|
211
|
+
let reason = 'unknown';
|
|
212
|
+
if (causeCode === 'ECONNREFUSED')
|
|
213
|
+
reason = 'connection-refused';
|
|
214
|
+
else if (causeCode === 'ECONNRESET')
|
|
215
|
+
reason = 'connection-reset';
|
|
216
|
+
else if (causeCode === 'ENOTFOUND' || causeCode === 'EAI_AGAIN')
|
|
217
|
+
reason = 'network-error';
|
|
218
|
+
return makeFailure({
|
|
219
|
+
endpoint,
|
|
220
|
+
reason,
|
|
221
|
+
message: error.message,
|
|
222
|
+
error,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
function makeFailure(fields) {
|
|
226
|
+
return { kind: 'failure', success: false, ...fields };
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=run-tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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
|
@@ -42,6 +42,13 @@ export type ProgressEvent = {
|
|
|
42
42
|
phase: 'editor-launched';
|
|
43
43
|
message: string;
|
|
44
44
|
pid?: number;
|
|
45
|
+
} | {
|
|
46
|
+
phase: 'launch-errors-dismissed';
|
|
47
|
+
message: string;
|
|
48
|
+
/** Button label that was clicked (e.g. `Ignore`). */
|
|
49
|
+
button: string;
|
|
50
|
+
/** Platform on which the dismiss was performed (`win32` | `darwin` | `linux`). */
|
|
51
|
+
platform: string;
|
|
45
52
|
} | {
|
|
46
53
|
phase: 'done';
|
|
47
54
|
message: string;
|
|
@@ -251,11 +258,56 @@ export interface OpenProjectOptions {
|
|
|
251
258
|
* avoid the CLI's stringly-typed `"true"`/`"false"` parse step.
|
|
252
259
|
*/
|
|
253
260
|
startServer?: boolean;
|
|
261
|
+
/**
|
|
262
|
+
* If `true` (the default), poll for the Unity Editor's
|
|
263
|
+
* "compile errors at launch" dialog after the editor process has
|
|
264
|
+
* been spawned and click `Ignore` (or the platform-equivalent
|
|
265
|
+
* button) so the editor finishes initialising. Set to `false` to
|
|
266
|
+
* disable the polling loop entirely — corresponds to the CLI's
|
|
267
|
+
* `--no-auto-dismiss-launch-errors` flag.
|
|
268
|
+
*
|
|
269
|
+
* The polling loop runs concurrently with the existing wait-for-
|
|
270
|
+
* ready logic (which is the authoritative ready signal); when no
|
|
271
|
+
* dialog appears, behaviour is unchanged from the pre-feature
|
|
272
|
+
* baseline (no spurious clicks, no extra delay).
|
|
273
|
+
*/
|
|
274
|
+
autoDismissLaunchErrors?: boolean;
|
|
275
|
+
/**
|
|
276
|
+
* Overall timeout (milliseconds) for the launch-errors dismissal
|
|
277
|
+
* polling loop. The loop ticks every
|
|
278
|
+
* `launchDismissPollIntervalMs` until either the dialog is
|
|
279
|
+
* dismissed, this timeout elapses, or `openProject` returns. Default
|
|
280
|
+
* `30000` (30 s).
|
|
281
|
+
*/
|
|
282
|
+
launchDismissTimeoutMs?: number;
|
|
283
|
+
/**
|
|
284
|
+
* Polling tick interval (milliseconds) for the launch-errors
|
|
285
|
+
* dismissal loop. Default `1500`.
|
|
286
|
+
*/
|
|
287
|
+
launchDismissPollIntervalMs?: number;
|
|
288
|
+
/**
|
|
289
|
+
* Optional abort signal that, when fired, stops the launch-errors
|
|
290
|
+
* dismissal polling loop early. Intended for callers that have an
|
|
291
|
+
* authoritative "Unity is ready" signal in scope (e.g. a parallel
|
|
292
|
+
* `wait-for-ready` poll) so the dismissal loop does not keep
|
|
293
|
+
* ticking after Unity has finished initialising.
|
|
294
|
+
*
|
|
295
|
+
* When omitted, the loop falls back to a grace window after the
|
|
296
|
+
* editor process is spawned: if no dialog has been observed within
|
|
297
|
+
* ~15s of polling, the loop exits early on the assumption that the
|
|
298
|
+
* dialog is not going to appear for this launch. The grace window
|
|
299
|
+
* has to cover Unity's full startup phase (process spawn → Package
|
|
300
|
+
* Manager connect → first compile pass) because the launch-errors
|
|
301
|
+
* dialog (`"Enter Safe Mode?"` on Unity 2020.2+) appears at the end
|
|
302
|
+
* of that phase, not the start of it (issue #737).
|
|
303
|
+
*/
|
|
304
|
+
launchDismissAbortSignal?: AbortSignal;
|
|
254
305
|
/**
|
|
255
306
|
* Optional progress callback — fires for `start`,
|
|
256
307
|
* `detecting-editor-version`, `editors-located`, `editor-resolved`,
|
|
257
|
-
* `connection-details`, `launching-editor`, `editor-launched`,
|
|
258
|
-
* `
|
|
308
|
+
* `connection-details`, `launching-editor`, `editor-launched`,
|
|
309
|
+
* `launch-errors-dismissed` (only when a dialog was actually
|
|
310
|
+
* dismissed), and `done`.
|
|
259
311
|
*/
|
|
260
312
|
onProgress?: ProgressCallback;
|
|
261
313
|
}
|
|
@@ -324,3 +376,107 @@ export interface OpenEnvInputs {
|
|
|
324
376
|
transport?: OpenProjectOptions['transport'];
|
|
325
377
|
startServer?: OpenProjectOptions['startServer'];
|
|
326
378
|
}
|
|
379
|
+
/**
|
|
380
|
+
* Coarse failure category for {@link RunToolFailure}. Mirrors the
|
|
381
|
+
* branches the CLI's `run-tool` command surfaces in its error path so
|
|
382
|
+
* library consumers can render the same diagnostics without re-deriving
|
|
383
|
+
* them from the underlying `Error`.
|
|
384
|
+
*/
|
|
385
|
+
export type RunToolFailureReason = 'invalid-input' | 'connection-refused' | 'connection-reset' | 'network-error' | 'timeout' | 'http-error' | 'unknown';
|
|
386
|
+
/**
|
|
387
|
+
* Options accepted by both {@link runTool} and {@link runSystemTool}.
|
|
388
|
+
*
|
|
389
|
+
* Either `unityProjectPath` (preferred — resolves URL + token from the
|
|
390
|
+
* project's `UserSettings/AI-Game-Developer-Config.json`, falling back
|
|
391
|
+
* to a deterministic localhost port when the file is absent) or `url`
|
|
392
|
+
* (explicit endpoint override) MUST be provided.
|
|
393
|
+
*/
|
|
394
|
+
export interface RunToolOptions {
|
|
395
|
+
/**
|
|
396
|
+
* Tool name to invoke. Forwarded as the `{name}` segment of the
|
|
397
|
+
* route — the function URL-encodes it before issuing the request.
|
|
398
|
+
*/
|
|
399
|
+
toolName: string;
|
|
400
|
+
/**
|
|
401
|
+
* Absolute or relative path to the Unity project. Used to read the
|
|
402
|
+
* project's config (host + token) and, as a last resort, to derive
|
|
403
|
+
* the deterministic localhost port mirroring the C# plugin's hash.
|
|
404
|
+
*/
|
|
405
|
+
unityProjectPath?: string;
|
|
406
|
+
/** Explicit base URL override (no trailing slash required). */
|
|
407
|
+
url?: string;
|
|
408
|
+
/** Bearer token override. */
|
|
409
|
+
token?: string;
|
|
410
|
+
/**
|
|
411
|
+
* Tool arguments, serialized as the JSON request body. When omitted,
|
|
412
|
+
* the body is `{}`. Anything other than `undefined` / `null` /
|
|
413
|
+
* `object` is rejected with a `kind: 'failure'` result.
|
|
414
|
+
*/
|
|
415
|
+
input?: unknown;
|
|
416
|
+
/**
|
|
417
|
+
* Per-request timeout in milliseconds. Defaults to `60000` (matching
|
|
418
|
+
* the CLI command's `--timeout` default). Values <= 0 are treated as
|
|
419
|
+
* the default to keep accidental "0 = disable" mistakes from
|
|
420
|
+
* stalling polling callers.
|
|
421
|
+
*/
|
|
422
|
+
timeoutMs?: number;
|
|
423
|
+
/**
|
|
424
|
+
* Optional abort signal. When fired, the in-flight fetch is
|
|
425
|
+
* cancelled and the result resolves to a `kind: 'failure'` with
|
|
426
|
+
* `reason: 'timeout'`.
|
|
427
|
+
*/
|
|
428
|
+
signal?: AbortSignal;
|
|
429
|
+
/**
|
|
430
|
+
* Optional injection point so tests can swap the `fetch`
|
|
431
|
+
* implementation. Defaults to the global `fetch`.
|
|
432
|
+
*/
|
|
433
|
+
fetchImpl?: typeof fetch;
|
|
434
|
+
}
|
|
435
|
+
/** Successful `runTool` / `runSystemTool` outcome. Narrow with `kind === 'success'`. */
|
|
436
|
+
export interface RunToolSuccess {
|
|
437
|
+
kind: 'success';
|
|
438
|
+
/** Always `true` for the success variant. Wire-compatible alias for `kind === 'success'`. */
|
|
439
|
+
success: true;
|
|
440
|
+
/** Resolved endpoint URL that was hit (post URL/token resolution). */
|
|
441
|
+
endpoint: string;
|
|
442
|
+
/** HTTP status code returned by the Unity plugin. */
|
|
443
|
+
httpStatus: number;
|
|
444
|
+
/**
|
|
445
|
+
* Parsed response body. The Unity plugin returns
|
|
446
|
+
* `{ status: "success", structured?: <tool output>, content?: <text blocks[]> }`
|
|
447
|
+
* — consumers typically read `data.structured` or `data.content`
|
|
448
|
+
* depending on whether the invoked tool returns structured content.
|
|
449
|
+
* Non-JSON responses surface the raw text string.
|
|
450
|
+
*/
|
|
451
|
+
data: unknown;
|
|
452
|
+
}
|
|
453
|
+
/** Failed `runTool` / `runSystemTool` outcome. Narrow with `kind === 'failure'`. */
|
|
454
|
+
export interface RunToolFailure {
|
|
455
|
+
kind: 'failure';
|
|
456
|
+
/** Always `false` for the failure variant. Wire-compatible alias for `kind === 'failure'`. */
|
|
457
|
+
success: false;
|
|
458
|
+
/**
|
|
459
|
+
* Resolved endpoint URL. Empty string when the failure is
|
|
460
|
+
* `reason: 'invalid-input'` and resolution never happened.
|
|
461
|
+
*/
|
|
462
|
+
endpoint: string;
|
|
463
|
+
/** Coarse cause — see {@link RunToolFailureReason}. */
|
|
464
|
+
reason: RunToolFailureReason;
|
|
465
|
+
/** HTTP status code when `reason === 'http-error'`. */
|
|
466
|
+
httpStatus?: number;
|
|
467
|
+
/**
|
|
468
|
+
* Response body for diagnostics on `http-error` (parsed JSON when the
|
|
469
|
+
* server returned JSON, otherwise the raw text). Omitted on transport
|
|
470
|
+
* failures where no response was received.
|
|
471
|
+
*/
|
|
472
|
+
data?: unknown;
|
|
473
|
+
/** Human-readable failure summary; never thrown past the public boundary. */
|
|
474
|
+
message: string;
|
|
475
|
+
/** Captured error, when applicable. */
|
|
476
|
+
error?: Error;
|
|
477
|
+
}
|
|
478
|
+
export type RunToolResult = RunToolSuccess | RunToolFailure;
|
|
479
|
+
export type RunSystemToolOptions = RunToolOptions;
|
|
480
|
+
export type RunSystemToolResult = RunToolResult;
|
|
481
|
+
export type RunSystemToolSuccess = RunToolSuccess;
|
|
482
|
+
export type RunSystemToolFailure = RunToolFailure;
|
package/dist/lib.d.ts
CHANGED
|
@@ -3,4 +3,5 @@ export { removePlugin } from './lib/remove-plugin.js';
|
|
|
3
3
|
export { configure } from './lib/configure.js';
|
|
4
4
|
export { setupMcp, listAgentIds } from './lib/setup-mcp.js';
|
|
5
5
|
export { openProject } from './lib/open.js';
|
|
6
|
-
export
|
|
6
|
+
export { runTool, runSystemTool } from './lib/run-tool.js';
|
|
7
|
+
export type { ProgressEvent, ProgressCallback, ResultKind, InstallPluginOptions, InstallResult, InstallSuccess, InstallFailure, RemovePluginOptions, RemoveResult, RemoveSuccess, RemoveFailure, ConfigureOptions, ConfigureResult, ConfigureSuccess, ConfigureFailure, ConfigureSnapshot, FeatureAction, McpFeatureSnapshot, SetupMcpOptions, SetupMcpResult, SetupMcpSuccess, SetupMcpFailure, McpTransport, OpenProjectOptions, OpenProjectResult, OpenProjectSuccess, OpenProjectFailure, OpenProjectAuthOption, OpenProjectTransport, RunToolOptions, RunToolResult, RunToolSuccess, RunToolFailure, RunToolFailureReason, RunSystemToolOptions, RunSystemToolResult, RunSystemToolSuccess, RunSystemToolFailure, } from './lib/types.js';
|
package/dist/lib.js
CHANGED
|
@@ -20,4 +20,5 @@ export { removePlugin } from './lib/remove-plugin.js';
|
|
|
20
20
|
export { configure } from './lib/configure.js';
|
|
21
21
|
export { setupMcp, listAgentIds } from './lib/setup-mcp.js';
|
|
22
22
|
export { openProject } from './lib/open.js';
|
|
23
|
+
export { runTool, runSystemTool } from './lib/run-tool.js';
|
|
23
24
|
//# 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"}
|
|
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,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supported `process.platform` values for the launch-errors dialog
|
|
3
|
+
* dismiss helper. Narrowed alias of NodeJS.Platform — keeps the
|
|
4
|
+
* platform-dispatch table exhaustive in tests without forcing callers
|
|
5
|
+
* to import a Node-internal type.
|
|
6
|
+
*/
|
|
7
|
+
export type DismissPlatform = 'win32' | 'darwin' | 'linux';
|
|
8
|
+
/**
|
|
9
|
+
* Outcome of a single dismiss attempt against the running OS desktop.
|
|
10
|
+
*
|
|
11
|
+
* `dismissed`: the dialog was found AND a click was dispatched
|
|
12
|
+
* successfully. The polling loop should stop and return.
|
|
13
|
+
*
|
|
14
|
+
* `not-found`: no matching dialog was visible on this poll tick. The
|
|
15
|
+
* polling loop should continue ticking until either the overall
|
|
16
|
+
* timeout elapses or Unity reports ready (the existing wait-for-ready
|
|
17
|
+
* logic, which runs in parallel, is the authoritative ready signal).
|
|
18
|
+
*
|
|
19
|
+
* `error`: an unexpected platform error happened (a required tool was
|
|
20
|
+
* missing, a syscall failed). The polling loop logs the error once
|
|
21
|
+
* and continues with `not-found` semantics — the dialog may simply
|
|
22
|
+
* not be open yet, and a single transient error must not abort the
|
|
23
|
+
* whole launch flow.
|
|
24
|
+
*/
|
|
25
|
+
export type DismissOutcome = {
|
|
26
|
+
kind: 'dismissed';
|
|
27
|
+
button: string;
|
|
28
|
+
} | {
|
|
29
|
+
kind: 'not-found';
|
|
30
|
+
} | {
|
|
31
|
+
kind: 'error';
|
|
32
|
+
message: string;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Window-title fragments matched against the Unity launch-errors
|
|
36
|
+
* dialog. Both legacy and current strings are listed so the matcher
|
|
37
|
+
* stays resilient across Unity versions. The match is case-insensitive
|
|
38
|
+
* and substring-based — Unity's actual title varies by version but
|
|
39
|
+
* always contains one of these.
|
|
40
|
+
*
|
|
41
|
+
* Exposed so tests can assert the matcher knows about both spellings
|
|
42
|
+
* without grepping the implementation.
|
|
43
|
+
*/
|
|
44
|
+
export declare const LAUNCH_ERROR_DIALOG_TITLE_FRAGMENTS: readonly string[];
|
|
45
|
+
/** The button label this helper presses to dismiss the dialog. */
|
|
46
|
+
export declare const DISMISS_BUTTON_LABEL = "Ignore";
|
|
47
|
+
/**
|
|
48
|
+
* Producer-side prefixes for error messages that callers treat as
|
|
49
|
+
* permanent (the polling loop bails out instead of ticking again).
|
|
50
|
+
*
|
|
51
|
+
* Exported so the bailout matcher in `lib/open.ts` and the
|
|
52
|
+
* error-construction sites below reference the SAME literal — a
|
|
53
|
+
* future re-word lands in both places at once.
|
|
54
|
+
*
|
|
55
|
+
* The matcher in `lib/open.ts` uses `String.includes`, so each
|
|
56
|
+
* constant just needs to be a stable substring of the full message.
|
|
57
|
+
*/
|
|
58
|
+
export declare const LINUX_XDOTOOL_MISSING_PREFIX = "xdotool not found on PATH";
|
|
59
|
+
export declare const UNSUPPORTED_PLATFORM_PREFIX = "Unsupported platform for launch-errors auto-dismiss";
|
|
60
|
+
/**
|
|
61
|
+
* Try once to find and dismiss the Unity launch-errors dialog on the
|
|
62
|
+
* current OS desktop. Pure-ish — performs a single OS call and
|
|
63
|
+
* returns; never blocks past the underlying syscall's own timeout.
|
|
64
|
+
*
|
|
65
|
+
* Library-safe: never throws (errors are returned in the
|
|
66
|
+
* `DismissOutcome` union), never writes to stdout/stderr, never
|
|
67
|
+
* mutates global state.
|
|
68
|
+
*
|
|
69
|
+
* The helper is platform-dispatched:
|
|
70
|
+
* - **Windows**: Win32 (`FindWindowW` / `EnumWindows` /
|
|
71
|
+
* `EnumChildWindows` / `GetWindowTextW` / `SendMessageW(BM_CLICK)`)
|
|
72
|
+
* driven from PowerShell so we do not pull in a native node-gyp
|
|
73
|
+
* dependency. UI Automation is the documented fallback if title
|
|
74
|
+
* matching breaks on a future Unity release.
|
|
75
|
+
* - **macOS**: AppleScript via `osascript` (the leaner
|
|
76
|
+
* AX-C-API-direct path is a documented follow-up). Requires the
|
|
77
|
+
* user to have granted Accessibility permission to the terminal /
|
|
78
|
+
* `unity-mcp-cli` binary once.
|
|
79
|
+
* - **Linux/X11**: `xdotool` (documented as a Linux platform
|
|
80
|
+
* dependency; `wmctrl` is acceptable as an alternative window
|
|
81
|
+
* enumerator). Wayland is deferred — call out explicitly in the
|
|
82
|
+
* error message so the user does not waste time debugging.
|
|
83
|
+
*/
|
|
84
|
+
export declare function tryDismissLaunchErrorsDialog(platform?: DismissPlatform): Promise<DismissOutcome>;
|
|
85
|
+
/**
|
|
86
|
+
* The PowerShell payload that probes for the Unity launch-errors
|
|
87
|
+
* dialog and clicks `Ignore` if found. Exported as a string (not a
|
|
88
|
+
* function) so tests can assert the script shape without launching
|
|
89
|
+
* PowerShell.
|
|
90
|
+
*
|
|
91
|
+
* Strategy:
|
|
92
|
+
* 1. P/Invoke `EnumWindows` via Add-Type to enumerate every visible
|
|
93
|
+
* top-level window owned by `Unity.exe`.
|
|
94
|
+
* 2. Filter by title fragment (case-insensitive substring).
|
|
95
|
+
* 3. Walk child windows with `EnumChildWindows`, looking for a
|
|
96
|
+
* Button whose text equals `Ignore`.
|
|
97
|
+
* 4. Send `BM_CLICK` (0x00F5) to the matched button. `BM_CLICK` is
|
|
98
|
+
* preferred over a synthesised mouse event — it works even if
|
|
99
|
+
* the user is mid-click in another app, and it does not steal
|
|
100
|
+
* focus.
|
|
101
|
+
*
|
|
102
|
+
* The script writes a single-token result to stdout:
|
|
103
|
+
* - `dismissed:<button>` on success
|
|
104
|
+
* - `not-found` when no dialog was matched
|
|
105
|
+
* - `error:<message>` on an unexpected exception
|
|
106
|
+
*/
|
|
107
|
+
export declare const WINDOWS_DISMISS_PS_SCRIPT: string;
|
|
108
|
+
/**
|
|
109
|
+
* The AppleScript snippet used for the macOS dismiss path. Exposed as
|
|
110
|
+
* a string for testability.
|
|
111
|
+
*
|
|
112
|
+
* Strategy: iterate every window of the Unity application process and
|
|
113
|
+
* click the first button titled `Ignore`. If the Unity process is not
|
|
114
|
+
* running OR no matching button exists, the script reports
|
|
115
|
+
* `not-found`. Any AppleScript exception (e.g. Accessibility
|
|
116
|
+
* permission not granted) is reported as `error:<message>` so the
|
|
117
|
+
* caller can surface it once and continue polling.
|
|
118
|
+
*
|
|
119
|
+
* Requires the Terminal / `unity-mcp-cli` binary to have been granted
|
|
120
|
+
* Accessibility permission in System Settings → Privacy & Security →
|
|
121
|
+
* Accessibility. Documented in the README.
|
|
122
|
+
*/
|
|
123
|
+
export declare const MACOS_DISMISS_APPLESCRIPT = "\non run\n try\n tell application \"System Events\"\n if not (exists process \"Unity\") then\n return \"not-found\"\n end if\n tell process \"Unity\"\n repeat with w in windows\n try\n if exists (button \"Ignore\" of w) then\n click button \"Ignore\" of w\n return \"dismissed:Ignore\"\n end if\n end try\n end repeat\n end tell\n end tell\n return \"not-found\"\n on error errMsg\n return \"error:\" & errMsg\n end try\nend run\n";
|
|
124
|
+
/**
|
|
125
|
+
* Reset the cached `xdotool` presence flag. Test-only — production
|
|
126
|
+
* code never needs to call this. Exposed so tests can simulate "the
|
|
127
|
+
* tool was installed mid-process" without affecting other tests.
|
|
128
|
+
*/
|
|
129
|
+
export declare function _resetXdotoolPresenceForTests(): void;
|
|
130
|
+
/**
|
|
131
|
+
* Escape a literal string for safe use in `xdotool search --name`.
|
|
132
|
+
* `xdotool search --name` interprets its argument as a regex; without
|
|
133
|
+
* escaping, a future fragment containing metacharacters (e.g.
|
|
134
|
+
* `(Hold On)` or `Compiler Errors v2.0+`) would silently change the
|
|
135
|
+
* match semantics. The current fragments are regex-safe but this
|
|
136
|
+
* helper is defensive and zero-runtime-cost.
|
|
137
|
+
*
|
|
138
|
+
* Exposed for tests so the regex-safety contract is locked down.
|
|
139
|
+
*/
|
|
140
|
+
export declare function regexEscapeForXdotool(s: string): string;
|
|
141
|
+
/**
|
|
142
|
+
* Parse the single-token contract every platform-specific dispatcher
|
|
143
|
+
* writes to stdout. Exposed for tests so we can exhaustively cover
|
|
144
|
+
* the parser without invoking PowerShell / osascript / xdotool.
|
|
145
|
+
*
|
|
146
|
+
* Inspects the LAST non-empty line of stdout, not the whole buffer:
|
|
147
|
+
* a stray PowerShell warning, `osascript` deprecation notice, or
|
|
148
|
+
* `xdotool` chatter printed before the contract token must not
|
|
149
|
+
* misclassify the result as `not-found`.
|
|
150
|
+
*
|
|
151
|
+
* Contract:
|
|
152
|
+
* - `dismissed:<button>` → `{ kind: 'dismissed', button }`
|
|
153
|
+
* - `not-found` → `{ kind: 'not-found' }`
|
|
154
|
+
* - `error:<message>` → `{ kind: 'error', message }`
|
|
155
|
+
* - any other / empty → `{ kind: 'not-found' }` (defensive — a
|
|
156
|
+
* transient parse miss is treated as "not yet visible" rather
|
|
157
|
+
* than aborting the polling loop)
|
|
158
|
+
*/
|
|
159
|
+
export declare function parseDismissOutput(stdout: string): DismissOutcome;
|