unity-open-mcp 0.9.0 → 1.1.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/asmdef-discovery.d.ts +35 -0
- package/dist/asmdef-discovery.js +171 -0
- package/dist/asmdef-discovery.js.map +1 -0
- package/dist/batch-spawn.d.ts +27 -0
- package/dist/batch-spawn.js +218 -24
- package/dist/batch-spawn.js.map +1 -1
- package/dist/capabilities/build-capabilities.d.ts +10 -0
- package/dist/capabilities/build-capabilities.js +4 -0
- package/dist/capabilities/build-capabilities.js.map +1 -1
- package/dist/capabilities/capabilities-view.d.ts +48 -0
- package/dist/capabilities/capabilities-view.js +93 -0
- package/dist/capabilities/capabilities-view.js.map +1 -0
- package/dist/capabilities/intent-groups.js +42 -0
- package/dist/capabilities/intent-groups.js.map +1 -1
- package/dist/capabilities/rule-catalog.js +7 -1
- package/dist/capabilities/rule-catalog.js.map +1 -1
- package/dist/capabilities/tool-groups.js +37 -2
- package/dist/capabilities/tool-groups.js.map +1 -1
- package/dist/child-supervision.d.ts +34 -0
- package/dist/child-supervision.js +110 -0
- package/dist/child-supervision.js.map +1 -0
- package/dist/cli/cli.js +9 -0
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/commands.js +37 -4
- package/dist/cli/commands.js.map +1 -1
- package/dist/compressible-router.js +12 -1
- package/dist/compressible-router.js.map +1 -1
- package/dist/constants.d.ts +31 -1
- package/dist/constants.js +31 -1
- package/dist/constants.js.map +1 -1
- package/dist/dialog-dismiss.d.ts +11 -0
- package/dist/dialog-dismiss.js +59 -4
- package/dist/dialog-dismiss.js.map +1 -1
- package/dist/editor-wedge.d.ts +45 -0
- package/dist/editor-wedge.js +111 -0
- package/dist/editor-wedge.js.map +1 -0
- package/dist/event-stream.d.ts +19 -6
- package/dist/event-stream.js +139 -17
- package/dist/event-stream.js.map +1 -1
- package/dist/gate-error.d.ts +2 -0
- package/dist/gate-error.js +9 -0
- package/dist/gate-error.js.map +1 -1
- package/dist/instance-discovery.d.ts +23 -0
- package/dist/instance-discovery.js +47 -1
- package/dist/instance-discovery.js.map +1 -1
- package/dist/live-client.d.ts +40 -5
- package/dist/live-client.js +254 -36
- package/dist/live-client.js.map +1 -1
- package/dist/offline/api.js +82 -30
- package/dist/offline/api.js.map +1 -1
- package/dist/offline/index-builders.d.ts +9 -0
- package/dist/offline/index-builders.js +58 -8
- package/dist/offline/index-builders.js.map +1 -1
- package/dist/offline/parse.js +5 -1
- package/dist/offline/parse.js.map +1 -1
- package/dist/process-diagnostics.d.ts +101 -19
- package/dist/process-diagnostics.js +197 -59
- package/dist/process-diagnostics.js.map +1 -1
- package/dist/project-settings.d.ts +36 -0
- package/dist/project-settings.js +96 -0
- package/dist/project-settings.js.map +1 -0
- package/dist/results.d.ts +8 -0
- package/dist/results.js +4 -1
- package/dist/results.js.map +1 -1
- package/dist/routers.js +4 -1
- package/dist/routers.js.map +1 -1
- package/dist/running-unity.d.ts +23 -0
- package/dist/running-unity.js +60 -0
- package/dist/running-unity.js.map +1 -1
- package/dist/server.js +8 -2
- package/dist/server.js.map +1 -1
- package/dist/stale-assembly-cache.d.ts +40 -0
- package/dist/stale-assembly-cache.js +76 -0
- package/dist/stale-assembly-cache.js.map +1 -0
- package/dist/tool-hint.d.ts +36 -0
- package/dist/tool-hint.js +98 -0
- package/dist/tool-hint.js.map +1 -0
- package/dist/tool-router.d.ts +47 -2
- package/dist/tool-router.js +652 -71
- package/dist/tool-router.js.map +1 -1
- package/dist/tools/agent-capabilities.js +27 -1
- package/dist/tools/agent-capabilities.js.map +1 -1
- package/dist/tools/baseline-create.js +1 -1
- package/dist/tools/baseline-create.js.map +1 -1
- package/dist/tools/batch-execute.js +12 -1
- package/dist/tools/batch-execute.js.map +1 -1
- package/dist/tools/bridge-status.js +21 -1
- package/dist/tools/bridge-status.js.map +1 -1
- package/dist/tools/capture-inline.js +4 -3
- package/dist/tools/capture-inline.js.map +1 -1
- package/dist/tools/editor-status.js +7 -2
- package/dist/tools/editor-status.js.map +1 -1
- package/dist/tools/execute-csharp.js +36 -3
- package/dist/tools/execute-csharp.js.map +1 -1
- package/dist/tools/execute-menu.js +33 -2
- package/dist/tools/execute-menu.js.map +1 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +44 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/inputsim-key.d.ts +40 -0
- package/dist/tools/inputsim-key.js +72 -0
- package/dist/tools/inputsim-key.js.map +1 -0
- package/dist/tools/inputsim-pointer.d.ts +40 -0
- package/dist/tools/inputsim-pointer.js +121 -0
- package/dist/tools/inputsim-pointer.js.map +1 -0
- package/dist/tools/inputsim-pointer3d.d.ts +40 -0
- package/dist/tools/inputsim-pointer3d.js +55 -0
- package/dist/tools/inputsim-pointer3d.js.map +1 -0
- package/dist/tools/inputsim-probe.d.ts +40 -0
- package/dist/tools/inputsim-probe.js +43 -0
- package/dist/tools/inputsim-probe.js.map +1 -0
- package/dist/tools/inputsim-step.d.ts +40 -0
- package/dist/tools/inputsim-step.js +50 -0
- package/dist/tools/inputsim-step.js.map +1 -0
- package/dist/tools/inputsim-touch.d.ts +40 -0
- package/dist/tools/inputsim-touch.js +83 -0
- package/dist/tools/inputsim-touch.js.map +1 -0
- package/dist/tools/invoke-method.js +15 -1
- package/dist/tools/invoke-method.js.map +1 -1
- package/dist/tools/memory-snapshot-capture.js +11 -5
- package/dist/tools/memory-snapshot-capture.js.map +1 -1
- package/dist/tools/pull-events.js +18 -10
- package/dist/tools/pull-events.js.map +1 -1
- package/dist/tools/read-compile-errors.js +36 -7
- package/dist/tools/read-compile-errors.js.map +1 -1
- package/dist/tools/regression-check.js +2 -1
- package/dist/tools/regression-check.js.map +1 -1
- package/dist/tools/resource-pressure.js +21 -10
- package/dist/tools/resource-pressure.js.map +1 -1
- package/dist/tools/run-tests.js +11 -2
- package/dist/tools/run-tests.js.map +1 -1
- package/dist/tools/scan-all.js +2 -2
- package/dist/tools/scan-all.js.map +1 -1
- package/dist/tools/screenshot-window.js +18 -12
- package/dist/tools/screenshot-window.js.map +1 -1
- package/dist/tools/screenshot.js +13 -6
- package/dist/tools/screenshot.js.map +1 -1
- package/dist/tools/visual-compare.d.ts +40 -0
- package/dist/tools/visual-compare.js +98 -0
- package/dist/tools/visual-compare.js.map +1 -0
- package/dist/unity-log.d.ts +67 -2
- package/dist/unity-log.js +206 -8
- package/dist/unity-log.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Input simulation — 3D / legacy world-space pointer (M3).
|
|
2
|
+
//
|
|
3
|
+
// Reaches physics-collider gameplay and old-Input-Manager code that
|
|
4
|
+
// inputsim_pointer (uGUI ExecuteEvents) cannot. Mechanics: Physics.Raycast from
|
|
5
|
+
// the screen → SendMessage("OnMouseDown"/"OnMouseUp"/"OnMouseUpAsButton"/
|
|
6
|
+
// "OnMouseDrag"). No package dependency beyond built-in UnityEngine.Physics.
|
|
7
|
+
// Gate-free, play-mode-only. Compile-gated on com.unity.ugui (shares the uGUI
|
|
8
|
+
// sub-asmdef for target/screen resolution helpers, though it uses neither
|
|
9
|
+
// EventSystem nor uGUI types at the dispatch path).
|
|
10
|
+
import { makeTool } from "./schema-fragments.js";
|
|
11
|
+
export const inputsimPointer3d = makeTool("unity_open_mcp_inputsim_pointer3d", "Simulate a world-space / legacy mouse interaction during play mode by " +
|
|
12
|
+
"raycasting from the screen point through Camera.main and SendMessage-ing the " +
|
|
13
|
+
"OnMouseDown / OnMouseUp / OnMouseUpAsButton / OnMouseDrag magic methods on " +
|
|
14
|
+
"the hit collider. Reaches physics gameplay and old-Input-Manager code that " +
|
|
15
|
+
"inputsim_pointer (uGUI ExecuteEvents) cannot — the only way to drive " +
|
|
16
|
+
"world-space gameplay in a project running the legacy Input Manager. " +
|
|
17
|
+
"Resolution: object_id > target > screen_x/screen_y (same as inputsim_pointer). " +
|
|
18
|
+
"Play-mode only — refuses with `play_mode_required` otherwise. Gate-free. " +
|
|
19
|
+
"Requires a tagged MainCamera in the scene.", {
|
|
20
|
+
required: ["action"],
|
|
21
|
+
properties: {
|
|
22
|
+
action: {
|
|
23
|
+
type: "string",
|
|
24
|
+
enum: ["click", "down", "up", "drag"],
|
|
25
|
+
description: "click = OnMouseDown + OnMouseUpAsButton + OnMouseUp; down = OnMouseDown; " +
|
|
26
|
+
"up = OnMouseUp; drag = OnMouseDown + OnMouseDrag×drag_steps + OnMouseUp " +
|
|
27
|
+
"(requires to_x/to_y).",
|
|
28
|
+
},
|
|
29
|
+
object_id: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: "InstanceId of a GameObject used to refine the screen point (its center " +
|
|
32
|
+
"is raycast), as a quoted string. The actual target is whatever the ray " +
|
|
33
|
+
"hits at that point. Wins over target and screen_x/screen_y. Pass as a " +
|
|
34
|
+
"string to stay precise on Unity 6000.5+ where an EntityId can exceed " +
|
|
35
|
+
"2^53 (the bridge accepts a quoted string or a bare number).",
|
|
36
|
+
},
|
|
37
|
+
target: {
|
|
38
|
+
type: "string",
|
|
39
|
+
description: "GameObject name/path used to refine the screen point. Alternative to object_id/screen.",
|
|
40
|
+
},
|
|
41
|
+
screen_x: { type: "number", description: "Screen X (pixels) to raycast from. Pair with screen_y." },
|
|
42
|
+
screen_y: { type: "number", description: "Screen Y (pixels) to raycast from. Pair with screen_x." },
|
|
43
|
+
to_x: { type: "number", description: "Drag end — screen X (action: drag only). Pair with to_y." },
|
|
44
|
+
to_y: { type: "number", description: "Drag end — screen Y (action: drag only). Pair with to_x." },
|
|
45
|
+
drag_steps: {
|
|
46
|
+
type: "integer",
|
|
47
|
+
default: 8,
|
|
48
|
+
minimum: 1,
|
|
49
|
+
maximum: 100,
|
|
50
|
+
description: "Number of OnMouseDrag calls between from and to (action: drag). Capped at " +
|
|
51
|
+
"100 to bound main-thread cost. Default 8.",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
//# sourceMappingURL=inputsim-pointer3d.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inputsim-pointer3d.js","sourceRoot":"","sources":["../../src/tools/inputsim-pointer3d.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,EAAE;AACF,oEAAoE;AACpE,gFAAgF;AAChF,0EAA0E;AAC1E,6EAA6E;AAC7E,8EAA8E;AAC9E,0EAA0E;AAC1E,oDAAoD;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CACvC,mCAAmC,EACnC,wEAAwE;IACtE,+EAA+E;IAC/E,6EAA6E;IAC7E,6EAA6E;IAC7E,uEAAuE;IACvE,sEAAsE;IACtE,iFAAiF;IACjF,2EAA2E;IAC3E,4CAA4C,EAC9C;IACE,QAAQ,EAAE,CAAC,QAAQ,CAAC;IACpB,UAAU,EAAE;QACV,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC;YACrC,WAAW,EACT,2EAA2E;gBAC3E,0EAA0E;gBAC1E,uBAAuB;SAC1B;QACD,SAAS,EAAE;YACT,IAAI,EAAE,QAAQ;YACd,WAAW,EACT,yEAAyE;gBACzE,yEAAyE;gBACzE,wEAAwE;gBACxE,uEAAuE;gBACvE,6DAA6D;SAChE;QACD,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,wFAAwF;SACtG;QACD,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,wDAAwD,EAAE;QACnG,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,wDAAwD,EAAE;QACnG,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0DAA0D,EAAE;QACjG,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0DAA0D,EAAE;QACjG,UAAU,EAAE;YACV,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,GAAG;YACZ,WAAW,EACT,4EAA4E;gBAC5E,2CAA2C;SAC9C;KACF;CACF,CACF,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare const inputsimProbe: {
|
|
2
|
+
inputSchema: {
|
|
3
|
+
[x: string]: unknown;
|
|
4
|
+
type: "object";
|
|
5
|
+
properties?: {
|
|
6
|
+
[x: string]: object;
|
|
7
|
+
} | undefined;
|
|
8
|
+
required?: string[] | undefined;
|
|
9
|
+
};
|
|
10
|
+
name: string;
|
|
11
|
+
description?: string | undefined;
|
|
12
|
+
outputSchema?: {
|
|
13
|
+
[x: string]: unknown;
|
|
14
|
+
type: "object";
|
|
15
|
+
properties?: {
|
|
16
|
+
[x: string]: object;
|
|
17
|
+
} | undefined;
|
|
18
|
+
required?: string[] | undefined;
|
|
19
|
+
} | undefined;
|
|
20
|
+
annotations?: {
|
|
21
|
+
title?: string | undefined;
|
|
22
|
+
readOnlyHint?: boolean | undefined;
|
|
23
|
+
destructiveHint?: boolean | undefined;
|
|
24
|
+
idempotentHint?: boolean | undefined;
|
|
25
|
+
openWorldHint?: boolean | undefined;
|
|
26
|
+
} | undefined;
|
|
27
|
+
execution?: {
|
|
28
|
+
taskSupport?: "optional" | "required" | "forbidden" | undefined;
|
|
29
|
+
} | undefined;
|
|
30
|
+
_meta?: {
|
|
31
|
+
[x: string]: unknown;
|
|
32
|
+
} | undefined;
|
|
33
|
+
icons?: {
|
|
34
|
+
src: string;
|
|
35
|
+
mimeType?: string | undefined;
|
|
36
|
+
sizes?: string[] | undefined;
|
|
37
|
+
theme?: "light" | "dark" | undefined;
|
|
38
|
+
}[] | undefined;
|
|
39
|
+
title?: string | undefined;
|
|
40
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Input simulation — interactable discovery (M2).
|
|
2
|
+
//
|
|
3
|
+
// Turns the surface self-sufficient: the testing loop becomes
|
|
4
|
+
// probe → click by path → step → screenshot
|
|
5
|
+
// instead of screenshot → guess a name → target_not_found → guess again.
|
|
6
|
+
// Lists active uGUI interactables (IPointer*Handler / IDragHandler / IDropHandler /
|
|
7
|
+
// ISubmitHandler / Selectable) with hierarchy path, screen rect, interactable
|
|
8
|
+
// flag, instanceId, and whether anything occludes their center.
|
|
9
|
+
//
|
|
10
|
+
// Read-only. Works in edit mode AND play mode (use it to build a click plan
|
|
11
|
+
// before entering play mode). Compile-gated on com.unity.ugui.
|
|
12
|
+
import { makeTool } from "./schema-fragments.js";
|
|
13
|
+
export const inputsimProbe = makeTool("unity_open_mcp_inputsim_probe", "List active uGUI interactables (objects with IPointer*Handler / IDragHandler / " +
|
|
14
|
+
"IDropHandler / ISubmitHandler / Selectable) so an agent can build a click plan " +
|
|
15
|
+
"without guessing names. Each entry carries: hierarchy path, name, instanceId " +
|
|
16
|
+
"(pass it to inputsim_pointer.object_id for unambiguous targeting), screen " +
|
|
17
|
+
"rect, interactable (false when the Selectable or an ancestor CanvasGroup " +
|
|
18
|
+
"disables it), and occluded (true when something else raycast-hits in front of " +
|
|
19
|
+
"the element's center — play mode only). Read-only; works in edit mode and play " +
|
|
20
|
+
"mode. The intended loop: probe → inputsim_pointer (object_id) → inputsim_step " +
|
|
21
|
+
"→ screenshot. Requires com.unity.ugui.", {
|
|
22
|
+
required: [],
|
|
23
|
+
properties: {
|
|
24
|
+
page_size: {
|
|
25
|
+
type: "integer",
|
|
26
|
+
default: 50,
|
|
27
|
+
minimum: 1,
|
|
28
|
+
maximum: 200,
|
|
29
|
+
description: "Max entries per page. Default 50, hard cap 200.",
|
|
30
|
+
},
|
|
31
|
+
cursor: {
|
|
32
|
+
type: "string",
|
|
33
|
+
description: "Opaque pagination cursor from a previous response's pagination.next_cursor. " +
|
|
34
|
+
"Omit on the first call.",
|
|
35
|
+
},
|
|
36
|
+
scene: {
|
|
37
|
+
type: "string",
|
|
38
|
+
description: "Optional loaded-scene name filter — only enumerate interactables in this " +
|
|
39
|
+
"scene. Omit to enumerate across all loaded scenes.",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
//# sourceMappingURL=inputsim-probe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inputsim-probe.js","sourceRoot":"","sources":["../../src/tools/inputsim-probe.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,EAAE;AACF,8DAA8D;AAC9D,8CAA8C;AAC9C,yEAAyE;AACzE,oFAAoF;AACpF,8EAA8E;AAC9E,gEAAgE;AAChE,EAAE;AACF,4EAA4E;AAC5E,+DAA+D;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,MAAM,CAAC,MAAM,aAAa,GAAG,QAAQ,CACnC,+BAA+B,EAC/B,iFAAiF;IAC/E,iFAAiF;IACjF,+EAA+E;IAC/E,4EAA4E;IAC5E,2EAA2E;IAC3E,gFAAgF;IAChF,iFAAiF;IACjF,gFAAgF;IAChF,wCAAwC,EAC1C;IACE,QAAQ,EAAE,EAAE;IACZ,UAAU,EAAE;QACV,SAAS,EAAE;YACT,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,EAAE;YACX,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,GAAG;YACZ,WAAW,EAAE,iDAAiD;SAC/D;QACD,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,WAAW,EACT,8EAA8E;gBAC9E,yBAAyB;SAC5B;QACD,KAAK,EAAE;YACL,IAAI,EAAE,QAAQ;YACd,WAAW,EACT,2EAA2E;gBAC3E,oDAAoD;SACvD;KACF;CACF,CACF,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare const inputsimStep: {
|
|
2
|
+
inputSchema: {
|
|
3
|
+
[x: string]: unknown;
|
|
4
|
+
type: "object";
|
|
5
|
+
properties?: {
|
|
6
|
+
[x: string]: object;
|
|
7
|
+
} | undefined;
|
|
8
|
+
required?: string[] | undefined;
|
|
9
|
+
};
|
|
10
|
+
name: string;
|
|
11
|
+
description?: string | undefined;
|
|
12
|
+
outputSchema?: {
|
|
13
|
+
[x: string]: unknown;
|
|
14
|
+
type: "object";
|
|
15
|
+
properties?: {
|
|
16
|
+
[x: string]: object;
|
|
17
|
+
} | undefined;
|
|
18
|
+
required?: string[] | undefined;
|
|
19
|
+
} | undefined;
|
|
20
|
+
annotations?: {
|
|
21
|
+
title?: string | undefined;
|
|
22
|
+
readOnlyHint?: boolean | undefined;
|
|
23
|
+
destructiveHint?: boolean | undefined;
|
|
24
|
+
idempotentHint?: boolean | undefined;
|
|
25
|
+
openWorldHint?: boolean | undefined;
|
|
26
|
+
} | undefined;
|
|
27
|
+
execution?: {
|
|
28
|
+
taskSupport?: "optional" | "required" | "forbidden" | undefined;
|
|
29
|
+
} | undefined;
|
|
30
|
+
_meta?: {
|
|
31
|
+
[x: string]: unknown;
|
|
32
|
+
} | undefined;
|
|
33
|
+
icons?: {
|
|
34
|
+
src: string;
|
|
35
|
+
mimeType?: string | undefined;
|
|
36
|
+
sizes?: string[] | undefined;
|
|
37
|
+
theme?: "light" | "dark" | undefined;
|
|
38
|
+
}[] | undefined;
|
|
39
|
+
title?: string | undefined;
|
|
40
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// Input simulation — frame advance. The missing middle of the play-mode
|
|
2
|
+
// testing loop: inject input (inputsim_pointer / _key / _touch), then advance N
|
|
3
|
+
// frames so gameplay MonoBehaviour.Update / coroutines / tweens run, THEN
|
|
4
|
+
// screenshot. Without this, a click that opens a panel with a 0.3s tween
|
|
5
|
+
// screenshots as the old panel.
|
|
6
|
+
//
|
|
7
|
+
// Also the fix for K1/K2/`hold`: a synchronous tool cannot otherwise let a key
|
|
8
|
+
// press or swipe be observed by polling game code. `step` lets the documented
|
|
9
|
+
// `down → advance → up` workflow actually work.
|
|
10
|
+
//
|
|
11
|
+
// Implementation: EditorApplication.Step() is synchronous — it runs one full
|
|
12
|
+
// player-loop frame inline (Update/FixedUpdate/coroutines/render) before
|
|
13
|
+
// returning, so a tight loop pumps N frames within one tool dispatch. Unlike
|
|
14
|
+
// QueuePlayerLoopUpdate + Thread.Sleep (documented broken elsewhere in the
|
|
15
|
+
// bridge — the sleeping thread is the one that would service the update), Step
|
|
16
|
+
// does not deadlock. Play-mode only (no-op in edit mode → play_mode_required).
|
|
17
|
+
import { makeTool } from "./schema-fragments.js";
|
|
18
|
+
export const inputsimStep = makeTool("unity_open_mcp_inputsim_step", "Advance the Unity play-mode player loop by N frames, then return. Pump the " +
|
|
19
|
+
"frames synchronously via EditorApplication.Step (each Step runs one full " +
|
|
20
|
+
"Update/FixedUpdate/coroutines/render cycle inline). Use between an input " +
|
|
21
|
+
"injection (inputsim_pointer / _key / _touch) and a screenshot so gameplay " +
|
|
22
|
+
"code, tweens, and animations actually run before you look — and so polling " +
|
|
23
|
+
"game code (`wasPressedThisFrame`, per-frame touch delta) can observe a " +
|
|
24
|
+
"press/swipe injected with inputsim_key/_touch (which otherwise process in a " +
|
|
25
|
+
"single InputSystem.Update and are invisible to polling). Play-mode only — " +
|
|
26
|
+
"refuses with `play_mode_required` otherwise (Step is a no-op in edit mode). " +
|
|
27
|
+
"Gate-free (writes no assets). Cap 60 frames per call to bound dispatch cost; " +
|
|
28
|
+
"for longer advances, call repeatedly.", {
|
|
29
|
+
required: [],
|
|
30
|
+
properties: {
|
|
31
|
+
frames: {
|
|
32
|
+
type: "integer",
|
|
33
|
+
default: 1,
|
|
34
|
+
minimum: 0,
|
|
35
|
+
maximum: 60,
|
|
36
|
+
description: "Number of player-loop frames to advance. Default 1. Hard cap 60 to " +
|
|
37
|
+
"bound dispatch cost (each frame is a full Update cycle). 0 is allowed " +
|
|
38
|
+
"and useful as a pure settle tick (one QueuePlayerLoopUpdate).",
|
|
39
|
+
},
|
|
40
|
+
settle_ms: {
|
|
41
|
+
type: "integer",
|
|
42
|
+
default: 0,
|
|
43
|
+
minimum: 0,
|
|
44
|
+
description: "Optional extra wall-clock settle in milliseconds AFTER stepping, as a " +
|
|
45
|
+
"single QueuePlayerLoopUpdate (lets one more render tick land before a " +
|
|
46
|
+
"screenshot). Default 0 (no extra tick).",
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
//# sourceMappingURL=inputsim-step.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inputsim-step.js","sourceRoot":"","sources":["../../src/tools/inputsim-step.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,gFAAgF;AAChF,0EAA0E;AAC1E,yEAAyE;AACzE,gCAAgC;AAChC,EAAE;AACF,+EAA+E;AAC/E,8EAA8E;AAC9E,gDAAgD;AAChD,EAAE;AACF,6EAA6E;AAC7E,yEAAyE;AACzE,6EAA6E;AAC7E,2EAA2E;AAC3E,+EAA+E;AAC/E,+EAA+E;AAC/E,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,MAAM,CAAC,MAAM,YAAY,GAAG,QAAQ,CAClC,8BAA8B,EAC9B,6EAA6E;IAC3E,2EAA2E;IAC3E,2EAA2E;IAC3E,4EAA4E;IAC5E,6EAA6E;IAC7E,yEAAyE;IACzE,8EAA8E;IAC9E,4EAA4E;IAC5E,8EAA8E;IAC9E,+EAA+E;IAC/E,uCAAuC,EACzC;IACE,QAAQ,EAAE,EAAE;IACZ,UAAU,EAAE;QACV,MAAM,EAAE;YACN,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,EAAE;YACX,WAAW,EACT,qEAAqE;gBACrE,wEAAwE;gBACxE,+DAA+D;SAClE;QACD,SAAS,EAAE;YACT,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;YACV,WAAW,EACT,wEAAwE;gBACxE,wEAAwE;gBACxE,yCAAyC;SAC5C;KACF;CACF,CACF,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare const inputsimTouch: {
|
|
2
|
+
inputSchema: {
|
|
3
|
+
[x: string]: unknown;
|
|
4
|
+
type: "object";
|
|
5
|
+
properties?: {
|
|
6
|
+
[x: string]: object;
|
|
7
|
+
} | undefined;
|
|
8
|
+
required?: string[] | undefined;
|
|
9
|
+
};
|
|
10
|
+
name: string;
|
|
11
|
+
description?: string | undefined;
|
|
12
|
+
outputSchema?: {
|
|
13
|
+
[x: string]: unknown;
|
|
14
|
+
type: "object";
|
|
15
|
+
properties?: {
|
|
16
|
+
[x: string]: object;
|
|
17
|
+
} | undefined;
|
|
18
|
+
required?: string[] | undefined;
|
|
19
|
+
} | undefined;
|
|
20
|
+
annotations?: {
|
|
21
|
+
title?: string | undefined;
|
|
22
|
+
readOnlyHint?: boolean | undefined;
|
|
23
|
+
destructiveHint?: boolean | undefined;
|
|
24
|
+
idempotentHint?: boolean | undefined;
|
|
25
|
+
openWorldHint?: boolean | undefined;
|
|
26
|
+
} | undefined;
|
|
27
|
+
execution?: {
|
|
28
|
+
taskSupport?: "optional" | "required" | "forbidden" | undefined;
|
|
29
|
+
} | undefined;
|
|
30
|
+
_meta?: {
|
|
31
|
+
[x: string]: unknown;
|
|
32
|
+
} | undefined;
|
|
33
|
+
icons?: {
|
|
34
|
+
src: string;
|
|
35
|
+
mimeType?: string | undefined;
|
|
36
|
+
sizes?: string[] | undefined;
|
|
37
|
+
theme?: "light" | "dark" | undefined;
|
|
38
|
+
}[] | undefined;
|
|
39
|
+
title?: string | undefined;
|
|
40
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Input simulation — Input System touch / swipe device events.
|
|
2
|
+
//
|
|
3
|
+
// Compile-gated on com.unity.inputsystem (UNITY_OPEN_MCP_EXT_INPUTSIM_IS).
|
|
4
|
+
// Queues Touchscreen state events through the new Input System.
|
|
5
|
+
//
|
|
6
|
+
// K2 fix: `swipe` accepts `advance_frames` to advance a frame AFTER each Moved
|
|
7
|
+
// phase, so the swipe genuinely unfolds across frames for polling code (per-frame
|
|
8
|
+
// primaryTouch.delta, distance/velocity gesture recognizers). Without
|
|
9
|
+
// `advance_frames`, all Moved phases collapse into a single InputSystem.Update —
|
|
10
|
+
// documented honestly now (previously mis-advertised as "across real frames").
|
|
11
|
+
//
|
|
12
|
+
// Play-mode only. Gate-free. Requires com.unity.inputsystem.
|
|
13
|
+
import { makeTool } from "./schema-fragments.js";
|
|
14
|
+
export const inputsimTouch = makeTool("unity_open_mcp_inputsim_touch", "Queue a touch / swipe event sequence through the Input System " +
|
|
15
|
+
"(Touchscreen.current) during play mode. `tap` = press+release at a point; " +
|
|
16
|
+
"`swipe` = press at from_, move across `steps` interpolated points, release " +
|
|
17
|
+
"at to_; `press`/`release` = single-phase control. POLLING vs CALLBACK: " +
|
|
18
|
+
"without `advance_frames`, all touch phases process in a single " +
|
|
19
|
+
"InputSystem.Update — so polling code (per-frame primaryTouch.delta, gesture " +
|
|
20
|
+
"recognizers) sees a collapsed jump, not a real swipe. Pass `advance_frames` " +
|
|
21
|
+
"≥ 1 to advance a frame after each Moved phase so the swipe unfolds across " +
|
|
22
|
+
"real frames for polling code. Callback-driven InputAction.performed fires " +
|
|
23
|
+
"either way. Endpoints resolve target-first (object_id/name/path → screen " +
|
|
24
|
+
"point) or accept screen_x/screen_y directly. NOTE: target resolution here " +
|
|
25
|
+
"uses a plain GameObject.Find name/path match (no ambiguity detection or " +
|
|
26
|
+
"partial-path matching — that lives in the uGUI-gated inputsim_pointer, and " +
|
|
27
|
+
"this tool compiles against the Input System package only); prefer an " +
|
|
28
|
+
"object_id or a full unique path for the target. Play-mode only — refuses " +
|
|
29
|
+
"with `play_mode_required` otherwise. Gate-free. Requires com.unity.inputsystem.", {
|
|
30
|
+
required: ["action"],
|
|
31
|
+
properties: {
|
|
32
|
+
action: {
|
|
33
|
+
type: "string",
|
|
34
|
+
enum: ["tap", "swipe", "press", "release"],
|
|
35
|
+
description: "tap = press+release at one point; swipe = press at from_, move across " +
|
|
36
|
+
"`steps` interpolated points, release at to_; press = touch down only; " +
|
|
37
|
+
"release = touch up only.",
|
|
38
|
+
},
|
|
39
|
+
finger: {
|
|
40
|
+
type: "integer",
|
|
41
|
+
default: 0,
|
|
42
|
+
minimum: 0,
|
|
43
|
+
maximum: 9,
|
|
44
|
+
description: "Touch finger index (0–9) for multi-touch. Default 0.",
|
|
45
|
+
},
|
|
46
|
+
target: {
|
|
47
|
+
type: "string",
|
|
48
|
+
description: "GameObject to tap/press/release — name or hierarchy path. Resolved to a " +
|
|
49
|
+
"screen point via the active camera. Omit when using screen_x/screen_y.",
|
|
50
|
+
},
|
|
51
|
+
screen_x: { type: "number", description: "Screen X (pixels) for tap/press/release. Pair with screen_y." },
|
|
52
|
+
screen_y: { type: "number", description: "Screen Y (pixels) for tap/press/release. Pair with screen_x." },
|
|
53
|
+
from_target: {
|
|
54
|
+
type: "string",
|
|
55
|
+
description: "Swipe start — target name/path (alternative to from_x/from_y).",
|
|
56
|
+
},
|
|
57
|
+
from_x: { type: "number", description: "Swipe start — screen X (alternative to from_target)." },
|
|
58
|
+
from_y: { type: "number", description: "Swipe start — screen Y (alternative to from_target)." },
|
|
59
|
+
to_target: { type: "string", description: "Swipe end — target name/path (alternative to to_x/to_y)." },
|
|
60
|
+
to_x: { type: "number", description: "Swipe end — screen X (alternative to to_target)." },
|
|
61
|
+
to_y: { type: "number", description: "Swipe end — screen Y (alternative to to_target)." },
|
|
62
|
+
duration_ms: { type: "integer", default: 200, description: "Swipe total duration in milliseconds (recorded). Default 200." },
|
|
63
|
+
steps: {
|
|
64
|
+
type: "integer",
|
|
65
|
+
default: 10,
|
|
66
|
+
minimum: 1,
|
|
67
|
+
maximum: 100,
|
|
68
|
+
description: "Number of interpolated move events in a swipe. Capped at 100 to bound " +
|
|
69
|
+
"main-thread cost (each step can run advance_frames × Step). Default 10.",
|
|
70
|
+
},
|
|
71
|
+
advance_frames: {
|
|
72
|
+
type: "integer",
|
|
73
|
+
default: 0,
|
|
74
|
+
minimum: 0,
|
|
75
|
+
maximum: 60,
|
|
76
|
+
description: "Pump this many player-loop frames (EditorApplication.Step) AFTER each " +
|
|
77
|
+
"Moved phase so the swipe unfolds across real frames for polling code " +
|
|
78
|
+
"(per-frame delta, gesture recognizers). 0 (default) collapses all phases " +
|
|
79
|
+
"into one update — only callback-driven input sees it then. Cap 60.",
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
//# sourceMappingURL=inputsim-touch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inputsim-touch.js","sourceRoot":"","sources":["../../src/tools/inputsim-touch.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,EAAE;AACF,2EAA2E;AAC3E,gEAAgE;AAChE,EAAE;AACF,+EAA+E;AAC/E,kFAAkF;AAClF,sEAAsE;AACtE,iFAAiF;AACjF,+EAA+E;AAC/E,EAAE;AACF,6DAA6D;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,MAAM,CAAC,MAAM,aAAa,GAAG,QAAQ,CACnC,+BAA+B,EAC/B,gEAAgE;IAC9D,4EAA4E;IAC5E,6EAA6E;IAC7E,yEAAyE;IACzE,iEAAiE;IACjE,8EAA8E;IAC9E,8EAA8E;IAC9E,4EAA4E;IAC5E,4EAA4E;IAC5E,2EAA2E;IAC3E,4EAA4E;IAC5E,0EAA0E;IAC1E,6EAA6E;IAC7E,uEAAuE;IACvE,2EAA2E;IAC3E,iFAAiF,EACnF;IACE,QAAQ,EAAE,CAAC,QAAQ,CAAC;IACpB,UAAU,EAAE;QACV,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC;YAC1C,WAAW,EACT,wEAAwE;gBACxE,wEAAwE;gBACxE,0BAA0B;SAC7B;QACD,MAAM,EAAE;YACN,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;YACV,WAAW,EAAE,sDAAsD;SACpE;QACD,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,WAAW,EACT,0EAA0E;gBAC1E,wEAAwE;SAC3E;QACD,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,8DAA8D,EAAE;QACzG,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,8DAA8D,EAAE;QACzG,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,gEAAgE;SAC9E;QACD,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sDAAsD,EAAE;QAC/F,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sDAAsD,EAAE;QAC/F,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0DAA0D,EAAE;QACtG,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,kDAAkD,EAAE;QACzF,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,kDAAkD,EAAE;QACzF,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,+DAA+D,EAAE;QAC5H,KAAK,EAAE;YACL,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,EAAE;YACX,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,GAAG;YACZ,WAAW,EACT,wEAAwE;gBACxE,yEAAyE;SAC5E;QACD,cAAc,EAAE;YACd,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,EAAE;YACX,WAAW,EACT,wEAAwE;gBACxE,uEAAuE;gBACvE,2EAA2E;gBAC3E,oEAAoE;SACvE;KACF;CACF,CACF,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BRIDGE_DEFAULT_TIMEOUT_MS } from "../constants.js";
|
|
1
|
+
import { BRIDGE_DEFAULT_TIMEOUT_MS, BRIDGE_MIN_TIMEOUT_MS, BRIDGE_HOST_SAFE_TIMEOUT_CAP_MS } from "../constants.js";
|
|
2
2
|
import { GATE_PROP, PATHS_HINT_TYPE, IGNORE_SCENE_DIRTY_BASE, makeTool } from "./schema-fragments.js";
|
|
3
3
|
// M16 Plan 6 — invoke_method enhanced in place with better overload + generic-
|
|
4
4
|
// arg resolution. Two new inputs:
|
|
@@ -69,6 +69,20 @@ export const invokeMethod = makeTool("unity_open_mcp_invoke_method", "Call a met
|
|
|
69
69
|
timeout_ms: {
|
|
70
70
|
type: "integer",
|
|
71
71
|
default: BRIDGE_DEFAULT_TIMEOUT_MS,
|
|
72
|
+
minimum: BRIDGE_MIN_TIMEOUT_MS,
|
|
73
|
+
// specs/feedback.md 2026-08-24 — the live POST path clamps every
|
|
74
|
+
// forwarded timeout_ms to BRIDGE_HOST_SAFE_TIMEOUT_CAP_MS, so the
|
|
75
|
+
// ceiling has to be DECLARED: a schema with no `maximum` invites a
|
|
76
|
+
// 120000 first call, which a validating client rejects outright
|
|
77
|
+
// (too_big) and a non-validating one gets clamped anyway. Same cap
|
|
78
|
+
// and same reasoning as execute_csharp / execute_menu.
|
|
79
|
+
maximum: BRIDGE_HOST_SAFE_TIMEOUT_CAP_MS,
|
|
80
|
+
description: `How long to wait for the invocation to return. Hard cap ${BRIDGE_HOST_SAFE_TIMEOUT_CAP_MS} ms ` +
|
|
81
|
+
"(the transport cap shared with execute_csharp / execute_menu): values above a typical " +
|
|
82
|
+
"MCP host request timeout (~60s) are unreachable because the host aborts the tools/call " +
|
|
83
|
+
"first, so the route clamps server-side and reports the clamp. A method that needs longer " +
|
|
84
|
+
"belongs in unity_senses_run_tests (async job-poll shape) or split into smaller calls. " +
|
|
85
|
+
"Default 30000.",
|
|
72
86
|
},
|
|
73
87
|
max_depth: {
|
|
74
88
|
type: "integer",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invoke-method.js","sourceRoot":"","sources":["../../src/tools/invoke-method.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"invoke-method.js","sourceRoot":"","sources":["../../src/tools/invoke-method.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,qBAAqB,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAC;AACpH,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,uBAAuB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtG,+EAA+E;AAC/E,kCAAkC;AAClC,wEAAwE;AACxE,+EAA+E;AAC/E,0DAA0D;AAC1D,8EAA8E;AAC9E,+DAA+D;AAC/D,0EAA0E;AAC1E,2EAA2E;AAC3E,6CAA6C;AAC7C,MAAM,CAAC,MAAM,YAAY,GAAG,QAAQ,CAClC,8BAA8B,EAC9B,qFAAqF;IACnF,oFAAoF;IACpF,uFAAuF;IACvF,uFAAuF;IACvF,sFAAsF,EACxF;IACE,QAAQ,EAAE,CAAC,WAAW,EAAE,aAAa,CAAC;IAClC,UAAU,EAAE;QACV,SAAS,EAAE;YACT,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,2BAA2B;SACzC;QACD,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;SACf;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,OAAO;YACb,WAAW,EAAE,6BAA6B;YAC1C,KAAK,EAAE,EAAE;SACV;QACD,cAAc,EAAE;YACd,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACzB,WAAW,EACT,+DAA+D;gBAC/D,+EAA+E;gBAC/E,mFAAmF;gBACnF,8EAA8E;gBAC9E,YAAY;SACf;QACD,iBAAiB,EAAE;YACjB,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACzB,WAAW,EACT,oFAAoF;gBACpF,iFAAiF;gBACjF,uFAAuF;SAC1F;QACD,SAAS,EAAE;YACT,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,KAAK;SACf;QACD,aAAa,EAAE;YACb,IAAI,EAAE,QAAQ;YACd,WAAW,EACT,oDAAoD;SACvD;QACD,SAAS,EAAE;YACT,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,CAAC;YACV,WAAW,EACT,gEAAgE;gBAChE,+DAA+D;gBAC/D,iEAAiE;gBACjE,gEAAgE;gBAChE,iEAAiE;gBACjE,uCAAuC;SAC1C;QACD,UAAU,EAAE,EAAE,GAAG,eAAe,EAAE;QAClC,kBAAkB,EAAE,EAAE,GAAG,uBAAuB,EAAE,WAAW,EAAE,kEAAkE,GAAG,kEAAkE,GAAG,iEAAiE,GAAG,qEAAqE,EAAE;QACpV,IAAI,EAAE,EAAE,GAAG,SAAS,EAAE;QACtB,UAAU,EAAE;YACV,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,yBAAyB;YAClC,OAAO,EAAE,qBAAqB;YAC9B,iEAAiE;YACjE,kEAAkE;YAClE,mEAAmE;YACnE,gEAAgE;YAChE,mEAAmE;YACnE,uDAAuD;YACvD,OAAO,EAAE,+BAA+B;YACxC,WAAW,EACT,2DAA2D,+BAA+B,MAAM;gBAChG,wFAAwF;gBACxF,yFAAyF;gBACzF,2FAA2F;gBAC3F,wFAAwF;gBACxF,gBAAgB;SACnB;QACD,SAAS,EAAE;YACT,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;YACV,WAAW,EACT,6EAA6E;SAChF;QACD,SAAS,EAAE;YACT,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,GAAG;YACZ,OAAO,EAAE,CAAC;YACV,WAAW,EACT,+HAA+H;SAClI;KACF;CACN,CACF,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BRIDGE_HOST_SAFE_TIMEOUT_CAP_MS } from "../constants.js";
|
|
1
2
|
import { makeTool } from "./schema-fragments.js";
|
|
2
3
|
// M20 Plan 7 / T20.7.3 — Memory Profiler snapshot capture. Compile-gated in
|
|
3
4
|
// the bridge (UNITY_OPEN_MCP_EXT_MEMORYPROFILER on com.unity.memoryprofiler) +
|
|
@@ -44,12 +45,17 @@ export const memorySnapshotCapture = makeTool("unity_senses_memory_snapshot_capt
|
|
|
44
45
|
timeout_ms: {
|
|
45
46
|
type: "integer",
|
|
46
47
|
description: "Maximum milliseconds to wait for the callback-based capture to " +
|
|
47
|
-
"finish (default
|
|
48
|
-
"the snapshot file is written; if it times out
|
|
49
|
-
"memoryprofiler_capture_timeout."
|
|
50
|
-
|
|
48
|
+
"finish (default + maximum = the transport cap, ~55000 ms). The " +
|
|
49
|
+
"capture blocks until the snapshot file is written; if it times out " +
|
|
50
|
+
"the tool returns memoryprofiler_capture_timeout. The ceiling is the " +
|
|
51
|
+
"bridge transport cap (BRIDGE_HOST_SAFE_TIMEOUT_CAP_MS): a single " +
|
|
52
|
+
"blocking tool call cannot run longer than a typical MCP host " +
|
|
53
|
+
"request timeout, so a snapshot that needs more than ~55s cannot " +
|
|
54
|
+
"complete in one call — run it manually from the Memory Profiler " +
|
|
55
|
+
"window (Window > Analysis > Memory Profiler) for very large heaps.",
|
|
56
|
+
default: BRIDGE_HOST_SAFE_TIMEOUT_CAP_MS,
|
|
51
57
|
minimum: 1000,
|
|
52
|
-
maximum:
|
|
58
|
+
maximum: BRIDGE_HOST_SAFE_TIMEOUT_CAP_MS,
|
|
53
59
|
},
|
|
54
60
|
},
|
|
55
61
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-snapshot-capture.js","sourceRoot":"","sources":["../../src/tools/memory-snapshot-capture.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,4EAA4E;AAC5E,+EAA+E;AAC/E,8EAA8E;AAC9E,yEAAyE;AACzE,wEAAwE;AACxE,EAAE;AACF,2EAA2E;AAC3E,gFAAgF;AAChF,gFAAgF;AAChF,kFAAkF;AAClF,+EAA+E;AAC/E,6EAA6E;AAC7E,6DAA6D;AAC7D,EAAE;AACF,6EAA6E;AAC7E,qDAAqD;AACrD,MAAM,CAAC,MAAM,qBAAqB,GAAG,QAAQ,CAC3C,sCAAsC,EACtC,+DAA+D;IAC7D,yEAAyE;IACzE,2EAA2E;IAC3E,0EAA0E;IAC1E,sEAAsE;IACtE,2EAA2E;IAC3E,wEAAwE;IACxE,0EAA0E;IAC1E,iEAAiE;IACjE,wDAAwD;IACxD,6EAA6E;IAC7E,8EAA8E;IAC9E,yEAAyE;IACzE,sEAAsE;IACtE,uEAAuE;IACvE,YAAY,EACd;IACE,UAAU,EAAE;QACN,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,WAAW,EACT,uEAAuE;gBACvE,sEAAsE;gBACtE,mEAAmE;gBACnE,oEAAoE;gBACpE,oEAAoE;gBACpE,gDAAgD;SACnD;QACD,UAAU,EAAE;YACV,IAAI,EAAE,SAAS;YACf,WAAW,EACT,iEAAiE;gBACjE,sEAAsE;gBACtE,
|
|
1
|
+
{"version":3,"file":"memory-snapshot-capture.js","sourceRoot":"","sources":["../../src/tools/memory-snapshot-capture.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,4EAA4E;AAC5E,+EAA+E;AAC/E,8EAA8E;AAC9E,yEAAyE;AACzE,wEAAwE;AACxE,EAAE;AACF,2EAA2E;AAC3E,gFAAgF;AAChF,gFAAgF;AAChF,kFAAkF;AAClF,+EAA+E;AAC/E,6EAA6E;AAC7E,6DAA6D;AAC7D,EAAE;AACF,6EAA6E;AAC7E,qDAAqD;AACrD,MAAM,CAAC,MAAM,qBAAqB,GAAG,QAAQ,CAC3C,sCAAsC,EACtC,+DAA+D;IAC7D,yEAAyE;IACzE,2EAA2E;IAC3E,0EAA0E;IAC1E,sEAAsE;IACtE,2EAA2E;IAC3E,wEAAwE;IACxE,0EAA0E;IAC1E,iEAAiE;IACjE,wDAAwD;IACxD,6EAA6E;IAC7E,8EAA8E;IAC9E,yEAAyE;IACzE,sEAAsE;IACtE,uEAAuE;IACvE,YAAY,EACd;IACE,UAAU,EAAE;QACN,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,WAAW,EACT,uEAAuE;gBACvE,sEAAsE;gBACtE,mEAAmE;gBACnE,oEAAoE;gBACpE,oEAAoE;gBACpE,gDAAgD;SACnD;QACD,UAAU,EAAE;YACV,IAAI,EAAE,SAAS;YACf,WAAW,EACT,iEAAiE;gBACjE,iEAAiE;gBACjE,qEAAqE;gBACrE,sEAAsE;gBACtE,mEAAmE;gBACnE,+DAA+D;gBAC/D,kEAAkE;gBAClE,kEAAkE;gBAClE,oEAAoE;YACtE,OAAO,EAAE,+BAA+B;YACxC,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,+BAA+B;SACzC;KACF;CACN,CACF,CAAC"}
|
|
@@ -12,12 +12,15 @@ import { makeTool } from "./schema-fragments.js";
|
|
|
12
12
|
// keeps the model in the loop and lets an agent decide when to drain (e.g.
|
|
13
13
|
// right after a mutation that may produce logs).
|
|
14
14
|
export const pullEvents = makeTool("unity_senses_pull_events", "Drain incremental bridge events (console logs + editor-state transitions) since the previous call. " +
|
|
15
|
-
"The first call opens a server-side SSE subscription
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
15
|
+
"The first call opens a server-side SSE subscription and returns nothing (an empty events array with " +
|
|
16
|
+
"started:true); console history is NOT replayed. For anything that happened before the first call, " +
|
|
17
|
+
"read the Editor log via unity_open_mcp_read_compile_errors (compile errors) or call this tool BEFORE " +
|
|
18
|
+
"the operation you want to observe, then again after. Later calls return only events that arrived " +
|
|
19
|
+
"since the previous drain. Use this after execute_csharp / mutations to stream console output without " +
|
|
20
|
+
"polling /ping or re-reading the full console. Each event carries `seq`, `ts`, `type` ('log' | " +
|
|
21
|
+
"'editor_state'), and type-specific fields (logType/message/stack for logs, " +
|
|
22
|
+
"state/isCompiling/isPlaying for state). `dropped` reports events evicted from the queue before this " +
|
|
23
|
+
"pull; `connected` reports the SSE reader state. Requires a live Unity Editor connection.", {
|
|
21
24
|
properties: {
|
|
22
25
|
max_events: {
|
|
23
26
|
type: "integer",
|
|
@@ -26,12 +29,17 @@ export const pullEvents = makeTool("unity_senses_pull_events", "Drain incrementa
|
|
|
26
29
|
maximum: 1000,
|
|
27
30
|
description: "Maximum events to return per call. Additional buffered events are counted in `dropped`.",
|
|
28
31
|
},
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
+
// feedback #8 — an explicit subscriber id gives the caller its OWN
|
|
33
|
+
// read cursor over the shared queue: a fresh subscriber's first call
|
|
34
|
+
// returns started:true with NO events (its cursor starts at the current
|
|
35
|
+
// high-water mark, so history is not replayed). A returning subscriber
|
|
36
|
+
// resumes from its saved cursor. Omit to drain the shared queue
|
|
37
|
+
// (legacy behaviour). Use a distinct id per agent session.
|
|
32
38
|
subscriber: {
|
|
33
39
|
type: "string",
|
|
34
|
-
description: "Optional subscriber id
|
|
40
|
+
description: "Optional subscriber id. A NEW id starts a fresh read cursor at the current " +
|
|
41
|
+
"high-water mark (no backlog replay); a returning id resumes from its saved " +
|
|
42
|
+
"cursor. Omit to drain the shared queue.",
|
|
35
43
|
},
|
|
36
44
|
},
|
|
37
45
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pull-events.js","sourceRoot":"","sources":["../../src/tools/pull-events.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,qCAAqC;AACrC,EAAE;AACF,sEAAsE;AACtE,wEAAwE;AACxE,0EAA0E;AAC1E,yEAAyE;AACzE,0BAA0B;AAC1B,EAAE;AACF,+EAA+E;AAC/E,4EAA4E;AAC5E,2EAA2E;AAC3E,iDAAiD;AACjD,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAChC,0BAA0B,EAC1B,qGAAqG;IACnG,
|
|
1
|
+
{"version":3,"file":"pull-events.js","sourceRoot":"","sources":["../../src/tools/pull-events.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,qCAAqC;AACrC,EAAE;AACF,sEAAsE;AACtE,wEAAwE;AACxE,0EAA0E;AAC1E,yEAAyE;AACzE,0BAA0B;AAC1B,EAAE;AACF,+EAA+E;AAC/E,4EAA4E;AAC5E,2EAA2E;AAC3E,iDAAiD;AACjD,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAChC,0BAA0B,EAC1B,qGAAqG;IACnG,sGAAsG;IACtG,oGAAoG;IACpG,uGAAuG;IACvG,mGAAmG;IACnG,uGAAuG;IACvG,gGAAgG;IAChG,6EAA6E;IAC7E,sGAAsG;IACtG,0FAA0F,EAC5F;IACE,UAAU,EAAE;QACN,UAAU,EAAE;YACV,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,EAAE;YACX,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,IAAI;YACb,WAAW,EACT,yFAAyF;SAC5F;QACD,mEAAmE;QACnE,qEAAqE;QACrE,wEAAwE;QACxE,uEAAuE;QACvE,gEAAgE;QAChE,2DAA2D;QAC3D,UAAU,EAAE;YACV,IAAI,EAAE,QAAQ;YACd,WAAW,EACT,6EAA6E;gBAC7E,6EAA6E;gBAC7E,yCAAyC;SAC5C;KACF;CACN,CACF,CAAC"}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { makeTool } from "./schema-fragments.js";
|
|
2
|
+
import { toolHintReference } from "../tool-hint.js";
|
|
3
|
+
// specs/feedback.md 2026-08-14 — the description and the runtime hints must
|
|
4
|
+
// prescribe the SAME recovery path and must both carry the activation call for
|
|
5
|
+
// a tool outside the default surface. Both come from toolHintReference so the
|
|
6
|
+
// two can no longer drift.
|
|
7
|
+
const RECOMPILE_SCRIPTS_HINT = toolHintReference("unity_open_mcp_recompile_scripts");
|
|
8
|
+
const COMPILE_CHECK_HINT = toolHintReference("unity_open_mcp_compile_check");
|
|
2
9
|
// Offline, filesystem-only tool: reads the tail of Unity's Editor.log and
|
|
3
10
|
// extracts BOTH C# compiler errors AND package / assembly-level red flags AND
|
|
4
11
|
// a hard Editor hang signal. The one recovery channel that works when the
|
|
@@ -21,6 +28,9 @@ import { makeTool } from "./schema-fragments.js";
|
|
|
21
28
|
//
|
|
22
29
|
// Response fields:
|
|
23
30
|
// - status: "compile_failed" | "project_unhealthy" | "no_errors_found"
|
|
31
|
+
// | "stale_log" (errors may not apply — stale log / version
|
|
32
|
+
// mismatch) | "indeterminate" (no errors, but read from the
|
|
33
|
+
// ROTATED prev_log_* — not a verified clean bill of health)
|
|
24
34
|
// - unhealthy: true when compiler errors OR issues are present
|
|
25
35
|
// - headline: one-line triage summary (empty when healthy)
|
|
26
36
|
// - errors[]: structured CSxxxx diagnostics (file/line/code/message)
|
|
@@ -61,15 +71,34 @@ export const readCompileErrors = makeTool("unity_open_mcp_read_compile_errors",
|
|
|
61
71
|
"response carries `staleLogSuspected: true`, the cited source files " +
|
|
62
72
|
"were edited more recently than Editor.log — the error block may " +
|
|
63
73
|
"reference on-disk code you have already fixed (Unity's incremental " +
|
|
64
|
-
"compiler no-op'd the recompile).
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
74
|
+
"compiler no-op'd the recompile). When the response carries " +
|
|
75
|
+
"`errorsMayPredateEdits: true`, at least one file the errors CITE is newer " +
|
|
76
|
+
"than the newest built assembly, so no compile has completed since you " +
|
|
77
|
+
"edited it and the error block is from an earlier compile — do not re-read " +
|
|
78
|
+
"or re-fix that code on the strength of it. When the response carries " +
|
|
79
|
+
"`staleAssembly: true`, at least one Assets/**/*.cs " +
|
|
68
80
|
"source is newer than the newest Library/ScriptAssemblies/*.dll — the " +
|
|
69
81
|
"running assembly predates the latest source, so a no_errors_found signal " +
|
|
70
|
-
"CANNOT be trusted until the assembly is rebuilt.
|
|
71
|
-
"
|
|
72
|
-
"
|
|
82
|
+
"CANNOT be trusted until the assembly is rebuilt. When that flag is set " +
|
|
83
|
+
"WITH errors, the `headline` itself says the error block may predate the " +
|
|
84
|
+
"current sources (not just the separate staleAssemblyHint field). When " +
|
|
85
|
+
"`logSource` is a `prev_log_*` value (the read came from the ROTATED " +
|
|
86
|
+
"Editor-prev.log while a live Editor may be writing a different log) and " +
|
|
87
|
+
"no errors were found, `status` is `indeterminate`, NOT " +
|
|
88
|
+
"`no_errors_found` — a clean read from the rotated log is not a verified " +
|
|
89
|
+
"clean bill of health; confirm via the live bridge or re-read after the " +
|
|
90
|
+
"Editor settles. All staleness signals call for the " +
|
|
91
|
+
"same next step (one recommended path per situation, matching the runtime " +
|
|
92
|
+
`hints): call ${RECOMPILE_SCRIPTS_HINT} for a deterministic ` +
|
|
93
|
+
"force-recompile, then re-read compile errors; with the Editor closed or " +
|
|
94
|
+
`unreachable, ${COMPILE_CHECK_HINT} spawns a fresh headless recompile ` +
|
|
95
|
+
"instead. IMPORTANT — staged compilation: Unity compiles " +
|
|
96
|
+
"assemblies in dependency order, so when `errorCount` is small but the project " +
|
|
97
|
+
"has multiple assemblies (the response carries `partialCompileLikely: true` " +
|
|
98
|
+
"with `asmdefCount`/`assembliesWithErrors`), the reported errors may be a " +
|
|
99
|
+
"SUBSET — the failing assembly aborted the pipeline before dependent ones were " +
|
|
100
|
+
"reached. Do NOT treat `errorCount` as the complete picture; fix the reported " +
|
|
101
|
+
"errors and re-check until `errorCount` is 0.", {
|
|
73
102
|
properties: {
|
|
74
103
|
tail_bytes: {
|
|
75
104
|
type: "integer",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-compile-errors.js","sourceRoot":"","sources":["../../src/tools/read-compile-errors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"read-compile-errors.js","sourceRoot":"","sources":["../../src/tools/read-compile-errors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,4EAA4E;AAC5E,+EAA+E;AAC/E,8EAA8E;AAC9E,2BAA2B;AAC3B,MAAM,sBAAsB,GAAG,iBAAiB,CAAC,kCAAkC,CAAC,CAAC;AACrF,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,8BAA8B,CAAC,CAAC;AAE7E,0EAA0E;AAC1E,8EAA8E;AAC9E,0EAA0E;AAC1E,+EAA+E;AAC/E,2EAA2E;AAC3E,0EAA0E;AAC1E,4EAA4E;AAC5E,yEAAyE;AACzE,+EAA+E;AAC/E,8EAA8E;AAC9E,UAAU;AACV,EAAE;AACF,2EAA2E;AAC3E,4EAA4E;AAC5E,2EAA2E;AAC3E,4EAA4E;AAC5E,4EAA4E;AAC5E,2EAA2E;AAC3E,sCAAsC;AACtC,EAAE;AACF,mBAAmB;AACnB,yEAAyE;AACzE,wEAAwE;AACxE,wEAAwE;AACxE,wEAAwE;AACxE,iEAAiE;AACjE,6DAA6D;AAC7D,uEAAuE;AACvE,wEAAwE;AACxE,wEAAwE;AACxE,6EAA6E;AAC7E,iEAAiE;AACjE,sEAAsE;AACtE,8EAA8E;AAC9E,iBAAiB;AACjB,4EAA4E;AAC5E,4EAA4E;AAC5E,8EAA8E;AAC9E,wEAAwE;AACxE,uEAAuE;AACvE,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CACvC,oCAAoC,EACpC,uEAAuE;IACrE,uEAAuE;IACvE,0DAA0D;IAC1D,mEAAmE;IACnE,6DAA6D;IAC7D,+DAA+D;IAC/D,2DAA2D;IAC3D,6DAA6D;IAC7D,4DAA4D;IAC5D,mEAAmE;IACnE,yEAAyE;IACzE,kEAAkE;IAClE,qEAAqE;IACrE,uEAAuE;IACvE,uEAAuE;IACvE,yEAAyE;IACzE,qEAAqE;IACrE,mEAAmE;IACnE,qEAAqE;IACrE,wEAAwE;IACxE,yEAAyE;IACzE,oEAAoE;IACpE,qEAAqE;IACrE,kEAAkE;IAClE,qEAAqE;IACrE,6DAA6D;IAC7D,4EAA4E;IAC5E,wEAAwE;IACxE,4EAA4E;IAC5E,uEAAuE;IACvE,qDAAqD;IACrD,uEAAuE;IACvE,2EAA2E;IAC3E,yEAAyE;IACzE,0EAA0E;IAC1E,wEAAwE;IACxE,sEAAsE;IACtE,0EAA0E;IAC1E,yDAAyD;IACzD,0EAA0E;IAC1E,yEAAyE;IACzE,qDAAqD;IACrD,2EAA2E;IAC3E,gBAAgB,sBAAsB,uBAAuB;IAC7D,0EAA0E;IAC1E,gBAAgB,kBAAkB,qCAAqC;IACvE,0DAA0D;IAC1D,gFAAgF;IAChF,6EAA6E;IAC7E,2EAA2E;IAC3E,gFAAgF;IAChF,+EAA+E;IAC/E,8CAA8C,EAChD;IACE,UAAU,EAAE;QACN,UAAU,EAAE;YACV,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,OAAO;YAChB,WAAW,EACT,6DAA6D;gBAC7D,oEAAoE;gBACpE,kEAAkE;gBAClE,mEAAmE;SACtE;KACF;CACN,CACF,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { makeTool } from "./schema-fragments.js";
|
|
2
2
|
export const regressionCheck = makeTool("unity_open_mcp_regression_check", "Compare current full scan against a baseline file. Returns exitCode 1 when the error count increase exceeds " +
|
|
3
|
-
"regression_threshold (global) or any per-category threshold,
|
|
3
|
+
"regression_threshold (global) or any per-category threshold, when the baseline is missing/invalid, or when any " +
|
|
4
|
+
"verify rule threw (rulesFailed — the scan is incomplete and the verdict covers only rules that ran clean on both sides). " +
|
|
4
5
|
"per_category_thresholds maps a ruleId to its max tolerated error-count increase; rules absent from the map " +
|
|
5
6
|
"fall back to regression_threshold. Emits a compact regression summary (with optional per-rule breakdown) " +
|
|
6
7
|
"suitable for CI logs.", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"regression-check.js","sourceRoot":"","sources":["../../src/tools/regression-check.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CACrC,iCAAiC,EACjC,8GAA8G;IAC5G,
|
|
1
|
+
{"version":3,"file":"regression-check.js","sourceRoot":"","sources":["../../src/tools/regression-check.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CACrC,iCAAiC,EACjC,8GAA8G;IAC5G,iHAAiH;IACjH,2HAA2H;IAC3H,6GAA6G;IAC7G,2GAA2G;IAC3G,uBAAuB,EACzB;IACE,QAAQ,EAAE,CAAC,eAAe,CAAC;IACvB,UAAU,EAAE;QACV,aAAa,EAAE;YACb,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,yEAAyE;SACvF;QACD,oBAAoB,EAAE;YACpB,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;YACV,WAAW,EAAE,gFAAgF;SAC9F;QACD,uBAAuB,EAAE;YACvB,IAAI,EAAE,QAAQ;YACd,oBAAoB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;YACrD,WAAW,EACT,gHAAgH;gBAChH,qGAAqG;SACxG;QACD,gBAAgB,EAAE;YAChB,IAAI,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC;YACtC,OAAO,EAAE,SAAS;SACnB;KACF;CACN,CACF,CAAC"}
|