unity-open-mcp 1.1.0 → 1.3.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 +33 -2
- package/dist/agent-identity.d.ts +12 -0
- package/dist/agent-identity.js +2 -0
- package/dist/agent-identity.js.map +1 -1
- package/dist/batch-spawn.d.ts +39 -0
- package/dist/batch-spawn.js +287 -69
- package/dist/batch-spawn.js.map +1 -1
- package/dist/capabilities/build-capabilities.js +2 -0
- package/dist/capabilities/build-capabilities.js.map +1 -1
- package/dist/capabilities/discovery.d.ts +51 -0
- package/dist/capabilities/discovery.js +87 -0
- package/dist/capabilities/discovery.js.map +1 -0
- package/dist/capabilities/lifecycle.d.ts +6 -0
- package/dist/capabilities/lifecycle.js +17 -1
- package/dist/capabilities/lifecycle.js.map +1 -1
- package/dist/capabilities/tool-groups.js +1 -0
- package/dist/capabilities/tool-groups.js.map +1 -1
- package/dist/child-supervision.d.ts +6 -0
- package/dist/child-supervision.js +12 -0
- package/dist/child-supervision.js.map +1 -1
- package/dist/cli/args.d.ts +24 -2
- package/dist/cli/args.js +97 -2
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/cli.js +42 -3
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/help-text.d.ts +1 -0
- package/dist/cli/help-text.js +71 -3
- package/dist/cli/help-text.js.map +1 -1
- package/dist/cli/json-guards.d.ts +2 -0
- package/dist/cli/json-guards.js +5 -0
- package/dist/cli/json-guards.js.map +1 -0
- package/dist/cli/setup-command.d.ts +88 -0
- package/dist/cli/setup-command.js +444 -0
- package/dist/cli/setup-command.js.map +1 -0
- package/dist/cli/update-command.d.ts +30 -0
- package/dist/cli/update-command.js +271 -0
- package/dist/cli/update-command.js.map +1 -0
- package/dist/compile-verify.d.ts +3 -0
- package/dist/compile-verify.js +4 -0
- package/dist/compile-verify.js.map +1 -1
- package/dist/constants.d.ts +10 -2
- package/dist/constants.js +10 -2
- package/dist/constants.js.map +1 -1
- package/dist/dialog-dismiss.d.ts +108 -12
- package/dist/dialog-dismiss.js +294 -109
- package/dist/dialog-dismiss.js.map +1 -1
- package/dist/dialog-policy.d.ts +55 -9
- package/dist/dialog-policy.js +85 -15
- package/dist/dialog-policy.js.map +1 -1
- package/dist/editor-search.d.ts +2 -0
- package/dist/editor-search.js +8 -0
- package/dist/editor-search.js.map +1 -0
- package/dist/gate-error.d.ts +3 -0
- package/dist/gate-error.js.map +1 -1
- package/dist/index.js +55 -1
- package/dist/index.js.map +1 -1
- package/dist/instance-discovery.d.ts +16 -0
- package/dist/instance-discovery.js +45 -0
- package/dist/instance-discovery.js.map +1 -1
- package/dist/jobs/adapters.d.ts +15 -0
- package/dist/jobs/adapters.js +147 -0
- package/dist/jobs/adapters.js.map +1 -0
- package/dist/jobs/handler.d.ts +3 -0
- package/dist/jobs/handler.js +29 -0
- package/dist/jobs/handler.js.map +1 -0
- package/dist/jobs/job-manager.d.ts +123 -0
- package/dist/jobs/job-manager.js +290 -0
- package/dist/jobs/job-manager.js.map +1 -0
- package/dist/live-client.d.ts +50 -2
- package/dist/live-client.js +221 -26
- package/dist/live-client.js.map +1 -1
- package/dist/local-tools.d.ts +17 -0
- package/dist/local-tools.js +47 -0
- package/dist/local-tools.js.map +1 -0
- package/dist/process-diagnostics.d.ts +47 -20
- package/dist/process-diagnostics.js +30 -15
- package/dist/process-diagnostics.js.map +1 -1
- package/dist/project-path.d.ts +86 -0
- package/dist/project-path.js +159 -0
- package/dist/project-path.js.map +1 -0
- package/dist/release-lookup.d.ts +32 -0
- package/dist/release-lookup.js +147 -0
- package/dist/release-lookup.js.map +1 -0
- package/dist/routers.d.ts +17 -3
- package/dist/routers.js +28 -8
- package/dist/routers.js.map +1 -1
- package/dist/running-unity.d.ts +21 -0
- package/dist/running-unity.js +50 -0
- package/dist/running-unity.js.map +1 -1
- package/dist/schema-defaults.d.ts +4 -3
- package/dist/schema-defaults.js +20 -6
- package/dist/schema-defaults.js.map +1 -1
- package/dist/server-instructions.js +7 -1
- package/dist/server-instructions.js.map +1 -1
- package/dist/server.d.ts +10 -3
- package/dist/server.js +24 -25
- package/dist/server.js.map +1 -1
- package/dist/setup/portable-config.d.ts +60 -0
- package/dist/setup/portable-config.js +249 -0
- package/dist/setup/portable-config.js.map +1 -0
- package/dist/skill/SKILL.md +68 -0
- package/dist/skill/copy-references.d.ts +2 -0
- package/dist/skill/copy-references.js +16 -0
- package/dist/skill/copy-references.js.map +1 -0
- package/dist/skill/generate-skill.js +5 -3
- package/dist/skill/generate-skill.js.map +1 -1
- package/dist/skill/references/batch-and-gates.md +142 -0
- package/dist/skill/references/compile-and-safe-mode.md +163 -0
- package/dist/skill/references/discovery-and-groups.md +30 -0
- package/dist/skill/references/routing-and-lifecycle.md +62 -0
- package/dist/skill/references/senses-and-tests.md +41 -0
- package/dist/skill/references/yaml-and-offline-work.md +33 -0
- package/dist/templates/mcp-wrapper.sh +35 -0
- package/dist/tool-contract.d.ts +8 -0
- package/dist/tool-contract.js +253 -0
- package/dist/tool-contract.js.map +1 -0
- package/dist/tool-router.d.ts +62 -7
- package/dist/tool-router.js +535 -61
- package/dist/tool-router.js.map +1 -1
- package/dist/tool-session-state.d.ts +6 -0
- package/dist/tool-session-state.js +14 -0
- package/dist/tool-session-state.js.map +1 -1
- package/dist/tools/agent-capabilities.js +9 -0
- package/dist/tools/agent-capabilities.js.map +1 -1
- package/dist/tools/batch-execute.js +17 -14
- package/dist/tools/batch-execute.js.map +1 -1
- package/dist/tools/bridge-status.js +4 -5
- package/dist/tools/bridge-status.js.map +1 -1
- package/dist/tools/compile-check.js +6 -4
- package/dist/tools/compile-check.js.map +1 -1
- package/dist/tools/component-get.js +2 -2
- package/dist/tools/component-get.js.map +1 -1
- package/dist/tools/component-modify.js +4 -4
- package/dist/tools/component-modify.js.map +1 -1
- package/dist/tools/execute-csharp.js +8 -4
- package/dist/tools/execute-csharp.js.map +1 -1
- package/dist/tools/gameobject-modify.js +2 -1
- package/dist/tools/gameobject-modify.js.map +1 -1
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +10 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/inputsim-key.js +12 -14
- package/dist/tools/inputsim-key.js.map +1 -1
- package/dist/tools/inputsim-pointer.js +3 -3
- package/dist/tools/inputsim-pointer.js.map +1 -1
- package/dist/tools/inputsim-step.js +7 -8
- package/dist/tools/inputsim-step.js.map +1 -1
- package/dist/tools/inputsim-touch.js +9 -10
- package/dist/tools/inputsim-touch.js.map +1 -1
- package/dist/tools/jobs.d.ts +40 -0
- package/dist/tools/jobs.js +18 -0
- package/dist/tools/jobs.js.map +1 -0
- package/dist/tools/manage-tools.js +10 -5
- package/dist/tools/manage-tools.js.map +1 -1
- package/dist/tools/project-commands.d.ts +40 -0
- package/dist/tools/project-commands.js +23 -0
- package/dist/tools/project-commands.js.map +1 -0
- package/dist/tools/read-compile-errors.js +14 -93
- package/dist/tools/read-compile-errors.js.map +1 -1
- package/dist/tools/resource-pressure.js +27 -17
- package/dist/tools/resource-pressure.js.map +1 -1
- package/dist/tools/scan-paths.js +4 -4
- package/dist/tools/scan-paths.js.map +1 -1
- package/dist/tools/schema-fragments.d.ts +15 -3
- package/dist/tools/schema-fragments.js +23 -13
- package/dist/tools/schema-fragments.js.map +1 -1
- package/dist/tools/upgrade.d.ts +40 -0
- package/dist/tools/upgrade.js +55 -0
- package/dist/tools/upgrade.js.map +1 -0
- package/dist/unity-install-discovery.d.ts +24 -0
- package/dist/unity-install-discovery.js +113 -4
- package/dist/unity-install-discovery.js.map +1 -1
- package/package.json +4 -3
- package/templates/mcp-wrapper.sh +35 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// Portable Unity project-path resolution.
|
|
2
|
+
//
|
|
3
|
+
// One resolver shared by the stdio server bootstrap (`index.ts`), the thin
|
|
4
|
+
// CLI (`routers.ts` → `resolveEnv`), and the `setup` config writers. It turns
|
|
5
|
+
// whatever the caller has — an env var, a `--project` flag, or nothing but the
|
|
6
|
+
// spawn cwd — into ONE absolute Unity project root, so committed MCP client
|
|
7
|
+
// config never has to carry a per-machine path.
|
|
8
|
+
//
|
|
9
|
+
// The module is deliberately light (only `node:fs` + `node:path`): `index.ts`
|
|
10
|
+
// imports it statically on the pre-`getEnv()` path, which must not pull the
|
|
11
|
+
// heavy ALL_TOOLS graph.
|
|
12
|
+
import { existsSync, statSync } from "node:fs";
|
|
13
|
+
import * as nodePath from "node:path";
|
|
14
|
+
/** Directories that must exist directly under a Unity project root. */
|
|
15
|
+
export const UNITY_ROOT_MARKERS = ["Assets", "Packages", "ProjectSettings"];
|
|
16
|
+
export class ProjectPathError extends Error {
|
|
17
|
+
code;
|
|
18
|
+
constructor(code, message) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.code = code;
|
|
21
|
+
this.name = "ProjectPathError";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the Unity project root. First match wins:
|
|
26
|
+
*
|
|
27
|
+
* 1. `flagPath` (CLI `--project`) — an explicit argument beats ambient state.
|
|
28
|
+
* 2. `envPath` (`UNITY_PROJECT_PATH`) — keeps every existing client config
|
|
29
|
+
* working, and wins over `--project-from-cwd` so a machine-local env
|
|
30
|
+
* override can still redirect a committed config.
|
|
31
|
+
* 3. `projectFromCwd` (+ optional `unitySubpath`) — the portable path.
|
|
32
|
+
* 4. nothing → `ProjectPathError` with an actionable message.
|
|
33
|
+
*
|
|
34
|
+
* Relative `flagPath` / `envPath` values resolve against `cwd`, so
|
|
35
|
+
* `--project Client` works from a monorepo root. The result is always
|
|
36
|
+
* absolute: bridge port hashing and instance locks are keyed on it.
|
|
37
|
+
*
|
|
38
|
+
* Does NOT touch the filesystem — validation is `validateUnityProjectRoot`,
|
|
39
|
+
* which callers apply according to how strict they need to be.
|
|
40
|
+
*/
|
|
41
|
+
export function resolveProjectPath(options = {}) {
|
|
42
|
+
const p = options.pathApi ?? nodePath;
|
|
43
|
+
const cwd = options.cwd ?? process.cwd();
|
|
44
|
+
const flag = trimmed(options.flagPath);
|
|
45
|
+
if (flag)
|
|
46
|
+
return { absolute: absolutize(p, cwd, flag), source: "flag" };
|
|
47
|
+
const env = trimmed(options.envPath);
|
|
48
|
+
if (env)
|
|
49
|
+
return { absolute: absolutize(p, cwd, env), source: "env" };
|
|
50
|
+
if (options.projectFromCwd) {
|
|
51
|
+
const subpath = trimmed(options.unitySubpath);
|
|
52
|
+
if (subpath) {
|
|
53
|
+
if (p.isAbsolute(subpath)) {
|
|
54
|
+
throw new ProjectPathError("subpath_not_relative", `--unity-subpath must be relative to the workspace (received '${subpath}').`);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
absolute: absolutize(p, cwd, subpath),
|
|
58
|
+
source: "cwd+subpath",
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return { absolute: absolutize(p, cwd, "."), source: "cwd" };
|
|
62
|
+
}
|
|
63
|
+
if (trimmed(options.unitySubpath)) {
|
|
64
|
+
throw new ProjectPathError("subpath_without_cwd", "--unity-subpath requires --project-from-cwd (or an explicit project path).");
|
|
65
|
+
}
|
|
66
|
+
throw new ProjectPathError("missing_project_path", missingProjectPathMessage());
|
|
67
|
+
}
|
|
68
|
+
/** Shared wording so the server, the CLI, and setup all suggest the same fix. */
|
|
69
|
+
export function missingProjectPathMessage() {
|
|
70
|
+
return [
|
|
71
|
+
"No Unity project path. Use one of:",
|
|
72
|
+
" --project-from-cwd run from the Unity project root",
|
|
73
|
+
" --project-from-cwd --unity-subpath Client monorepo: Unity project in a subfolder",
|
|
74
|
+
" --project <path> explicit path (absolute or relative)",
|
|
75
|
+
" UNITY_PROJECT_PATH=<path> environment variable",
|
|
76
|
+
].join("\n");
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Check that `absolute` looks like a Unity project root (`Assets/`,
|
|
80
|
+
* `Packages/`, `ProjectSettings/`). Never throws — callers decide whether a
|
|
81
|
+
* miss is fatal.
|
|
82
|
+
*/
|
|
83
|
+
export function validateUnityProjectRoot(absolute) {
|
|
84
|
+
const missing = UNITY_ROOT_MARKERS.filter((marker) => {
|
|
85
|
+
const candidate = nodePath.join(absolute, marker);
|
|
86
|
+
try {
|
|
87
|
+
return !existsSync(candidate) || !statSync(candidate).isDirectory();
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
return { valid: missing.length === 0, missing };
|
|
94
|
+
}
|
|
95
|
+
/** One-line explanation of a failed {@link validateUnityProjectRoot}. */
|
|
96
|
+
export function notUnityProjectMessage(resolved, validation) {
|
|
97
|
+
return (`${resolved.absolute} is not a Unity project root (from ${resolved.source}): ` +
|
|
98
|
+
`missing ${validation.missing.map((m) => `${m}/`).join(", ")}.`);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Pre-parse the portable project-path flags out of the stdio server's argv.
|
|
102
|
+
* Unknown tokens are ignored on purpose: MCP clients pass through arbitrary
|
|
103
|
+
* extra arguments, and the server has always tolerated them.
|
|
104
|
+
*/
|
|
105
|
+
export function parseServerFlags(argv) {
|
|
106
|
+
const flags = {
|
|
107
|
+
projectFromCwd: false,
|
|
108
|
+
unitySubpath: undefined,
|
|
109
|
+
error: undefined,
|
|
110
|
+
};
|
|
111
|
+
for (let i = 0; i < argv.length; i++) {
|
|
112
|
+
const tok = argv[i];
|
|
113
|
+
if (tok === "--project-from-cwd") {
|
|
114
|
+
flags.projectFromCwd = true;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (tok === "--unity-subpath") {
|
|
118
|
+
const value = argv[i + 1];
|
|
119
|
+
if (!value || value.startsWith("-")) {
|
|
120
|
+
flags.error = "--unity-subpath requires a relative path (for example: Client).";
|
|
121
|
+
return flags;
|
|
122
|
+
}
|
|
123
|
+
flags.unitySubpath = value;
|
|
124
|
+
i++;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const inline = matchInline(tok, "--unity-subpath");
|
|
128
|
+
if (inline !== undefined) {
|
|
129
|
+
if (inline.length === 0) {
|
|
130
|
+
flags.error = "--unity-subpath requires a relative path (for example: Client).";
|
|
131
|
+
return flags;
|
|
132
|
+
}
|
|
133
|
+
flags.unitySubpath = inline;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return flags;
|
|
138
|
+
}
|
|
139
|
+
function matchInline(tok, flag) {
|
|
140
|
+
const prefix = `${flag}=`;
|
|
141
|
+
return tok.startsWith(prefix) ? tok.slice(prefix.length) : undefined;
|
|
142
|
+
}
|
|
143
|
+
function trimmed(value) {
|
|
144
|
+
if (typeof value !== "string")
|
|
145
|
+
return undefined;
|
|
146
|
+
const t = value.trim();
|
|
147
|
+
return t.length > 0 ? t : undefined;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Resolve `input` against `cwd` and normalize. `p.resolve` already returns an
|
|
151
|
+
* absolute path and strips a trailing separator, which matters because the
|
|
152
|
+
* bridge port hash is taken over this exact string.
|
|
153
|
+
*/
|
|
154
|
+
function absolutize(p, cwd, input) {
|
|
155
|
+
return p.isAbsolute(input)
|
|
156
|
+
? p.normalize(p.resolve(input))
|
|
157
|
+
: p.normalize(p.resolve(cwd, input));
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=project-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-path.js","sourceRoot":"","sources":["../src/project-path.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare const PACKAGE_NAME = "unity-open-mcp";
|
|
2
|
+
export type ReleaseSource = "npm" | "github";
|
|
3
|
+
export interface LatestVersion {
|
|
4
|
+
version: string;
|
|
5
|
+
source: ReleaseSource;
|
|
6
|
+
fallbackReason?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface BridgeTagConfirmation {
|
|
9
|
+
confirmed: boolean;
|
|
10
|
+
error?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Latest stable trio version: npm `latest` dist-tag first, GitHub `v*`
|
|
14
|
+
* releases as the fallback. Throws when neither source answers.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveLatestVersion(fetchImpl: typeof globalThis.fetch): Promise<LatestVersion>;
|
|
17
|
+
/**
|
|
18
|
+
* Whether the `bridge-v<version>` release tag exists on GitHub. Never throws:
|
|
19
|
+
* a failed lookup is reported as `confirmed: false` with the reason, because
|
|
20
|
+
* the caller's decision ("do not schedule a UPM re-pin to a tag we cannot
|
|
21
|
+
* prove exists") is the same either way.
|
|
22
|
+
*/
|
|
23
|
+
export declare function confirmBridgeReleaseTag(version: string, fetchImpl: typeof globalThis.fetch): Promise<BridgeTagConfirmation>;
|
|
24
|
+
interface Semver {
|
|
25
|
+
major: number;
|
|
26
|
+
minor: number;
|
|
27
|
+
patch: number;
|
|
28
|
+
prerelease: string[];
|
|
29
|
+
}
|
|
30
|
+
export declare function parseSemver(value: string): Semver | null;
|
|
31
|
+
export declare function compareSemver(a: string, b: string): number | null;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// Published-release lookups shared by the `update` CLI command and the
|
|
2
|
+
// `unity_open_mcp_upgrade` route.
|
|
3
|
+
//
|
|
4
|
+
// Both callers need the same two facts — "what is the latest trio version?"
|
|
5
|
+
// and "does the bridge release tag for version X exist?" — and both must get
|
|
6
|
+
// them WITHOUT going through the Unity Editor: the bridge's upgrade tool runs
|
|
7
|
+
// on the Editor main thread, where a 10 s registry timeout would freeze the
|
|
8
|
+
// Editor and the whole bridge request queue. The lookups therefore live here,
|
|
9
|
+
// in the MCP server process, and the bridge only ever receives a resolved
|
|
10
|
+
// `target_version`.
|
|
11
|
+
//
|
|
12
|
+
// Pure `fetch` + hand-rolled semver; no runtime dependencies.
|
|
13
|
+
import { isRecord } from "./cli/json-guards.js";
|
|
14
|
+
export const PACKAGE_NAME = "unity-open-mcp";
|
|
15
|
+
const NPM_LATEST_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
|
|
16
|
+
const GITHUB_RELEASES_URL = "https://api.github.com/repos/AlexeyPerov/Unity-Open-MCP/releases?per_page=30";
|
|
17
|
+
// matching-refs is a PREFIX query: asking for bridge-v1.2.3 also lists
|
|
18
|
+
// bridge-v1.2.30, so only the exact ref name proves the tag exists. Mirrors
|
|
19
|
+
// LatestVersionCheck.ContainsExactBridgeTag on the bridge.
|
|
20
|
+
const GITHUB_BRIDGE_TAG_URL = "https://api.github.com/repos/AlexeyPerov/Unity-Open-MCP/git/matching-refs/tags/bridge-v";
|
|
21
|
+
const REQUEST_TIMEOUT_MS = 10_000;
|
|
22
|
+
/**
|
|
23
|
+
* Latest stable trio version: npm `latest` dist-tag first, GitHub `v*`
|
|
24
|
+
* releases as the fallback. Throws when neither source answers.
|
|
25
|
+
*/
|
|
26
|
+
export async function resolveLatestVersion(fetchImpl) {
|
|
27
|
+
let npmFailure = "npm registry lookup failed";
|
|
28
|
+
try {
|
|
29
|
+
const body = await fetchJson(fetchImpl, NPM_LATEST_URL);
|
|
30
|
+
const version = isRecord(body) ? body.version : undefined;
|
|
31
|
+
if (typeof version === "string" && parseSemver(version)) {
|
|
32
|
+
return { version, source: "npm" };
|
|
33
|
+
}
|
|
34
|
+
npmFailure = "npm registry returned no valid version";
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
npmFailure = error instanceof Error ? error.message : String(error);
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const body = await fetchJson(fetchImpl, GITHUB_RELEASES_URL);
|
|
41
|
+
if (!Array.isArray(body))
|
|
42
|
+
throw new Error("GitHub returned an invalid release list");
|
|
43
|
+
const versions = body
|
|
44
|
+
.filter(isRecord)
|
|
45
|
+
.filter((release) => release.draft !== true && release.prerelease !== true)
|
|
46
|
+
.map((release) => release.tag_name)
|
|
47
|
+
.filter((tag) => typeof tag === "string" && /^v\d+\.\d+\.\d+$/.test(tag))
|
|
48
|
+
.map((tag) => tag.slice(1))
|
|
49
|
+
.filter((version) => parseSemver(version) !== null)
|
|
50
|
+
.sort((a, b) => compareSemver(b, a) ?? 0);
|
|
51
|
+
if (versions.length === 0)
|
|
52
|
+
throw new Error("GitHub has no stable trio release tag");
|
|
53
|
+
return { version: versions[0], source: "github", fallbackReason: npmFailure };
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
const githubFailure = error instanceof Error ? error.message : String(error);
|
|
57
|
+
throw new Error(`npm: ${npmFailure}; GitHub: ${githubFailure}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Whether the `bridge-v<version>` release tag exists on GitHub. Never throws:
|
|
62
|
+
* a failed lookup is reported as `confirmed: false` with the reason, because
|
|
63
|
+
* the caller's decision ("do not schedule a UPM re-pin to a tag we cannot
|
|
64
|
+
* prove exists") is the same either way.
|
|
65
|
+
*/
|
|
66
|
+
export async function confirmBridgeReleaseTag(version, fetchImpl) {
|
|
67
|
+
if (!/^\d+\.\d+\.\d+$/.test(version)) {
|
|
68
|
+
return { confirmed: false, error: "Target version must be a plain X.Y.Z." };
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const body = await fetchJson(fetchImpl, `${GITHUB_BRIDGE_TAG_URL}${version}`);
|
|
72
|
+
if (!Array.isArray(body)) {
|
|
73
|
+
return { confirmed: false, error: "GitHub returned an invalid ref list." };
|
|
74
|
+
}
|
|
75
|
+
const exact = `refs/tags/bridge-v${version}`;
|
|
76
|
+
return body.some((ref) => isRecord(ref) && ref.ref === exact)
|
|
77
|
+
? { confirmed: true }
|
|
78
|
+
: { confirmed: false, error: `Release tag bridge-v${version} was not found.` };
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
82
|
+
return { confirmed: false, error: `Bridge tag check failed: ${message}` };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
async function fetchJson(fetchImpl, url) {
|
|
86
|
+
const controller = new AbortController();
|
|
87
|
+
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
88
|
+
try {
|
|
89
|
+
const response = await fetchImpl(url, {
|
|
90
|
+
headers: { Accept: "application/json", "User-Agent": "unity-open-mcp-update" },
|
|
91
|
+
signal: controller.signal,
|
|
92
|
+
});
|
|
93
|
+
if (!response.ok) {
|
|
94
|
+
throw new Error(`${new URL(url).hostname} returned HTTP ${response.status}`);
|
|
95
|
+
}
|
|
96
|
+
return await response.json();
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
clearTimeout(timer);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export function parseSemver(value) {
|
|
103
|
+
const match = value.match(/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/);
|
|
104
|
+
if (!match)
|
|
105
|
+
return null;
|
|
106
|
+
return {
|
|
107
|
+
major: Number(match[1]),
|
|
108
|
+
minor: Number(match[2]),
|
|
109
|
+
patch: Number(match[3]),
|
|
110
|
+
prerelease: match[4]?.split(".") ?? [],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
export function compareSemver(a, b) {
|
|
114
|
+
const left = parseSemver(a);
|
|
115
|
+
const right = parseSemver(b);
|
|
116
|
+
if (!left || !right)
|
|
117
|
+
return null;
|
|
118
|
+
for (const key of ["major", "minor", "patch"]) {
|
|
119
|
+
if (left[key] !== right[key])
|
|
120
|
+
return left[key] > right[key] ? 1 : -1;
|
|
121
|
+
}
|
|
122
|
+
if (left.prerelease.length === 0 || right.prerelease.length === 0) {
|
|
123
|
+
if (left.prerelease.length === right.prerelease.length)
|
|
124
|
+
return 0;
|
|
125
|
+
return left.prerelease.length === 0 ? 1 : -1;
|
|
126
|
+
}
|
|
127
|
+
const length = Math.max(left.prerelease.length, right.prerelease.length);
|
|
128
|
+
for (let index = 0; index < length; index++) {
|
|
129
|
+
const l = left.prerelease[index];
|
|
130
|
+
const r = right.prerelease[index];
|
|
131
|
+
if (l === undefined)
|
|
132
|
+
return -1;
|
|
133
|
+
if (r === undefined)
|
|
134
|
+
return 1;
|
|
135
|
+
if (l === r)
|
|
136
|
+
continue;
|
|
137
|
+
const lNumeric = /^\d+$/.test(l);
|
|
138
|
+
const rNumeric = /^\d+$/.test(r);
|
|
139
|
+
if (lNumeric && rNumeric)
|
|
140
|
+
return Number(l) > Number(r) ? 1 : -1;
|
|
141
|
+
if (lNumeric !== rNumeric)
|
|
142
|
+
return lNumeric ? -1 : 1;
|
|
143
|
+
return l > r ? 1 : -1;
|
|
144
|
+
}
|
|
145
|
+
return 0;
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=release-lookup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release-lookup.js","sourceRoot":"","sources":["../src/release-lookup.ts"],"names":[],"mappings":"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"}
|
package/dist/routers.d.ts
CHANGED
|
@@ -5,8 +5,12 @@ import { PingCache } from "./ping-cache.js";
|
|
|
5
5
|
import { ResourceRouter } from "./resource-router.js";
|
|
6
6
|
import { BridgeEventStream } from "./event-stream.js";
|
|
7
7
|
import { ToolSessionState } from "./tool-session-state.js";
|
|
8
|
+
import { type ProjectPathSource } from "./project-path.js";
|
|
8
9
|
export interface ResolvedEnv {
|
|
10
|
+
/** Normalized absolute Unity project root. */
|
|
9
11
|
projectPath: string;
|
|
12
|
+
/** Which input produced {@link projectPath} (flag / env / cwd). */
|
|
13
|
+
projectPathSource: ProjectPathSource;
|
|
10
14
|
port: number;
|
|
11
15
|
authToken: string | undefined;
|
|
12
16
|
/** Parsed UNITY_OPEN_MCP_BRIDGE_PORT (or CLI --port override), else undefined.
|
|
@@ -14,18 +18,28 @@ export interface ResolvedEnv {
|
|
|
14
18
|
* override precedence as construction (env override ⇒ no lock refresh). */
|
|
15
19
|
envPort: number | undefined;
|
|
16
20
|
}
|
|
21
|
+
export interface ResolveEnvOptions {
|
|
22
|
+
/** `--project-from-cwd`: derive the Unity project root from the cwd. */
|
|
23
|
+
projectFromCwd?: boolean;
|
|
24
|
+
/** `--unity-subpath <rel>`: Unity project subfolder under the cwd. */
|
|
25
|
+
unitySubpath?: string;
|
|
26
|
+
}
|
|
17
27
|
/**
|
|
18
28
|
* Resolve the project path / port / auth token from explicit overrides (CLI
|
|
19
29
|
* flags) or the process env (MCP server). Throws when no project path is set —
|
|
20
30
|
* callers print a friendly message and exit non-zero.
|
|
21
31
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
32
|
+
* The project path goes through the shared `resolveProjectPath` resolver, so
|
|
33
|
+
* the CLI accepts exactly what the stdio server accepts: an absolute path, a
|
|
34
|
+
* path relative to the cwd (`--project Client` from a monorepo root), or no
|
|
35
|
+
* path at all with `--project-from-cwd [--unity-subpath Client]`.
|
|
36
|
+
*
|
|
37
|
+
* projectPath: --project > UNITY_PROJECT_PATH > cwd (+ subpath)
|
|
24
38
|
* port: override > UNITY_OPEN_MCP_BRIDGE_PORT > lock file > hash
|
|
25
39
|
* authToken: discovered from the same lock as the port (no token with an
|
|
26
40
|
* explicit port override)
|
|
27
41
|
*/
|
|
28
|
-
export declare function resolveEnv(projectPathOverride?: string, portOverride?: number): ResolvedEnv;
|
|
42
|
+
export declare function resolveEnv(projectPathOverride?: string, portOverride?: number, options?: ResolveEnvOptions): ResolvedEnv;
|
|
29
43
|
export declare class ResolveEnvError extends Error {
|
|
30
44
|
}
|
|
31
45
|
export interface RouterStack {
|
package/dist/routers.js
CHANGED
|
@@ -13,30 +13,50 @@ import { ResourceRouter } from "./resource-router.js";
|
|
|
13
13
|
import { BridgeEventStream } from "./event-stream.js";
|
|
14
14
|
import { resolvePort, resolveAuthToken } from "./instance-discovery.js";
|
|
15
15
|
import { ToolSessionState } from "./tool-session-state.js";
|
|
16
|
+
import { ProjectPathError, resolveProjectPath, } from "./project-path.js";
|
|
16
17
|
import { PORT_ENV_VAR, PROJECT_PATH_ENV_VAR, bridgeBaseUrl, } from "./constants.js";
|
|
17
18
|
/**
|
|
18
19
|
* Resolve the project path / port / auth token from explicit overrides (CLI
|
|
19
20
|
* flags) or the process env (MCP server). Throws when no project path is set —
|
|
20
21
|
* callers print a friendly message and exit non-zero.
|
|
21
22
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
23
|
+
* The project path goes through the shared `resolveProjectPath` resolver, so
|
|
24
|
+
* the CLI accepts exactly what the stdio server accepts: an absolute path, a
|
|
25
|
+
* path relative to the cwd (`--project Client` from a monorepo root), or no
|
|
26
|
+
* path at all with `--project-from-cwd [--unity-subpath Client]`.
|
|
27
|
+
*
|
|
28
|
+
* projectPath: --project > UNITY_PROJECT_PATH > cwd (+ subpath)
|
|
24
29
|
* port: override > UNITY_OPEN_MCP_BRIDGE_PORT > lock file > hash
|
|
25
30
|
* authToken: discovered from the same lock as the port (no token with an
|
|
26
31
|
* explicit port override)
|
|
27
32
|
*/
|
|
28
|
-
export function resolveEnv(projectPathOverride, portOverride) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
export function resolveEnv(projectPathOverride, portOverride, options = {}) {
|
|
34
|
+
let resolvedProject;
|
|
35
|
+
try {
|
|
36
|
+
resolvedProject = resolveProjectPath({
|
|
37
|
+
flagPath: projectPathOverride,
|
|
38
|
+
envPath: process.env[PROJECT_PATH_ENV_VAR],
|
|
39
|
+
cwd: process.cwd(),
|
|
40
|
+
projectFromCwd: options.projectFromCwd,
|
|
41
|
+
unitySubpath: options.unitySubpath,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
throw new ResolveEnvError(err instanceof ProjectPathError ? err.message : String(err));
|
|
33
46
|
}
|
|
47
|
+
const projectPath = resolvedProject.absolute;
|
|
34
48
|
const rawEnvPort = process.env[PORT_ENV_VAR];
|
|
35
49
|
const envPort = rawEnvPort ? parseInt(rawEnvPort, 10) : undefined;
|
|
36
50
|
const effectiveEnvPort = rawEnvPort && Number.isInteger(envPort) ? envPort : undefined;
|
|
37
51
|
const port = resolvePort(projectPath, portOverride ?? effectiveEnvPort);
|
|
38
52
|
const authToken = resolveAuthToken(projectPath, portOverride ?? effectiveEnvPort);
|
|
39
|
-
return {
|
|
53
|
+
return {
|
|
54
|
+
projectPath,
|
|
55
|
+
projectPathSource: resolvedProject.source,
|
|
56
|
+
port,
|
|
57
|
+
authToken,
|
|
58
|
+
envPort: portOverride ?? effectiveEnvPort,
|
|
59
|
+
};
|
|
40
60
|
}
|
|
41
61
|
export class ResolveEnvError extends Error {
|
|
42
62
|
}
|
package/dist/routers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routers.js","sourceRoot":"","sources":["../src/routers.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,EAAE;AACF,yEAAyE;AACzE,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yBAAyB;AAEzB,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,aAAa,GACd,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"routers.js","sourceRoot":"","sources":["../src/routers.ts"],"names":[],"mappings":"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"}
|
package/dist/running-unity.d.ts
CHANGED
|
@@ -6,7 +6,14 @@ export interface RunningUnity {
|
|
|
6
6
|
/** Normalized `-projectPath` argument, or null when it could not be parsed
|
|
7
7
|
* (Unity opened without `-projectPath`, e.g. via the Hub's "Open Editor"). */
|
|
8
8
|
projectPath: string | null;
|
|
9
|
+
/** `true` when the command line carries `-batchmode`: a headless run (a
|
|
10
|
+
* compile_check / verify spawn from this or another MCP server, a CI run),
|
|
11
|
+
* never the interactive Editor a user owns. Optional so hand-built scanner
|
|
12
|
+
* fixtures keep working. */
|
|
13
|
+
batchMode?: boolean;
|
|
9
14
|
}
|
|
15
|
+
/** `true` when the command line runs Unity headless (`-batchmode`, any case). */
|
|
16
|
+
export declare function isBatchModeCommandLine(commandLine: string): boolean;
|
|
10
17
|
/**
|
|
11
18
|
* Pure `-projectPath` argument parser. Port of Hub
|
|
12
19
|
* `running_unity.rs#parse_project_path_arg`. Accepts both the space-separated
|
|
@@ -106,6 +113,10 @@ export declare function setUnityProcessScannerForTest(fake: UnityProcessScanner
|
|
|
106
113
|
* scan simply returns null and the caller falls back to its pre-feature
|
|
107
114
|
* behavior. Documented in tests.
|
|
108
115
|
*
|
|
116
|
+
* Skips headless batch children this server spawned and still supervises
|
|
117
|
+
* (see `child-supervision.ts`): they carry the same `-projectPath` but are
|
|
118
|
+
* tracked by the batch lease, not by Editor-ownership diagnostics.
|
|
119
|
+
*
|
|
109
120
|
* Never throws: any scanner failure (ps missing, PowerShell slow, parse
|
|
110
121
|
* error) returns null. A failed scan must not mask the underlying offline
|
|
111
122
|
* state.
|
|
@@ -115,6 +126,16 @@ export declare function setUnityProcessScannerForTest(fake: UnityProcessScanner
|
|
|
115
126
|
export declare function findUnityForProject(projectPath: string | null | undefined): {
|
|
116
127
|
pid: number;
|
|
117
128
|
} | null;
|
|
129
|
+
/**
|
|
130
|
+
* A headless (`-batchmode`) Unity that ANOTHER process has open on
|
|
131
|
+
* `projectPath`: a compile_check / verify spawn from a second MCP server, or a
|
|
132
|
+
* CI run. This server's own supervised child is excluded (the batch lease
|
|
133
|
+
* accounts for it), and the interactive Editor is `findUnityForProject`'s
|
|
134
|
+
* business. Never throws; null when no such process is found.
|
|
135
|
+
*/
|
|
136
|
+
export declare function findHeadlessUnityForProject(projectPath: string | null | undefined): {
|
|
137
|
+
pid: number;
|
|
138
|
+
} | null;
|
|
118
139
|
/**
|
|
119
140
|
* Read the full command line of a live process by PID. Cross-platform best
|
|
120
141
|
* effort: macOS/Linux via `ps -p <pid> -o command=`, Windows via a PowerShell
|
package/dist/running-unity.js
CHANGED
|
@@ -29,6 +29,11 @@
|
|
|
29
29
|
// two projects).
|
|
30
30
|
import { execFileSync } from "node:child_process";
|
|
31
31
|
import { normalizePath } from "./instance-discovery.js";
|
|
32
|
+
import { isSupervisedBatchChildPid } from "./child-supervision.js";
|
|
33
|
+
/** `true` when the command line runs Unity headless (`-batchmode`, any case). */
|
|
34
|
+
export function isBatchModeCommandLine(commandLine) {
|
|
35
|
+
return /(^|\s)-batchmode(\s|$)/i.test(commandLine);
|
|
36
|
+
}
|
|
32
37
|
/**
|
|
33
38
|
* Pure `-projectPath` argument parser. Port of Hub
|
|
34
39
|
* `running_unity.rs#parse_project_path_arg`. Accepts both the space-separated
|
|
@@ -272,6 +277,7 @@ export function parsePsOutput(stdout) {
|
|
|
272
277
|
out.push({
|
|
273
278
|
pid,
|
|
274
279
|
projectPath: projectPath !== null ? normalizePath(projectPath) : null,
|
|
280
|
+
batchMode: isBatchModeCommandLine(rest),
|
|
275
281
|
});
|
|
276
282
|
}
|
|
277
283
|
return out;
|
|
@@ -305,6 +311,7 @@ export function parsePowerShellLines(stdout) {
|
|
|
305
311
|
out.push({
|
|
306
312
|
pid,
|
|
307
313
|
projectPath: projectPath !== null ? normalizePath(projectPath) : null,
|
|
314
|
+
batchMode: rest.length > 0 && rest !== "null" && isBatchModeCommandLine(rest),
|
|
308
315
|
});
|
|
309
316
|
}
|
|
310
317
|
return out;
|
|
@@ -385,6 +392,10 @@ export function setUnityProcessScannerForTest(fake) {
|
|
|
385
392
|
* scan simply returns null and the caller falls back to its pre-feature
|
|
386
393
|
* behavior. Documented in tests.
|
|
387
394
|
*
|
|
395
|
+
* Skips headless batch children this server spawned and still supervises
|
|
396
|
+
* (see `child-supervision.ts`): they carry the same `-projectPath` but are
|
|
397
|
+
* tracked by the batch lease, not by Editor-ownership diagnostics.
|
|
398
|
+
*
|
|
388
399
|
* Never throws: any scanner failure (ps missing, PowerShell slow, parse
|
|
389
400
|
* error) returns null. A failed scan must not mask the underlying offline
|
|
390
401
|
* state.
|
|
@@ -405,6 +416,45 @@ export function findUnityForProject(projectPath) {
|
|
|
405
416
|
return null;
|
|
406
417
|
}
|
|
407
418
|
for (const proc of found) {
|
|
419
|
+
// Our own headless child is not an Editor the user owns; the batch lease
|
|
420
|
+
// accounts for it (and restart_editor must never pick it).
|
|
421
|
+
if (isSupervisedBatchChildPid(proc.pid))
|
|
422
|
+
continue;
|
|
423
|
+
// Neither is a -batchmode Unity another process started (a second MCP
|
|
424
|
+
// server's compile_check, a CI run): it is never in Safe Mode, must never
|
|
425
|
+
// be killed by restart_editor, and batch-spawn reports it separately
|
|
426
|
+
// (findHeadlessUnityForProject).
|
|
427
|
+
if (proc.batchMode)
|
|
428
|
+
continue;
|
|
429
|
+
if (proc.projectPath !== null && normalizePath(proc.projectPath) === target) {
|
|
430
|
+
return { pid: proc.pid };
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return null;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* A headless (`-batchmode`) Unity that ANOTHER process has open on
|
|
437
|
+
* `projectPath`: a compile_check / verify spawn from a second MCP server, or a
|
|
438
|
+
* CI run. This server's own supervised child is excluded (the batch lease
|
|
439
|
+
* accounts for it), and the interactive Editor is `findUnityForProject`'s
|
|
440
|
+
* business. Never throws; null when no such process is found.
|
|
441
|
+
*/
|
|
442
|
+
export function findHeadlessUnityForProject(projectPath) {
|
|
443
|
+
if (!projectPath)
|
|
444
|
+
return null;
|
|
445
|
+
const target = normalizePath(projectPath);
|
|
446
|
+
if (target.length === 0)
|
|
447
|
+
return null;
|
|
448
|
+
let found = [];
|
|
449
|
+
try {
|
|
450
|
+
found = getUnityProcessScanner().scan();
|
|
451
|
+
}
|
|
452
|
+
catch {
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
for (const proc of found) {
|
|
456
|
+
if (!proc.batchMode || isSupervisedBatchChildPid(proc.pid))
|
|
457
|
+
continue;
|
|
408
458
|
if (proc.projectPath !== null && normalizePath(proc.projectPath) === target) {
|
|
409
459
|
return { pid: proc.pid };
|
|
410
460
|
}
|