unity-open-mcp 0.3.1 → 0.4.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/dist/capabilities/build-capabilities.d.ts +11 -0
- package/dist/capabilities/build-capabilities.js +19 -3
- package/dist/capabilities/build-capabilities.js.map +1 -1
- package/dist/cli/cli.d.ts +18 -10
- package/dist/cli/cli.js +29 -20
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/ping-poller.js +10 -1
- package/dist/cli/ping-poller.js.map +1 -1
- package/dist/dialog-dismiss.d.ts +12 -0
- package/dist/dialog-dismiss.js +43 -13
- package/dist/dialog-dismiss.js.map +1 -1
- package/dist/dialog-policy.d.ts +40 -9
- package/dist/dialog-policy.js +122 -7
- package/dist/dialog-policy.js.map +1 -1
- package/dist/instance-discovery.d.ts +34 -0
- package/dist/instance-discovery.js +60 -2
- package/dist/instance-discovery.js.map +1 -1
- package/dist/live-client.d.ts +3 -0
- package/dist/live-client.js +95 -5
- package/dist/live-client.js.map +1 -1
- package/dist/tool-router.js +39 -4
- package/dist/tool-router.js.map +1 -1
- package/dist/tools/apply-fix.js +3 -1
- package/dist/tools/apply-fix.js.map +1 -1
- package/dist/tools/audio-source-add.js +1 -1
- package/dist/tools/audio-source-add.js.map +1 -1
- package/dist/tools/cinemachine-create-camera.js +2 -2
- package/dist/tools/cinemachine-create-camera.js.map +1 -1
- package/dist/tools/component-add.js +1 -1
- package/dist/tools/component-add.js.map +1 -1
- package/dist/tools/component-destroy.js +1 -1
- package/dist/tools/component-destroy.js.map +1 -1
- package/dist/tools/component-get.js +3 -3
- package/dist/tools/component-get.js.map +1 -1
- package/dist/tools/component-modify.js +2 -2
- package/dist/tools/component-modify.js.map +1 -1
- package/dist/tools/console-log.js +1 -1
- package/dist/tools/console-log.js.map +1 -1
- package/dist/tools/constraint-add.js +2 -2
- package/dist/tools/constraint-add.js.map +1 -1
- package/dist/tools/gameobject-destroy.js +1 -1
- package/dist/tools/gameobject-destroy.js.map +1 -1
- package/dist/tools/gameobject-duplicate.js +1 -1
- package/dist/tools/gameobject-duplicate.js.map +1 -1
- package/dist/tools/gameobject-find.js +1 -1
- package/dist/tools/gameobject-find.js.map +1 -1
- package/dist/tools/gameobject-modify.js +1 -1
- package/dist/tools/gameobject-modify.js.map +1 -1
- package/dist/tools/gameobject-set-parent.js +2 -2
- package/dist/tools/gameobject-set-parent.js.map +1 -1
- package/dist/tools/light-add.js +1 -1
- package/dist/tools/light-add.js.map +1 -1
- package/dist/tools/lod-add-level.js +1 -1
- package/dist/tools/lod-add-level.js.map +1 -1
- package/dist/tools/lod-group-configure.js +1 -1
- package/dist/tools/lod-group-configure.js.map +1 -1
- package/dist/tools/material-get-keywords.js +1 -1
- package/dist/tools/material-get-keywords.js.map +1 -1
- package/dist/tools/material-get-properties.js +1 -1
- package/dist/tools/material-get-properties.js.map +1 -1
- package/dist/tools/material-set-keyword.js +1 -1
- package/dist/tools/material-set-keyword.js.map +1 -1
- package/dist/tools/material-set-property.js +1 -1
- package/dist/tools/material-set-property.js.map +1 -1
- package/dist/tools/material-set-shader.js +1 -1
- package/dist/tools/material-set-shader.js.map +1 -1
- package/dist/tools/navigation-surface-add.js +1 -1
- package/dist/tools/navigation-surface-add.js.map +1 -1
- package/dist/tools/object-get-data.js +1 -1
- package/dist/tools/object-get-data.js.map +1 -1
- package/dist/tools/object-modify.js +1 -1
- package/dist/tools/object-modify.js.map +1 -1
- package/dist/tools/particle-system-get.js +1 -1
- package/dist/tools/particle-system-get.js.map +1 -1
- package/dist/tools/particle-system-modify.js +1 -1
- package/dist/tools/particle-system-modify.js.map +1 -1
- package/dist/tools/prefab-apply.js +1 -1
- package/dist/tools/prefab-apply.js.map +1 -1
- package/dist/tools/prefab-create.js +1 -1
- package/dist/tools/prefab-create.js.map +1 -1
- package/dist/tools/prefab-get-overrides.js +1 -1
- package/dist/tools/prefab-get-overrides.js.map +1 -1
- package/dist/tools/prefab-revert.js +1 -1
- package/dist/tools/prefab-revert.js.map +1 -1
- package/dist/tools/prefab-status.js +1 -1
- package/dist/tools/prefab-status.js.map +1 -1
- package/dist/tools/prefab-unpack.js +1 -1
- package/dist/tools/prefab-unpack.js.map +1 -1
- package/dist/tools/probuilder-delete-faces.js +1 -1
- package/dist/tools/probuilder-delete-faces.js.map +1 -1
- package/dist/tools/probuilder-extrude.js +1 -1
- package/dist/tools/probuilder-extrude.js.map +1 -1
- package/dist/tools/probuilder-set-face-material.js +1 -1
- package/dist/tools/probuilder-set-face-material.js.map +1 -1
- package/dist/tools/read-compile-errors.js +16 -3
- package/dist/tools/read-compile-errors.js.map +1 -1
- package/dist/tools/scene-focus.js +1 -1
- package/dist/tools/scene-focus.js.map +1 -1
- package/dist/tools/selection-set.js +1 -1
- package/dist/tools/selection-set.js.map +1 -1
- package/dist/tools/spatial-query.js +1 -1
- package/dist/tools/spatial-query.js.map +1 -1
- package/dist/tools/terrain-paint-layer.js +1 -1
- package/dist/tools/terrain-paint-layer.js.map +1 -1
- package/dist/tools/terrain-place-trees.js +1 -1
- package/dist/tools/terrain-place-trees.js.map +1 -1
- package/dist/tools/terrain-set-heights.js +1 -1
- package/dist/tools/terrain-set-heights.js.map +1 -1
- package/dist/tools/terrain-set-neighbors.js +1 -1
- package/dist/tools/terrain-set-neighbors.js.map +1 -1
- package/dist/tools/ui-canvas-add.js +1 -1
- package/dist/tools/ui-canvas-add.js.map +1 -1
- package/dist/tools/ui-element-add.js +1 -1
- package/dist/tools/ui-element-add.js.map +1 -1
- package/dist/tools/ui-element-modify.js +1 -1
- package/dist/tools/ui-element-modify.js.map +1 -1
- package/dist/tools/ui-layout-group-add.js +1 -1
- package/dist/tools/ui-layout-group-add.js.map +1 -1
- package/dist/unity-log.d.ts +56 -1
- package/dist/unity-log.js +136 -2
- package/dist/unity-log.js.map +1 -1
- package/package.json +1 -1
package/dist/dialog-policy.d.ts
CHANGED
|
@@ -43,12 +43,22 @@ export declare const DIALOG_POLICY_ENV = "UNITY_OPEN_MCP_DIALOG_POLICY";
|
|
|
43
43
|
*/
|
|
44
44
|
export declare function parseDialogPolicy(env?: NodeJS.ProcessEnv, warn?: (msg: string) => void): DialogPolicy;
|
|
45
45
|
/**
|
|
46
|
-
* The
|
|
47
|
-
* (under the active policy) dismiss. Each maps to a window-title
|
|
48
|
-
* (see {@link DIALOG_TITLE_FRAGMENTS}) and a per-policy button
|
|
49
|
-
* table (see {@link preferredDialogButtonLabel}).
|
|
46
|
+
* The Unity startup/steady-state modal families this helper knows how to
|
|
47
|
+
* classify and (under the active policy) dismiss. Each maps to a window-title
|
|
48
|
+
* keyword set (see {@link DIALOG_TITLE_FRAGMENTS}) and a per-policy button
|
|
49
|
+
* preference table (see {@link preferredDialogButtonLabel}).
|
|
50
|
+
*
|
|
51
|
+
* The first four (`launch_errors` … `auto_graphics_api`) are launch-time
|
|
52
|
+
* modals. The last two (`scene_modified_externally`, `unsaved_scene_changes`)
|
|
53
|
+
* are steady-state modals that can surface ANY time the editor is running —
|
|
54
|
+
* see specs/feedback.md 2026-07-03 (entries "Scene has been modified
|
|
55
|
+
* externally" + cascade-from-Unity-modal-dialog). They are NOT auto-dismissed
|
|
56
|
+
* by default: `unsaved_scene_changes` is destructive (data loss) so it is
|
|
57
|
+
* treated like `project_upgrade` (blocked unless opted in), and
|
|
58
|
+
* `scene_modified_externally` defaults to the safe Reload/Revert under auto/
|
|
59
|
+
* ignore but a `manual`/`safe-mode` policy still declines.
|
|
50
60
|
*/
|
|
51
|
-
export type DialogKind = "launch_errors" | "non_matching_editor" | "project_upgrade" | "auto_graphics_api";
|
|
61
|
+
export type DialogKind = "launch_errors" | "non_matching_editor" | "project_upgrade" | "auto_graphics_api" | "scene_modified_externally" | "unsaved_scene_changes";
|
|
52
62
|
/**
|
|
53
63
|
* Window-title fragments per dialog kind. Case-insensitive substring match
|
|
54
64
|
* against the normalized title (alphanumeric-only, lowercased — see
|
|
@@ -57,6 +67,13 @@ export type DialogKind = "launch_errors" | "non_matching_editor" | "project_upgr
|
|
|
57
67
|
*
|
|
58
68
|
* The `launch_errors` set mirrors the M13 T4.5 fragment list so the new
|
|
59
69
|
* classifier stays a strict superset of the old matcher.
|
|
70
|
+
*
|
|
71
|
+
* The steady-state kinds (`scene_modified_externally`,
|
|
72
|
+
* `unsaved_scene_changes`) cover the two modals that jam the bridge when an
|
|
73
|
+
* external process rewrites a scene file (git checkout, codegen, build
|
|
74
|
+
* tooling) or when a mutating tool leaves a scene dirty and Unity surfaces its
|
|
75
|
+
* native save prompt. Without these fragments the dismiss loop can never
|
|
76
|
+
* match them, so the modal blocks the main thread until a human clicks.
|
|
60
77
|
*/
|
|
61
78
|
export declare const DIALOG_TITLE_FRAGMENTS: Readonly<Record<DialogKind, readonly string[]>>;
|
|
62
79
|
/**
|
|
@@ -87,8 +104,14 @@ export declare function normalizeDialogLabel(value: string): string;
|
|
|
87
104
|
* Project Upgrade is gated: even when a policy WOULD confirm it (auto/ignore/
|
|
88
105
|
* recover), this function returns `null` unless `allowProjectUpgrade` is true.
|
|
89
106
|
* See {@link isProjectUpgradeBlocked}.
|
|
107
|
+
*
|
|
108
|
+
* `unsaved_scene_changes` is gated the same way via
|
|
109
|
+
* `allowUnsavedSceneDismiss` — it is destructive under every policy ("Don't
|
|
110
|
+
* Save" loses work, "Save" persists unwanted state), so it requires the
|
|
111
|
+
* dedicated opt-in before any policy may click. See
|
|
112
|
+
* {@link isUnsavedSceneBlocked}.
|
|
90
113
|
*/
|
|
91
|
-
export declare function preferenceTokensForPolicy(kind: DialogKind, policy: DialogPolicy, allowProjectUpgrade?: boolean): readonly string[] | null;
|
|
114
|
+
export declare function preferenceTokensForPolicy(kind: DialogKind, policy: DialogPolicy, allowProjectUpgrade?: boolean, allowUnsavedSceneDismiss?: boolean): readonly string[] | null;
|
|
92
115
|
/**
|
|
93
116
|
* Generic per-policy fallback token list, applied when a dialog title does NOT
|
|
94
117
|
* match any known kind (an unknown Unity modal). Ported from UCP's generic
|
|
@@ -100,16 +123,23 @@ export declare function genericFallbackTokens(policy: DialogPolicy): readonly st
|
|
|
100
123
|
/**
|
|
101
124
|
* The kinds a policy explicitly declines to dismiss. Used by the polling loop
|
|
102
125
|
* to report a `blocked` outcome (audit line, no click) instead of silently
|
|
103
|
-
* ignoring the dialog. Currently
|
|
104
|
-
* (no opt-
|
|
126
|
+
* ignoring the dialog. Currently `project_upgrade` and `unsaved_scene_changes`
|
|
127
|
+
* under the default (no opt-ins) — the two destructive-mutation guards.
|
|
105
128
|
*/
|
|
106
|
-
export declare function blockedKindsForPolicy(policy: DialogPolicy, allowProjectUpgrade?: boolean): readonly DialogKind[];
|
|
129
|
+
export declare function blockedKindsForPolicy(policy: DialogPolicy, allowProjectUpgrade?: boolean, allowUnsavedSceneDismiss?: boolean): readonly DialogKind[];
|
|
107
130
|
/**
|
|
108
131
|
* Whether a project-upgrade confirm would be blocked under the given flags.
|
|
109
132
|
* True unless the dedicated opt-in is set. Independent of policy because NO
|
|
110
133
|
* policy value implies consent to mutate the project.
|
|
111
134
|
*/
|
|
112
135
|
export declare function isProjectUpgradeBlocked(_policy: DialogPolicy, allowProjectUpgrade?: boolean): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Whether an unsaved-scene-changes dismissal would be blocked under the given
|
|
138
|
+
* flags. True unless the dedicated opt-in is set — independent of policy
|
|
139
|
+
* because "Don't Save" loses work and "Save" persists unwanted state under
|
|
140
|
+
* every policy. See {@link blockedKindsForPolicy}.
|
|
141
|
+
*/
|
|
142
|
+
export declare function isUnsavedSceneBlocked(_policy: DialogPolicy, allowUnsavedSceneDismiss?: boolean): boolean;
|
|
113
143
|
/**
|
|
114
144
|
* Select the button to click on a dialog, given its kind, the visible button
|
|
115
145
|
* labels, the active policy, and the project-upgrade opt-in.
|
|
@@ -126,6 +156,7 @@ export declare function isProjectUpgradeBlocked(_policy: DialogPolicy, allowProj
|
|
|
126
156
|
*/
|
|
127
157
|
export declare function preferredDialogButtonLabel(kind: DialogKind, buttonLabels: readonly string[], policy: DialogPolicy, opts?: {
|
|
128
158
|
allowProjectUpgrade?: boolean;
|
|
159
|
+
allowUnsavedSceneDismiss?: boolean;
|
|
129
160
|
}): {
|
|
130
161
|
button: string;
|
|
131
162
|
token: string;
|
package/dist/dialog-policy.js
CHANGED
|
@@ -60,6 +60,13 @@ function defaultWarn(msg) {
|
|
|
60
60
|
*
|
|
61
61
|
* The `launch_errors` set mirrors the M13 T4.5 fragment list so the new
|
|
62
62
|
* classifier stays a strict superset of the old matcher.
|
|
63
|
+
*
|
|
64
|
+
* The steady-state kinds (`scene_modified_externally`,
|
|
65
|
+
* `unsaved_scene_changes`) cover the two modals that jam the bridge when an
|
|
66
|
+
* external process rewrites a scene file (git checkout, codegen, build
|
|
67
|
+
* tooling) or when a mutating tool leaves a scene dirty and Unity surfaces its
|
|
68
|
+
* native save prompt. Without these fragments the dismiss loop can never
|
|
69
|
+
* match them, so the modal blocks the main thread until a human clicks.
|
|
63
70
|
*/
|
|
64
71
|
export const DIALOG_TITLE_FRAGMENTS = {
|
|
65
72
|
// Unity 2020.2+ renamed the launch-errors dialog to "Enter Safe Mode?".
|
|
@@ -82,6 +89,38 @@ export const DIALOG_TITLE_FRAGMENTS = {
|
|
|
82
89
|
project_upgrade: ["projectupgraderequired"],
|
|
83
90
|
// "Auto Graphics API Notice" — informational, typically OK only.
|
|
84
91
|
auto_graphics_api: ["autographicsapi"],
|
|
92
|
+
// specs/feedback.md 2026-07-03 — "Scene has been modified externally. Do you
|
|
93
|
+
// want to reload?" surfaces when an external process (git checkout, build
|
|
94
|
+
// tooling, codegen) rewrites a .unity file Unity has open. Buttons are
|
|
95
|
+
// typically "Reload" / "Revert" / "Keep Mine". The safe forward-progress
|
|
96
|
+
// choice under auto/ignore is to accept the disk version (Reload/Revert) —
|
|
97
|
+
// the external rewrite was intentional. Title fragments cover the observed
|
|
98
|
+
// spellings across Unity 2022 LTS and 6000.x.
|
|
99
|
+
scene_modified_externally: [
|
|
100
|
+
"modifiedexternally",
|
|
101
|
+
"scenemodified",
|
|
102
|
+
"fileondiskwasmodified",
|
|
103
|
+
"reloadscene",
|
|
104
|
+
"scenemodifiedonthedisk",
|
|
105
|
+
],
|
|
106
|
+
// specs/feedback.md 2026-07-03 — "Unsaved changes to scene. Save Changes?"
|
|
107
|
+
// surfaces when a mutating tool leaves a scene dirty and Unity's native save
|
|
108
|
+
// prompt fires (often via a domain reload / scene reload). Buttons are
|
|
109
|
+
// typically "Save" / "Don't Save" / "Cancel". This is DESTRUCTIVE under every
|
|
110
|
+
// policy: "Don't Save" discards work, "Save" persists potentially-unwanted
|
|
111
|
+
// state. So it is treated like project_upgrade — blocked unless the dedicated
|
|
112
|
+
// opt-in UNITY_OPEN_MCP_ALLOW_UNSAVED_SCENE_DISMISS=1 is set (see
|
|
113
|
+
// blockedKindsForPolicy / isUnsavedSceneBlocked). The fragment list lets the
|
|
114
|
+
// classifier still RECOGNIZE the modal (so the dismiss loop reports `blocked`
|
|
115
|
+
// with a clear audit line instead of `not-found`) even when it declines to
|
|
116
|
+
// click.
|
|
117
|
+
unsaved_scene_changes: [
|
|
118
|
+
"unsavedchanges",
|
|
119
|
+
"savechanges",
|
|
120
|
+
"savethechanges",
|
|
121
|
+
"savemodifiedscenes",
|
|
122
|
+
"doyouwanttosave",
|
|
123
|
+
],
|
|
85
124
|
};
|
|
86
125
|
/**
|
|
87
126
|
* Classify a Unity window title into a known dialog kind, or `null` when it
|
|
@@ -139,12 +178,22 @@ export function normalizeDialogLabel(value) {
|
|
|
139
178
|
* Project Upgrade is gated: even when a policy WOULD confirm it (auto/ignore/
|
|
140
179
|
* recover), this function returns `null` unless `allowProjectUpgrade` is true.
|
|
141
180
|
* See {@link isProjectUpgradeBlocked}.
|
|
181
|
+
*
|
|
182
|
+
* `unsaved_scene_changes` is gated the same way via
|
|
183
|
+
* `allowUnsavedSceneDismiss` — it is destructive under every policy ("Don't
|
|
184
|
+
* Save" loses work, "Save" persists unwanted state), so it requires the
|
|
185
|
+
* dedicated opt-in before any policy may click. See
|
|
186
|
+
* {@link isUnsavedSceneBlocked}.
|
|
142
187
|
*/
|
|
143
|
-
export function preferenceTokensForPolicy(kind, policy, allowProjectUpgrade = false) {
|
|
188
|
+
export function preferenceTokensForPolicy(kind, policy, allowProjectUpgrade = false, allowUnsavedSceneDismiss = false) {
|
|
144
189
|
// Project Upgrade: never confirm unless the dedicated opt-in is set,
|
|
145
190
|
// regardless of policy. This is the irreversible-mutation guard.
|
|
146
191
|
if (kind === "project_upgrade" && !allowProjectUpgrade)
|
|
147
192
|
return null;
|
|
193
|
+
// Unsaved-scene-changes: destructive under every policy (data loss either
|
|
194
|
+
// way). Requires the dedicated opt-in before any policy may click.
|
|
195
|
+
if (kind === "unsaved_scene_changes" && !allowUnsavedSceneDismiss)
|
|
196
|
+
return null;
|
|
148
197
|
switch (kind) {
|
|
149
198
|
case "launch_errors":
|
|
150
199
|
return launchErrorsTokens(policy);
|
|
@@ -155,6 +204,11 @@ export function preferenceTokensForPolicy(kind, policy, allowProjectUpgrade = fa
|
|
|
155
204
|
return projectUpgradeTokens(policy);
|
|
156
205
|
case "auto_graphics_api":
|
|
157
206
|
return autoGraphicsApiTokens(policy);
|
|
207
|
+
case "scene_modified_externally":
|
|
208
|
+
return sceneModifiedExternallyTokens(policy);
|
|
209
|
+
case "unsaved_scene_changes":
|
|
210
|
+
// Only reached when allowUnsavedSceneDismiss === true.
|
|
211
|
+
return unsavedSceneChangesTokens(policy);
|
|
158
212
|
}
|
|
159
213
|
}
|
|
160
214
|
function launchErrorsTokens(policy) {
|
|
@@ -214,6 +268,50 @@ function autoGraphicsApiTokens(policy) {
|
|
|
214
268
|
return null;
|
|
215
269
|
}
|
|
216
270
|
}
|
|
271
|
+
// specs/feedback.md 2026-07-03 — "Scene has been modified externally" modal.
|
|
272
|
+
// Under auto/ignore/recover the safe choice is to accept the disk version
|
|
273
|
+
// (Reload/Revert) — the external rewrite (git checkout, codegen) was
|
|
274
|
+
// intentional, so keeping the in-memory copy would silently undo it. cancel
|
|
275
|
+
// declines (Quit/Cancel). safe-mode/manual decline (no safe forward-progress
|
|
276
|
+
// button — the operator should inspect).
|
|
277
|
+
function sceneModifiedExternallyTokens(policy) {
|
|
278
|
+
switch (policy) {
|
|
279
|
+
case "auto":
|
|
280
|
+
case "ignore":
|
|
281
|
+
case "recover":
|
|
282
|
+
// "Reload" / "Revert" / "Load From Disk" all accept the on-disk version.
|
|
283
|
+
// "Continue" covers variants that phrase it that way. Order matters: we
|
|
284
|
+
// prefer the explicit reload verbs before the generic continue/ok.
|
|
285
|
+
return ["reload", "revert", "loadfromdisk", "continue", "ok"];
|
|
286
|
+
case "cancel":
|
|
287
|
+
return ["quit", "cancel", "close", "no"];
|
|
288
|
+
case "safe-mode":
|
|
289
|
+
case "manual":
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
// specs/feedback.md 2026-07-03 — "Unsaved changes to scene. Save Changes?"
|
|
294
|
+
// modal. Only reached when allowUnsavedSceneDismiss === true (the dedicated
|
|
295
|
+
// opt-in). Under auto/ignore/recover the least-bad choice is to Save
|
|
296
|
+
// (preserve work) — "Don't Save" discards it. cancel still declines. This is
|
|
297
|
+
// inherently judgment-laden, which is why it is opt-in only.
|
|
298
|
+
function unsavedSceneChangesTokens(policy) {
|
|
299
|
+
switch (policy) {
|
|
300
|
+
case "auto":
|
|
301
|
+
case "ignore":
|
|
302
|
+
case "recover":
|
|
303
|
+
// Prefer Save (preserve work) over Don't Save (discard). "Save All"
|
|
304
|
+
// covers the multi-scene variant.
|
|
305
|
+
return ["save", "saveall", "savechanges", "ok", "yes"];
|
|
306
|
+
case "cancel":
|
|
307
|
+
// Cancel under cancel policy = Don't Save (decline to persist). Phrased
|
|
308
|
+
// as the explicit dontsave token first so the audit line is unambiguous.
|
|
309
|
+
return ["dontsave", "dontsaveall", "no", "quit", "cancel", "close"];
|
|
310
|
+
case "safe-mode":
|
|
311
|
+
case "manual":
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
217
315
|
/**
|
|
218
316
|
* Generic per-policy fallback token list, applied when a dialog title does NOT
|
|
219
317
|
* match any known kind (an unknown Unity modal). Ported from UCP's generic
|
|
@@ -275,15 +373,22 @@ export function genericFallbackTokens(policy) {
|
|
|
275
373
|
/**
|
|
276
374
|
* The kinds a policy explicitly declines to dismiss. Used by the polling loop
|
|
277
375
|
* to report a `blocked` outcome (audit line, no click) instead of silently
|
|
278
|
-
* ignoring the dialog. Currently
|
|
279
|
-
* (no opt-
|
|
376
|
+
* ignoring the dialog. Currently `project_upgrade` and `unsaved_scene_changes`
|
|
377
|
+
* under the default (no opt-ins) — the two destructive-mutation guards.
|
|
280
378
|
*/
|
|
281
|
-
export function blockedKindsForPolicy(policy, allowProjectUpgrade = false) {
|
|
379
|
+
export function blockedKindsForPolicy(policy, allowProjectUpgrade = false, allowUnsavedSceneDismiss = false) {
|
|
282
380
|
if (policy === "manual")
|
|
283
381
|
return []; // manual declines everything — not "blocked"
|
|
382
|
+
const blocked = [];
|
|
284
383
|
if (!allowProjectUpgrade)
|
|
285
|
-
|
|
286
|
-
|
|
384
|
+
blocked.push("project_upgrade");
|
|
385
|
+
// unsaved_scene_changes is destructive under every policy (data loss either
|
|
386
|
+
// way); block it unless the dedicated opt-in is set. This means the dismiss
|
|
387
|
+
// loop reports `blocked` with a clear audit line instead of silently passing
|
|
388
|
+
// it as `not-found` — so a stall shows up with the right diagnosis.
|
|
389
|
+
if (!allowUnsavedSceneDismiss)
|
|
390
|
+
blocked.push("unsaved_scene_changes");
|
|
391
|
+
return blocked;
|
|
287
392
|
}
|
|
288
393
|
/**
|
|
289
394
|
* Whether a project-upgrade confirm would be blocked under the given flags.
|
|
@@ -293,6 +398,15 @@ export function blockedKindsForPolicy(policy, allowProjectUpgrade = false) {
|
|
|
293
398
|
export function isProjectUpgradeBlocked(_policy, allowProjectUpgrade = false) {
|
|
294
399
|
return !allowProjectUpgrade;
|
|
295
400
|
}
|
|
401
|
+
/**
|
|
402
|
+
* Whether an unsaved-scene-changes dismissal would be blocked under the given
|
|
403
|
+
* flags. True unless the dedicated opt-in is set — independent of policy
|
|
404
|
+
* because "Don't Save" loses work and "Save" persists unwanted state under
|
|
405
|
+
* every policy. See {@link blockedKindsForPolicy}.
|
|
406
|
+
*/
|
|
407
|
+
export function isUnsavedSceneBlocked(_policy, allowUnsavedSceneDismiss = false) {
|
|
408
|
+
return !allowUnsavedSceneDismiss;
|
|
409
|
+
}
|
|
296
410
|
/**
|
|
297
411
|
* Select the button to click on a dialog, given its kind, the visible button
|
|
298
412
|
* labels, the active policy, and the project-upgrade opt-in.
|
|
@@ -309,7 +423,8 @@ export function isProjectUpgradeBlocked(_policy, allowProjectUpgrade = false) {
|
|
|
309
423
|
*/
|
|
310
424
|
export function preferredDialogButtonLabel(kind, buttonLabels, policy, opts = {}) {
|
|
311
425
|
const allowProjectUpgrade = opts.allowProjectUpgrade ?? false;
|
|
312
|
-
const
|
|
426
|
+
const allowUnsavedSceneDismiss = opts.allowUnsavedSceneDismiss ?? false;
|
|
427
|
+
const tokens = preferenceTokensForPolicy(kind, policy, allowProjectUpgrade, allowUnsavedSceneDismiss);
|
|
313
428
|
if (tokens === null)
|
|
314
429
|
return null;
|
|
315
430
|
return matchTokens(tokens, buttonLabels);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dialog-policy.js","sourceRoot":"","sources":["../src/dialog-policy.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,sEAAsE;AACtE,EAAE;AACF,6EAA6E;AAC7E,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,gFAAgF;AAChF,+EAA+E;AAC/E,+EAA+E;AAC/E,EAAE;AACF,iFAAiF;AACjF,qEAAqE;AA0CrE,sDAAsD;AACtD,MAAM,CAAC,MAAM,oBAAoB,GAA4B;IAC3D,MAAM;IACN,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,WAAW;IACX,QAAQ;CACT,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAiB,QAAQ,CAAC;AAE5D,4CAA4C;AAC5C,MAAM,CAAC,MAAM,iBAAiB,GAAG,8BAA8B,CAAC;AAEhE;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAyB,OAAO,CAAC,GAAG,EACpC,OAA8B,WAAW;IAEzC,MAAM,GAAG,GAAG,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACnC,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE;QAAE,OAAO,qBAAqB,CAAC;IAClE,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACtC,IAAK,oBAA0C,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/D,OAAO,IAAoB,CAAC;IAC9B,CAAC;IACD,IAAI,CACF,4BAA4B,iBAAiB,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI;QACtE,mBAAmB,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;QACtD,oBAAoB,qBAAqB,IAAI,CAChD,CAAC;IACF,OAAO,qBAAqB,CAAC;AAC/B,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,6EAA6E;IAC7E,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACpB,CAAC;
|
|
1
|
+
{"version":3,"file":"dialog-policy.js","sourceRoot":"","sources":["../src/dialog-policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -37,10 +37,44 @@ export declare function projectHash(projectPath: string): string;
|
|
|
37
37
|
* C# UInt64 computation exactly.
|
|
38
38
|
*/
|
|
39
39
|
export declare function computePort(projectPath: string): number;
|
|
40
|
+
/**
|
|
41
|
+
* Base scratch directory shared by the bridge and the MCP server
|
|
42
|
+
* (`~/.unity-open-mcp`). Mirrors the C# `TestRunnerService.StatusDir`. Holds
|
|
43
|
+
* the `instances/` subdirectory (per-project locks) and the bridge's
|
|
44
|
+
* `test-pending-*.json` / `test-results-*.json` scratch files.
|
|
45
|
+
*/
|
|
46
|
+
export declare function statusDir(): string;
|
|
40
47
|
/** Directory holding one lock file per running bridge instance. */
|
|
41
48
|
export declare function instancesDir(): string;
|
|
42
49
|
/** Path to this project's instance lock file. */
|
|
43
50
|
export declare function lockPath(projectPath: string): string;
|
|
51
|
+
/**
|
|
52
|
+
* Default TTL for considering a `test-pending-*.json` file "recent." A pending
|
|
53
|
+
* file older than this is treated as a stale leftover from a crashed/abandoned
|
|
54
|
+
* run and does NOT suppress the dead-bridge classification. Generous enough to
|
|
55
|
+
* outlast a slow PlayMode domain reload + ILPP pass; short enough that a
|
|
56
|
+
* genuinely dead bridge is surfaced promptly once a run is no longer active.
|
|
57
|
+
*/
|
|
58
|
+
export declare const TEST_PENDING_TTL_MS = 300000;
|
|
59
|
+
/**
|
|
60
|
+
* Whether a `test-pending-*.json` file written within `ttlMs` exists in the
|
|
61
|
+
* status directory. The bridge writes one such file at the start of every test
|
|
62
|
+
* run (RunTestsTool.MarkPending, all modes) and deletes it in the run's
|
|
63
|
+
* onFinished callback (ClearPending). Its existence therefore signals "a test
|
|
64
|
+
* run is in flight" — used by the dead-bridge emitters to keep waiting (treat
|
|
65
|
+
* the stale heartbeat as a normal reload) instead of failing fast with
|
|
66
|
+
* `bridge_compile_failed`, because Unity's TestRunnerApi can freeze the
|
|
67
|
+
* heartbeat writer during a domain reload long enough to trip the stale-
|
|
68
|
+
* heartbeat threshold. Never throws: any fs error returns false (fail safe —
|
|
69
|
+
* a missing/unreadable signal must not mask a genuine dead bridge).
|
|
70
|
+
*
|
|
71
|
+
* @param nowMs Current time (injectable for tests). Defaults to Date.now().
|
|
72
|
+
* @param ttlMs Max age of a pending file to count as recent.
|
|
73
|
+
* Defaults to {@link TEST_PENDING_TTL_MS}.
|
|
74
|
+
* @param dir Status directory to scan (injectable for tests). Defaults to
|
|
75
|
+
* {@link statusDir}.
|
|
76
|
+
*/
|
|
77
|
+
export declare function hasRecentPendingTestRun(nowMs?: number, ttlMs?: number, dir?: string): boolean;
|
|
44
78
|
/**
|
|
45
79
|
* Read this project's instance lock from disk. Returns null if the file is
|
|
46
80
|
* missing, unreadable, or doesn't parse. Never throws — the caller falls
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
// No external deps (only node:crypto, node:fs, node:os, node:path) so the
|
|
20
20
|
// "no runtime deps beyond MCP SDK" rule (mcp-server/AGENTS.md) holds.
|
|
21
21
|
import { createHash } from "node:crypto";
|
|
22
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
22
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
23
23
|
import { homedir } from "node:os";
|
|
24
24
|
import { join } from "node:path";
|
|
25
25
|
export const PORT_RANGE_START = 20000;
|
|
@@ -54,14 +54,72 @@ export function computePort(projectPath) {
|
|
|
54
54
|
const prefix = BigInt("0x" + hash.slice(0, 16));
|
|
55
55
|
return PORT_RANGE_START + Number(prefix % BigInt(PORT_RANGE_SIZE));
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Base scratch directory shared by the bridge and the MCP server
|
|
59
|
+
* (`~/.unity-open-mcp`). Mirrors the C# `TestRunnerService.StatusDir`. Holds
|
|
60
|
+
* the `instances/` subdirectory (per-project locks) and the bridge's
|
|
61
|
+
* `test-pending-*.json` / `test-results-*.json` scratch files.
|
|
62
|
+
*/
|
|
63
|
+
export function statusDir() {
|
|
64
|
+
return join(homedir(), ".unity-open-mcp");
|
|
65
|
+
}
|
|
57
66
|
/** Directory holding one lock file per running bridge instance. */
|
|
58
67
|
export function instancesDir() {
|
|
59
|
-
return join(
|
|
68
|
+
return join(statusDir(), "instances");
|
|
60
69
|
}
|
|
61
70
|
/** Path to this project's instance lock file. */
|
|
62
71
|
export function lockPath(projectPath) {
|
|
63
72
|
return join(instancesDir(), `${projectHash(projectPath)}.json`);
|
|
64
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Default TTL for considering a `test-pending-*.json` file "recent." A pending
|
|
76
|
+
* file older than this is treated as a stale leftover from a crashed/abandoned
|
|
77
|
+
* run and does NOT suppress the dead-bridge classification. Generous enough to
|
|
78
|
+
* outlast a slow PlayMode domain reload + ILPP pass; short enough that a
|
|
79
|
+
* genuinely dead bridge is surfaced promptly once a run is no longer active.
|
|
80
|
+
*/
|
|
81
|
+
export const TEST_PENDING_TTL_MS = 300_000; // 5 minutes
|
|
82
|
+
/**
|
|
83
|
+
* Whether a `test-pending-*.json` file written within `ttlMs` exists in the
|
|
84
|
+
* status directory. The bridge writes one such file at the start of every test
|
|
85
|
+
* run (RunTestsTool.MarkPending, all modes) and deletes it in the run's
|
|
86
|
+
* onFinished callback (ClearPending). Its existence therefore signals "a test
|
|
87
|
+
* run is in flight" — used by the dead-bridge emitters to keep waiting (treat
|
|
88
|
+
* the stale heartbeat as a normal reload) instead of failing fast with
|
|
89
|
+
* `bridge_compile_failed`, because Unity's TestRunnerApi can freeze the
|
|
90
|
+
* heartbeat writer during a domain reload long enough to trip the stale-
|
|
91
|
+
* heartbeat threshold. Never throws: any fs error returns false (fail safe —
|
|
92
|
+
* a missing/unreadable signal must not mask a genuine dead bridge).
|
|
93
|
+
*
|
|
94
|
+
* @param nowMs Current time (injectable for tests). Defaults to Date.now().
|
|
95
|
+
* @param ttlMs Max age of a pending file to count as recent.
|
|
96
|
+
* Defaults to {@link TEST_PENDING_TTL_MS}.
|
|
97
|
+
* @param dir Status directory to scan (injectable for tests). Defaults to
|
|
98
|
+
* {@link statusDir}.
|
|
99
|
+
*/
|
|
100
|
+
export function hasRecentPendingTestRun(nowMs = Date.now(), ttlMs = TEST_PENDING_TTL_MS, dir = statusDir()) {
|
|
101
|
+
let entries;
|
|
102
|
+
try {
|
|
103
|
+
entries = readdirSync(dir);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
for (const entry of entries) {
|
|
109
|
+
if (!entry.startsWith("test-pending-") || !entry.endsWith(".json"))
|
|
110
|
+
continue;
|
|
111
|
+
let mtimeMs;
|
|
112
|
+
try {
|
|
113
|
+
mtimeMs = statSync(join(dir, entry)).mtimeMs;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (nowMs - mtimeMs <= ttlMs)
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
65
123
|
/**
|
|
66
124
|
* Read this project's instance lock from disk. Returns null if the file is
|
|
67
125
|
* missing, unreadable, or doesn't parse. Never throws — the caller falls
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instance-discovery.js","sourceRoot":"","sources":["../src/instance-discovery.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,EAAE;AACF,iFAAiF;AACjF,8EAA8E;AAC9E,8EAA8E;AAC9E,UAAU;AACV,EAAE;AACF,0DAA0D;AAC1D,6EAA6E;AAC7E,yEAAyE;AACzE,yEAAyE;AACzE,wEAAwE;AACxE,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAChF,wDAAwD;AACxD,0EAA0E;AAC1E,EAAE;AACF,0EAA0E;AAC1E,sEAAsE;AAEtE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"instance-discovery.js","sourceRoot":"","sources":["../src/instance-discovery.ts"],"names":[],"mappings":"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"}
|
package/dist/live-client.d.ts
CHANGED
|
@@ -45,6 +45,9 @@ export declare class LiveClient implements Router {
|
|
|
45
45
|
/** M23 Plan 2 — opt-in for the Project Upgrade Required dialog (irreversible,
|
|
46
46
|
* off by default). */
|
|
47
47
|
private allowProjectUpgrade;
|
|
48
|
+
/** specs/feedback.md 2026-07-03 — opt-in for the "Unsaved changes to scene"
|
|
49
|
+
* modal (destructive under every policy, off by default). */
|
|
50
|
+
private allowUnsavedSceneDismiss;
|
|
48
51
|
/** M14 — per-session bearer token auto-discovered from the instance lock.
|
|
49
52
|
* Undefined when no live lock was found (older bridge / env port override);
|
|
50
53
|
* in that case no Authorization header is sent and the bridge must be in
|