unity-open-mcp 0.1.2 → 0.3.1
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/agent-identity.d.ts +52 -0
- package/dist/agent-identity.js +115 -0
- package/dist/agent-identity.js.map +1 -0
- package/dist/batch-spawn.d.ts +7 -0
- package/dist/batch-spawn.js +155 -29
- package/dist/batch-spawn.js.map +1 -1
- package/dist/capabilities/build-capabilities.d.ts +45 -0
- package/dist/capabilities/build-capabilities.js +262 -27
- package/dist/capabilities/build-capabilities.js.map +1 -1
- package/dist/capabilities/cost-hints.d.ts +82 -0
- package/dist/capabilities/cost-hints.js +185 -0
- package/dist/capabilities/cost-hints.js.map +1 -0
- package/dist/capabilities/lifecycle.d.ts +40 -0
- package/dist/capabilities/lifecycle.js +353 -0
- package/dist/capabilities/lifecycle.js.map +1 -0
- package/dist/capabilities/rule-catalog.d.ts +13 -1
- package/dist/capabilities/rule-catalog.js +620 -75
- package/dist/capabilities/rule-catalog.js.map +1 -1
- package/dist/capabilities/tool-groups.d.ts +21 -0
- package/dist/capabilities/tool-groups.js +411 -14
- package/dist/capabilities/tool-groups.js.map +1 -1
- package/dist/cli/args.d.ts +32 -1
- package/dist/cli/args.js +201 -4
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/cli.d.ts +21 -0
- package/dist/cli/cli.js +68 -5
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/commands.d.ts +33 -0
- package/dist/cli/commands.js +400 -0
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/exit-codes.d.ts +43 -0
- package/dist/cli/exit-codes.js +78 -0
- package/dist/cli/exit-codes.js.map +1 -0
- package/dist/compile-verify.d.ts +65 -0
- package/dist/compile-verify.js +94 -0
- package/dist/compile-verify.js.map +1 -0
- package/dist/compressible-router.js +64 -11
- package/dist/compressible-router.js.map +1 -1
- package/dist/compression/asset-model.d.ts +15 -0
- package/dist/compression/compact.d.ts +5 -4
- package/dist/compression/compact.js +13 -10
- package/dist/compression/compact.js.map +1 -1
- package/dist/dialog-dismiss.d.ts +127 -74
- package/dist/dialog-dismiss.js +427 -170
- package/dist/dialog-dismiss.js.map +1 -1
- package/dist/dialog-policy.d.ts +141 -0
- package/dist/dialog-policy.js +345 -0
- package/dist/dialog-policy.js.map +1 -0
- package/dist/gate-error.d.ts +6 -0
- package/dist/gate-error.js +13 -2
- package/dist/gate-error.js.map +1 -1
- package/dist/hub-control.d.ts +247 -0
- package/dist/hub-control.js +703 -0
- package/dist/hub-control.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +46 -12
- package/dist/index.js.map +1 -1
- package/dist/live-client.d.ts +123 -3
- package/dist/live-client.js +555 -69
- package/dist/live-client.js.map +1 -1
- package/dist/offline.d.ts +105 -0
- package/dist/offline.js +816 -23
- package/dist/offline.js.map +1 -1
- package/dist/output-profile.d.ts +110 -0
- package/dist/output-profile.js +255 -0
- package/dist/output-profile.js.map +1 -0
- package/dist/retry-policy.d.ts +72 -0
- package/dist/retry-policy.js +146 -0
- package/dist/retry-policy.js.map +1 -0
- package/dist/routers.d.ts +4 -0
- package/dist/routers.js +2 -2
- package/dist/routers.js.map +1 -1
- package/dist/server-instructions.d.ts +18 -0
- package/dist/server-instructions.js +145 -0
- package/dist/server-instructions.js.map +1 -0
- package/dist/tool-router.d.ts +38 -1
- package/dist/tool-router.js +690 -37
- package/dist/tool-router.js.map +1 -1
- package/dist/tool-session-state.d.ts +37 -0
- package/dist/tool-session-state.js +78 -1
- package/dist/tool-session-state.js.map +1 -1
- package/dist/tools/apply-fix.js +16 -2
- package/dist/tools/apply-fix.js.map +1 -1
- package/dist/tools/asmdef-create.d.ts +2 -0
- package/dist/tools/asmdef-create.js +114 -0
- package/dist/tools/asmdef-create.js.map +1 -0
- package/dist/tools/asmdef-get.d.ts +2 -0
- package/dist/tools/asmdef-get.js +31 -0
- package/dist/tools/asmdef-get.js.map +1 -0
- package/dist/tools/asmdef-list.d.ts +2 -0
- package/dist/tools/asmdef-list.js +41 -0
- package/dist/tools/asmdef-list.js.map +1 -0
- package/dist/tools/asmdef-modify.d.ts +2 -0
- package/dist/tools/asmdef-modify.js +108 -0
- package/dist/tools/asmdef-modify.js.map +1 -0
- package/dist/tools/audio-listener-get.d.ts +2 -0
- package/dist/tools/audio-listener-get.js +16 -0
- package/dist/tools/audio-listener-get.js.map +1 -0
- package/dist/tools/audio-mixer-get-parameter.d.ts +2 -0
- package/dist/tools/audio-mixer-get-parameter.js +25 -0
- package/dist/tools/audio-mixer-get-parameter.js.map +1 -0
- package/dist/tools/audio-mixer-set-parameter.d.ts +2 -0
- package/dist/tools/audio-mixer-set-parameter.js +44 -0
- package/dist/tools/audio-mixer-set-parameter.js.map +1 -0
- package/dist/tools/audio-source-add.d.ts +2 -0
- package/dist/tools/audio-source-add.js +94 -0
- package/dist/tools/audio-source-add.js.map +1 -0
- package/dist/tools/audio-source-modify.d.ts +2 -0
- package/dist/tools/audio-source-modify.js +52 -0
- package/dist/tools/audio-source-modify.js.map +1 -0
- package/dist/tools/bridge-status.js +16 -6
- package/dist/tools/bridge-status.js.map +1 -1
- package/dist/tools/build-get-active-target.js +1 -2
- package/dist/tools/build-get-active-target.js.map +1 -1
- package/dist/tools/build-get-defines.js +1 -1
- package/dist/tools/build-get-defines.js.map +1 -1
- package/dist/tools/build-get-scenes.js +1 -2
- package/dist/tools/build-get-scenes.js.map +1 -1
- package/dist/tools/build-get-targets.js +1 -1
- package/dist/tools/build-get-targets.js.map +1 -1
- package/dist/tools/build-set-defines.js +1 -2
- package/dist/tools/build-set-defines.js.map +1 -1
- package/dist/tools/build-set-scenes.js +1 -1
- package/dist/tools/build-set-scenes.js.map +1 -1
- package/dist/tools/build-set-target.js +1 -1
- package/dist/tools/build-set-target.js.map +1 -1
- package/dist/tools/build-start.js +0 -1
- package/dist/tools/build-start.js.map +1 -1
- package/dist/tools/cinemachine-brain-ensure.d.ts +2 -0
- package/dist/tools/cinemachine-brain-ensure.js +27 -0
- package/dist/tools/cinemachine-brain-ensure.js.map +1 -0
- package/dist/tools/cinemachine-camera-list.d.ts +2 -0
- package/dist/tools/cinemachine-camera-list.js +15 -0
- package/dist/tools/cinemachine-camera-list.js.map +1 -0
- package/dist/tools/cinemachine-create-camera.d.ts +2 -0
- package/dist/tools/cinemachine-create-camera.js +55 -0
- package/dist/tools/cinemachine-create-camera.js.map +1 -0
- package/dist/tools/cinemachine-set-body.d.ts +2 -0
- package/dist/tools/cinemachine-set-body.js +33 -0
- package/dist/tools/cinemachine-set-body.js.map +1 -0
- package/dist/tools/cinemachine-set-lens.d.ts +2 -0
- package/dist/tools/cinemachine-set-lens.js +41 -0
- package/dist/tools/cinemachine-set-lens.js.map +1 -0
- package/dist/tools/cinemachine-set-noise.d.ts +2 -0
- package/dist/tools/cinemachine-set-noise.js +31 -0
- package/dist/tools/cinemachine-set-noise.js.map +1 -0
- package/dist/tools/cinemachine-set-targets.d.ts +2 -0
- package/dist/tools/cinemachine-set-targets.js +30 -0
- package/dist/tools/cinemachine-set-targets.js.map +1 -0
- package/dist/tools/console-log.js +2 -2
- package/dist/tools/console-log.js.map +1 -1
- package/dist/tools/constraint-add.d.ts +2 -0
- package/dist/tools/constraint-add.js +85 -0
- package/dist/tools/constraint-add.js.map +1 -0
- package/dist/tools/dependencies.d.ts +2 -0
- package/dist/tools/dependencies.js +76 -0
- package/dist/tools/dependencies.js.map +1 -0
- package/dist/tools/editor-add-tag.js +2 -3
- package/dist/tools/editor-add-tag.js.map +1 -1
- package/dist/tools/editor-clear-history.d.ts +2 -0
- package/dist/tools/editor-clear-history.js +25 -0
- package/dist/tools/editor-clear-history.js.map +1 -0
- package/dist/tools/editor-get-layers.js +3 -3
- package/dist/tools/editor-get-layers.js.map +1 -1
- package/dist/tools/editor-get-tags.js +2 -2
- package/dist/tools/editor-get-tags.js.map +1 -1
- package/dist/tools/editor-redo.js +2 -3
- package/dist/tools/editor-redo.js.map +1 -1
- package/dist/tools/editor-undo-history.d.ts +2 -0
- package/dist/tools/editor-undo-history.js +21 -0
- package/dist/tools/editor-undo-history.js.map +1 -0
- package/dist/tools/editor-undo.js +3 -3
- package/dist/tools/editor-undo.js.map +1 -1
- package/dist/tools/editorprefs-delete.d.ts +2 -0
- package/dist/tools/editorprefs-delete.js +23 -0
- package/dist/tools/editorprefs-delete.js.map +1 -0
- package/dist/tools/editorprefs-get.d.ts +2 -0
- package/dist/tools/editorprefs-get.js +28 -0
- package/dist/tools/editorprefs-get.js.map +1 -0
- package/dist/tools/editorprefs-set.d.ts +2 -0
- package/dist/tools/editorprefs-set.js +33 -0
- package/dist/tools/editorprefs-set.js.map +1 -0
- package/dist/tools/find-references.js +24 -4
- package/dist/tools/find-references.js.map +1 -1
- package/dist/tools/frame-debugger.d.ts +2 -0
- package/dist/tools/frame-debugger.js +48 -0
- package/dist/tools/frame-debugger.js.map +1 -0
- package/dist/tools/gameobject-modify.js +69 -2
- package/dist/tools/gameobject-modify.js.map +1 -1
- package/dist/tools/gate-budget-estimate.js +2 -1
- package/dist/tools/gate-budget-estimate.js.map +1 -1
- package/dist/tools/hub-available-releases.d.ts +2 -0
- package/dist/tools/hub-available-releases.js +23 -0
- package/dist/tools/hub-available-releases.js.map +1 -0
- package/dist/tools/hub-get-install-path.d.ts +2 -0
- package/dist/tools/hub-get-install-path.js +20 -0
- package/dist/tools/hub-get-install-path.js.map +1 -0
- package/dist/tools/hub-install-editor.d.ts +2 -0
- package/dist/tools/hub-install-editor.js +47 -0
- package/dist/tools/hub-install-editor.js.map +1 -0
- package/dist/tools/hub-install-modules.d.ts +2 -0
- package/dist/tools/hub-install-modules.js +44 -0
- package/dist/tools/hub-install-modules.js.map +1 -0
- package/dist/tools/hub-list-editors.d.ts +2 -0
- package/dist/tools/hub-list-editors.js +25 -0
- package/dist/tools/hub-list-editors.js.map +1 -0
- package/dist/tools/hub-set-install-path.d.ts +2 -0
- package/dist/tools/hub-set-install-path.js +30 -0
- package/dist/tools/hub-set-install-path.js.map +1 -0
- package/dist/tools/impact-preview.js +2 -2
- package/dist/tools/impact-preview.js.map +1 -1
- package/dist/tools/index.d.ts +14 -0
- package/dist/tools/index.js +534 -24
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/light-add.d.ts +2 -0
- package/dist/tools/light-add.js +73 -0
- package/dist/tools/light-add.js.map +1 -0
- package/dist/tools/light-modify.d.ts +2 -0
- package/dist/tools/light-modify.js +36 -0
- package/dist/tools/light-modify.js.map +1 -0
- package/dist/tools/light-set.d.ts +2 -0
- package/dist/tools/light-set.js +54 -0
- package/dist/tools/light-set.js.map +1 -0
- package/dist/tools/list-assets-of-type.d.ts +2 -0
- package/dist/tools/list-assets-of-type.js +54 -0
- package/dist/tools/list-assets-of-type.js.map +1 -0
- package/dist/tools/lod-add-level.d.ts +2 -0
- package/dist/tools/lod-add-level.js +66 -0
- package/dist/tools/lod-add-level.js.map +1 -0
- package/dist/tools/lod-group-configure.d.ts +2 -0
- package/dist/tools/lod-group-configure.js +64 -0
- package/dist/tools/lod-group-configure.js.map +1 -0
- package/dist/tools/manage-tools.js +7 -5
- package/dist/tools/manage-tools.js.map +1 -1
- package/dist/tools/material-set-property.js +5 -1
- package/dist/tools/material-set-property.js.map +1 -1
- package/dist/tools/memory-snapshot-capture.d.ts +2 -0
- package/dist/tools/memory-snapshot-capture.js +61 -0
- package/dist/tools/memory-snapshot-capture.js.map +1 -0
- package/dist/tools/mutation-explain.js +2 -2
- package/dist/tools/mutation-explain.js.map +1 -1
- package/dist/tools/playerprefs-delete.d.ts +2 -0
- package/dist/tools/playerprefs-delete.js +24 -0
- package/dist/tools/playerprefs-delete.js.map +1 -0
- package/dist/tools/playerprefs-get.d.ts +2 -0
- package/dist/tools/playerprefs-get.js +28 -0
- package/dist/tools/playerprefs-get.js.map +1 -0
- package/dist/tools/playerprefs-set.d.ts +2 -0
- package/dist/tools/playerprefs-set.js +37 -0
- package/dist/tools/playerprefs-set.js.map +1 -0
- package/dist/tools/profiler-capture-frame.d.ts +2 -0
- package/dist/tools/profiler-capture-frame.js +75 -0
- package/dist/tools/profiler-capture-frame.js.map +1 -0
- package/dist/tools/profiler-clear-data.js +1 -2
- package/dist/tools/profiler-clear-data.js.map +1 -1
- package/dist/tools/profiler-enable-module.js +4 -5
- package/dist/tools/profiler-enable-module.js.map +1 -1
- package/dist/tools/profiler-get-status.js +5 -6
- package/dist/tools/profiler-get-status.js.map +1 -1
- package/dist/tools/profiler-load-data.js +4 -5
- package/dist/tools/profiler-load-data.js.map +1 -1
- package/dist/tools/profiler-save-data.js +3 -3
- package/dist/tools/profiler-save-data.js.map +1 -1
- package/dist/tools/profiler-set-config.js +5 -5
- package/dist/tools/profiler-set-config.js.map +1 -1
- package/dist/tools/profiler-start.js +4 -4
- package/dist/tools/profiler-start.js.map +1 -1
- package/dist/tools/profiler-stop.js +2 -3
- package/dist/tools/profiler-stop.js.map +1 -1
- package/dist/tools/read-asset.js +21 -3
- package/dist/tools/read-asset.js.map +1 -1
- package/dist/tools/reflection-probe-bake.d.ts +2 -0
- package/dist/tools/reflection-probe-bake.js +47 -0
- package/dist/tools/reflection-probe-bake.js.map +1 -0
- package/dist/tools/reflection-probe-get.d.ts +2 -0
- package/dist/tools/reflection-probe-get.js +19 -0
- package/dist/tools/reflection-probe-get.js.map +1 -0
- package/dist/tools/reimport-package.d.ts +2 -0
- package/dist/tools/reimport-package.js +53 -0
- package/dist/tools/reimport-package.js.map +1 -0
- package/dist/tools/scan-paths.js +19 -0
- package/dist/tools/scan-paths.js.map +1 -1
- package/dist/tools/scene-focus.js +1 -1
- package/dist/tools/scene-focus.js.map +1 -1
- package/dist/tools/scene-get-data.js +31 -13
- package/dist/tools/scene-get-data.js.map +1 -1
- package/dist/tools/scene-get-dirty-summary.js +1 -1
- package/dist/tools/scene-get-dirty-summary.js.map +1 -1
- package/dist/tools/sceneview-get-camera.d.ts +2 -0
- package/dist/tools/sceneview-get-camera.js +16 -0
- package/dist/tools/sceneview-get-camera.js.map +1 -0
- package/dist/tools/sceneview-set-camera.d.ts +2 -0
- package/dist/tools/sceneview-set-camera.js +58 -0
- package/dist/tools/sceneview-set-camera.js.map +1 -0
- package/dist/tools/script-write.js +2 -2
- package/dist/tools/script-write.js.map +1 -1
- package/dist/tools/scriptableobject-create.d.ts +2 -0
- package/dist/tools/scriptableobject-create.js +86 -0
- package/dist/tools/scriptableobject-create.js.map +1 -0
- package/dist/tools/search-assets.js +20 -3
- package/dist/tools/search-assets.js.map +1 -1
- package/dist/tools/settings-get-lighting.js +3 -4
- package/dist/tools/settings-get-lighting.js.map +1 -1
- package/dist/tools/settings-get-player.js +2 -2
- package/dist/tools/settings-get-player.js.map +1 -1
- package/dist/tools/settings-get-quality.js +1 -2
- package/dist/tools/settings-get-quality.js.map +1 -1
- package/dist/tools/settings-get-render-pipeline.d.ts +2 -0
- package/dist/tools/settings-get-render-pipeline.js +19 -0
- package/dist/tools/settings-get-render-pipeline.js.map +1 -0
- package/dist/tools/settings-get-time.d.ts +2 -0
- package/dist/tools/settings-get-time.js +18 -0
- package/dist/tools/settings-get-time.js.map +1 -0
- package/dist/tools/settings-set-lighting.js +5 -5
- package/dist/tools/settings-set-lighting.js.map +1 -1
- package/dist/tools/settings-set-physics.js +2 -2
- package/dist/tools/settings-set-physics.js.map +1 -1
- package/dist/tools/settings-set-player.js +2 -2
- package/dist/tools/settings-set-player.js.map +1 -1
- package/dist/tools/settings-set-quality-level.d.ts +2 -0
- package/dist/tools/settings-set-quality-level.js +44 -0
- package/dist/tools/settings-set-quality-level.js.map +1 -0
- package/dist/tools/settings-set-quality.js +2 -2
- package/dist/tools/settings-set-quality.js.map +1 -1
- package/dist/tools/settings-set-time.d.ts +2 -0
- package/dist/tools/settings-set-time.js +53 -0
- package/dist/tools/settings-set-time.js.map +1 -0
- package/dist/tools/shader-get-data.js +3 -3
- package/dist/tools/shader-get-data.js.map +1 -1
- package/dist/tools/shader-graph-create.d.ts +2 -0
- package/dist/tools/shader-graph-create.js +40 -0
- package/dist/tools/shader-graph-create.js.map +1 -0
- package/dist/tools/shader-graph-node-add.d.ts +2 -0
- package/dist/tools/shader-graph-node-add.js +50 -0
- package/dist/tools/shader-graph-node-add.js.map +1 -0
- package/dist/tools/shader-graph-node-connect.d.ts +2 -0
- package/dist/tools/shader-graph-node-connect.js +60 -0
- package/dist/tools/shader-graph-node-connect.js.map +1 -0
- package/dist/tools/shader-graph-open.d.ts +2 -0
- package/dist/tools/shader-graph-open.js +29 -0
- package/dist/tools/shader-graph-open.js.map +1 -0
- package/dist/tools/skybox-get.d.ts +2 -0
- package/dist/tools/skybox-get.js +13 -0
- package/dist/tools/skybox-get.js.map +1 -0
- package/dist/tools/skybox-set.d.ts +2 -0
- package/dist/tools/skybox-set.js +34 -0
- package/dist/tools/skybox-set.js.map +1 -0
- package/dist/tools/spriteatlas-add-packable.d.ts +2 -0
- package/dist/tools/spriteatlas-add-packable.js +40 -0
- package/dist/tools/spriteatlas-add-packable.js.map +1 -0
- package/dist/tools/spriteatlas-create.d.ts +2 -0
- package/dist/tools/spriteatlas-create.js +41 -0
- package/dist/tools/spriteatlas-create.js.map +1 -0
- package/dist/tools/spriteatlas-delete.d.ts +2 -0
- package/dist/tools/spriteatlas-delete.js +32 -0
- package/dist/tools/spriteatlas-delete.js.map +1 -0
- package/dist/tools/spriteatlas-get.d.ts +2 -0
- package/dist/tools/spriteatlas-get.js +23 -0
- package/dist/tools/spriteatlas-get.js.map +1 -0
- package/dist/tools/spriteatlas-list.d.ts +2 -0
- package/dist/tools/spriteatlas-list.js +21 -0
- package/dist/tools/spriteatlas-list.js.map +1 -0
- package/dist/tools/spriteatlas-modify.d.ts +2 -0
- package/dist/tools/spriteatlas-modify.js +55 -0
- package/dist/tools/spriteatlas-modify.js.map +1 -0
- package/dist/tools/spriteatlas-remove-packable.d.ts +2 -0
- package/dist/tools/spriteatlas-remove-packable.js +39 -0
- package/dist/tools/spriteatlas-remove-packable.js.map +1 -0
- package/dist/tools/terrain-create.d.ts +2 -0
- package/dist/tools/terrain-create.js +73 -0
- package/dist/tools/terrain-create.js.map +1 -0
- package/dist/tools/terrain-paint-layer.d.ts +2 -0
- package/dist/tools/terrain-paint-layer.js +85 -0
- package/dist/tools/terrain-paint-layer.js.map +1 -0
- package/dist/tools/terrain-place-trees.d.ts +2 -0
- package/dist/tools/terrain-place-trees.js +92 -0
- package/dist/tools/terrain-place-trees.js.map +1 -0
- package/dist/tools/terrain-set-heights.d.ts +2 -0
- package/dist/tools/terrain-set-heights.js +68 -0
- package/dist/tools/terrain-set-heights.js.map +1 -0
- package/dist/tools/terrain-set-neighbors.d.ts +2 -0
- package/dist/tools/terrain-set-neighbors.js +65 -0
- package/dist/tools/terrain-set-neighbors.js.map +1 -0
- package/dist/tools/texture-get-importer.d.ts +2 -0
- package/dist/tools/texture-get-importer.js +25 -0
- package/dist/tools/texture-get-importer.js.map +1 -0
- package/dist/tools/texture-get.d.ts +2 -0
- package/dist/tools/texture-get.js +23 -0
- package/dist/tools/texture-get.js.map +1 -0
- package/dist/tools/texture-reimport.d.ts +2 -0
- package/dist/tools/texture-reimport.js +33 -0
- package/dist/tools/texture-reimport.js.map +1 -0
- package/dist/tools/texture-set-import.d.ts +2 -0
- package/dist/tools/texture-set-import.js +52 -0
- package/dist/tools/texture-set-import.js.map +1 -0
- package/dist/tools/tilemap-box-fill.d.ts +2 -0
- package/dist/tools/tilemap-box-fill.js +32 -0
- package/dist/tools/tilemap-box-fill.js.map +1 -0
- package/dist/tools/tilemap-create-rule-tile.d.ts +2 -0
- package/dist/tools/tilemap-create-rule-tile.js +39 -0
- package/dist/tools/tilemap-create-rule-tile.js.map +1 -0
- package/dist/tools/tilemap-create-tile-asset.d.ts +2 -0
- package/dist/tools/tilemap-create-tile-asset.js +35 -0
- package/dist/tools/tilemap-create-tile-asset.js.map +1 -0
- package/dist/tools/tilemap-create.d.ts +2 -0
- package/dist/tools/tilemap-create.js +32 -0
- package/dist/tools/tilemap-create.js.map +1 -0
- package/dist/tools/tilemap-set-tile.d.ts +2 -0
- package/dist/tools/tilemap-set-tile.js +33 -0
- package/dist/tools/tilemap-set-tile.js.map +1 -0
- package/dist/tools/timeline-clip-add.d.ts +2 -0
- package/dist/tools/timeline-clip-add.js +43 -0
- package/dist/tools/timeline-clip-add.js.map +1 -0
- package/dist/tools/timeline-create.d.ts +2 -0
- package/dist/tools/timeline-create.js +32 -0
- package/dist/tools/timeline-create.js.map +1 -0
- package/dist/tools/timeline-director-bind.d.ts +2 -0
- package/dist/tools/timeline-director-bind.js +34 -0
- package/dist/tools/timeline-director-bind.js.map +1 -0
- package/dist/tools/timeline-modify.d.ts +2 -0
- package/dist/tools/timeline-modify.js +44 -0
- package/dist/tools/timeline-modify.js.map +1 -0
- package/dist/tools/timeline-track-add.d.ts +2 -0
- package/dist/tools/timeline-track-add.js +37 -0
- package/dist/tools/timeline-track-add.js.map +1 -0
- package/dist/tools/ui-canvas-add.d.ts +2 -0
- package/dist/tools/ui-canvas-add.js +66 -0
- package/dist/tools/ui-canvas-add.js.map +1 -0
- package/dist/tools/ui-element-add.d.ts +2 -0
- package/dist/tools/ui-element-add.js +65 -0
- package/dist/tools/ui-element-add.js.map +1 -0
- package/dist/tools/ui-element-modify.d.ts +2 -0
- package/dist/tools/ui-element-modify.js +59 -0
- package/dist/tools/ui-element-modify.js.map +1 -0
- package/dist/tools/ui-layout-group-add.d.ts +2 -0
- package/dist/tools/ui-layout-group-add.js +80 -0
- package/dist/tools/ui-layout-group-add.js.map +1 -0
- package/dist/tools/validate-edit.js +22 -1
- package/dist/tools/validate-edit.js.map +1 -1
- package/dist/tools/vfx-block-edit.d.ts +2 -0
- package/dist/tools/vfx-block-edit.js +51 -0
- package/dist/tools/vfx-block-edit.js.map +1 -0
- package/dist/tools/vfx-list.d.ts +2 -0
- package/dist/tools/vfx-list.js +31 -0
- package/dist/tools/vfx-list.js.map +1 -0
- package/dist/tools/vfx-open.d.ts +2 -0
- package/dist/tools/vfx-open.js +29 -0
- package/dist/tools/vfx-open.js.map +1 -0
- package/package.json +1 -1
package/dist/dialog-dismiss.js
CHANGED
|
@@ -1,43 +1,60 @@
|
|
|
1
|
-
// M13 T4.5
|
|
1
|
+
// M13 T4.5 + M23 Plan 2 — Unity startup dialog auto-dismissal.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
// today (UCP bridge-wait pattern).
|
|
3
|
+
// M13 T4.5 shipped the single highest-frequency case: the launch-errors /
|
|
4
|
+
// Safe Mode dialog, dismissed with a hard-coded "Ignore" click. M23 Plan 2
|
|
5
|
+
// extends this with UCP's 6-variant dialog policy taxonomy so different
|
|
6
|
+
// automation workflows can pick different buttons on the SAME dialog, and
|
|
7
|
+
// adds the three remaining startup modals (Non-Matching Editor, Project
|
|
8
|
+
// Upgrade Required, Auto Graphics API Notice).
|
|
10
9
|
//
|
|
11
|
-
// Design
|
|
12
|
-
// -
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// -
|
|
16
|
-
//
|
|
10
|
+
// Design:
|
|
11
|
+
// - Policy taxonomy: UNITY_OPEN_MCP_DIALOG_POLICY=auto|manual|ignore|
|
|
12
|
+
// recover|safe-mode|cancel (default `ignore` — preserves T4.5). See
|
|
13
|
+
// dialog-policy.ts for the pure tables.
|
|
14
|
+
// - Per-kind-per-policy button preference tables (port of UCP
|
|
15
|
+
// `preferred_dialog_button_label`).
|
|
16
|
+
// - Project Upgrade is NEVER auto-confirmed unless the dedicated opt-in
|
|
17
|
+
// UNITY_OPEN_MCP_ALLOW_PROJECT_UPGRADE=1 is set; otherwise the probe
|
|
18
|
+
// reports a `blocked` outcome + audit line (no click).
|
|
17
19
|
// - Cross-platform: Windows (Win32/PowerShell), macOS (AppleScript),
|
|
18
|
-
// Linux/X11 (xdotool).
|
|
20
|
+
// Linux/X11 (xdotool). UCP's non-Windows dismiss is a no-op stub; we
|
|
21
|
+
// follow Unity-MCP's working macOS/Linux base instead.
|
|
19
22
|
//
|
|
20
23
|
// No runtime deps beyond node builtins (mcp-server/AGENTS.md "no runtime
|
|
21
24
|
// deps beyond MCP SDK"): only child_process and os.
|
|
22
25
|
import { execFile, execFileSync } from "node:child_process";
|
|
23
26
|
import { platform as nodePlatform } from "node:os";
|
|
27
|
+
import { DIALOG_TITLE_FRAGMENTS, parseDialogPolicy, preferenceTokensForPolicy, genericFallbackTokens, blockedKindsForPolicy, } from "./dialog-policy.js";
|
|
24
28
|
/**
|
|
25
29
|
* Window-title fragments matched against the Unity launch-errors dialog.
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
30
|
+
* Kept as the M13 T4.5 back-compat export (the launch-errors subset of
|
|
31
|
+
* {@link DIALOG_TITLE_FRAGMENTS}); the generalized matcher now consults the
|
|
32
|
+
* full per-kind table via {@link classifyDialogTitle}.
|
|
29
33
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
34
|
+
* Both legacy and current strings are listed so the matcher stays resilient
|
|
35
|
+
* across Unity versions. The match is case-insensitive and substring-based.
|
|
36
|
+
*/
|
|
37
|
+
export const LAUNCH_ERROR_DIALOG_TITLE_FRAGMENTS = DIALOG_TITLE_FRAGMENTS.launch_errors.map((f) =>
|
|
38
|
+
// Restore the human-readable spelling T4.5 tests assert against ("Safe
|
|
39
|
+
// Mode", "Compiler Errors", …). classifyDialogTitle normalizes both
|
|
40
|
+
// directions, so this stays a faithful superset.
|
|
41
|
+
f === "entersafemode"
|
|
42
|
+
? "Safe Mode"
|
|
43
|
+
: f === "scripthavecompilererrors"
|
|
44
|
+
? "Scripts have compiler errors"
|
|
45
|
+
: f === "compilererrors"
|
|
46
|
+
? "Compiler Errors"
|
|
47
|
+
: f === "holdon"
|
|
48
|
+
? "Hold On"
|
|
49
|
+
: f === "compileerrors"
|
|
50
|
+
? "Compile Errors"
|
|
51
|
+
: f);
|
|
52
|
+
/**
|
|
53
|
+
* The button label this helper presses to dismiss the launch-errors dialog
|
|
54
|
+
* under the default (`ignore`) policy. Preserved from M13 T4.5 for back-compat
|
|
55
|
+
* with tests and any external references; the generalized path now selects
|
|
56
|
+
* the button via {@link preferenceTokensForPolicy}.
|
|
32
57
|
*/
|
|
33
|
-
export const LAUNCH_ERROR_DIALOG_TITLE_FRAGMENTS = [
|
|
34
|
-
"Safe Mode", // Unity 2020.2+ ("Enter Safe Mode?") — the launch-errors dialog on every modern Unity (2022 LTS, 6000.x)
|
|
35
|
-
"Compiler Errors", // Unity 2020+ ("Hold On" + "Compiler Errors on Launch")
|
|
36
|
-
"Hold On", // Generic Unity progress dialog wrapping the launch-errors variant
|
|
37
|
-
"Compile Errors", // Older Unity dialog spelling
|
|
38
|
-
"Scripts have compiler errors", // Unity 2022+ on Linux (window manager surfacing)
|
|
39
|
-
];
|
|
40
|
-
/** The button label this helper presses to dismiss the dialog. */
|
|
41
58
|
export const DISMISS_BUTTON_LABEL = "Ignore";
|
|
42
59
|
/**
|
|
43
60
|
* Producer-side prefixes for error messages that callers treat as permanent
|
|
@@ -45,72 +62,116 @@ export const DISMISS_BUTTON_LABEL = "Ignore";
|
|
|
45
62
|
* bailout matcher references the SAME literal as the producers.
|
|
46
63
|
*/
|
|
47
64
|
export const LINUX_XDOTOOL_MISSING_PREFIX = "xdotool not found on PATH";
|
|
48
|
-
export const UNSUPPORTED_PLATFORM_PREFIX = "Unsupported platform for
|
|
65
|
+
export const UNSUPPORTED_PLATFORM_PREFIX = "Unsupported platform for Unity startup-dialog auto-dismiss";
|
|
49
66
|
/**
|
|
50
|
-
* Try once to find and dismiss
|
|
51
|
-
*
|
|
52
|
-
*
|
|
67
|
+
* Try once to find and dismiss a Unity startup dialog on the current OS
|
|
68
|
+
* desktop. Pure-ish — performs OS calls and returns; never blocks past the
|
|
69
|
+
* underlying syscall's own timeout.
|
|
53
70
|
*
|
|
54
71
|
* Library-safe: never throws (errors are returned in the `DismissOutcome`
|
|
55
72
|
* union), never writes to stdout/stderr, never mutates global state.
|
|
56
73
|
*
|
|
57
|
-
*
|
|
58
|
-
* - **Windows**: Win32 (`EnumWindows` / `EnumChildWindows` /
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* this out so the user does not waste time debugging.
|
|
74
|
+
* Platform-dispatched:
|
|
75
|
+
* - **Windows**: Win32 (`EnumWindows` / `EnumChildWindows` / `GetWindowTextW`
|
|
76
|
+
* / `SendMessageW(BM_CLICK)`) via PowerShell — no native node-gyp dep.
|
|
77
|
+
* - **macOS**: AppleScript via `osascript`. Clicks a named button per the
|
|
78
|
+
* policy token table (requires Accessibility perm once).
|
|
79
|
+
* - **Linux/X11**: `xdotool`. Wayland is unsupported — the error message
|
|
80
|
+
* calls this out so the user does not waste time debugging.
|
|
65
81
|
*/
|
|
66
|
-
export async function
|
|
67
|
-
switch (platform) {
|
|
82
|
+
export async function tryDismissDialog(opts) {
|
|
83
|
+
switch (opts.platform) {
|
|
68
84
|
case "win32":
|
|
69
|
-
return tryDismissWindows();
|
|
85
|
+
return tryDismissWindows(opts);
|
|
70
86
|
case "darwin":
|
|
71
|
-
return tryDismissMacOS();
|
|
87
|
+
return tryDismissMacOS(opts);
|
|
72
88
|
case "linux":
|
|
73
|
-
return tryDismissLinuxX11();
|
|
89
|
+
return tryDismissLinuxX11(opts);
|
|
74
90
|
default:
|
|
75
91
|
return {
|
|
76
92
|
kind: "error",
|
|
77
|
-
message: `${UNSUPPORTED_PLATFORM_PREFIX}: ${platform}`,
|
|
93
|
+
message: `${UNSUPPORTED_PLATFORM_PREFIX}: ${opts.platform}`,
|
|
78
94
|
};
|
|
79
95
|
}
|
|
80
96
|
}
|
|
81
97
|
// ---------------------------------------------------------------------------
|
|
98
|
+
// Token-table serialization (shared by all three platform scripts)
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
/**
|
|
101
|
+
* Serialize the per-kind token table + blocked-kinds set into a compact JSON
|
|
102
|
+
* blob embedded in the platform scripts. The script classifies each candidate
|
|
103
|
+
* window title (after normalizing it the same way {@link normalizeDialogLabel}
|
|
104
|
+
* does) and either clicks the first matching token or reports `blocked`.
|
|
105
|
+
*
|
|
106
|
+
* Shape (kept narrow so the PowerShell / AppleScript parsers stay simple):
|
|
107
|
+
* {
|
|
108
|
+
* kinds: {
|
|
109
|
+
* "<kind>": { fragments: string[], tokens: string[] | null }
|
|
110
|
+
* },
|
|
111
|
+
* blocked: ["<kind>", ...],
|
|
112
|
+
* genericTokens: string[] // for unknown titles
|
|
113
|
+
* }
|
|
114
|
+
*
|
|
115
|
+
* `tokens: null` means "this policy declines this kind" (manual, or a kind
|
|
116
|
+
* the policy has no safe button for). The script reports `blocked` for kinds
|
|
117
|
+
* in the `blocked` list and `not-found` for `tokens: null` kinds that are not
|
|
118
|
+
* blocked.
|
|
119
|
+
*/
|
|
120
|
+
function buildTokenTable(opts) {
|
|
121
|
+
const kinds = {};
|
|
122
|
+
for (const kind of Object.keys(DIALOG_TITLE_FRAGMENTS)) {
|
|
123
|
+
const tokens = preferenceTokensForPolicy(kind, opts.policy, opts.allowProjectUpgrade);
|
|
124
|
+
kinds[kind] = {
|
|
125
|
+
fragments: [...DIALOG_TITLE_FRAGMENTS[kind]],
|
|
126
|
+
tokens: tokens === null ? null : [...tokens],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
kinds,
|
|
131
|
+
blocked: [...blockedKindsForPolicy(opts.policy, opts.allowProjectUpgrade)],
|
|
132
|
+
genericTokens: [...genericFallbackTokens(opts.policy)],
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
82
136
|
// Windows — Win32 via PowerShell
|
|
83
137
|
// ---------------------------------------------------------------------------
|
|
84
138
|
/**
|
|
85
|
-
* The PowerShell payload that probes for
|
|
86
|
-
*
|
|
139
|
+
* The PowerShell payload that probes for any Unity startup dialog and clicks
|
|
140
|
+
* the policy-selected button. Exported as a string (not a function) so tests
|
|
87
141
|
* can assert the script shape without launching PowerShell.
|
|
88
142
|
*
|
|
89
143
|
* Strategy:
|
|
90
144
|
* 1. P/Invoke `EnumWindows` to enumerate every visible top-level window
|
|
91
145
|
* owned by `Unity.exe`.
|
|
92
|
-
* 2.
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
146
|
+
* 2. For each, normalize the title (alphanumeric lowercase) and match it
|
|
147
|
+
* against the embedded per-kind fragment table to classify it.
|
|
148
|
+
* 3. If the kind is in the blocked list → emit `blocked:<kind>` and skip
|
|
149
|
+
* the click. If the kind's token list is null → skip (not-found).
|
|
150
|
+
* 4. Walk child windows with `EnumChildWindows`, find a Button whose
|
|
151
|
+
* normalized text contains one of the policy tokens (first match wins),
|
|
152
|
+
* and send `BM_CLICK` (0x00F5). Preferred over a synthesised mouse event
|
|
153
|
+
* — works even if the user is mid-click in another app, no focus steal.
|
|
154
|
+
* 5. Unknown titles fall back to the generic per-policy token list.
|
|
98
155
|
*
|
|
99
|
-
* The script writes a single-token result to stdout:
|
|
100
|
-
* - `dismissed:<button>` on success
|
|
101
|
-
* - `
|
|
156
|
+
* The script writes a single-token result to stdout (last non-empty line):
|
|
157
|
+
* - `dismissed:<button>:<kind>` on success
|
|
158
|
+
* - `blocked:<kind>` when a dialog was found but the policy declines
|
|
159
|
+
* - `not-found` when no dismissable dialog was matched
|
|
102
160
|
* - `error:<message>` on an unexpected exception
|
|
161
|
+
*
|
|
162
|
+
* The token table is passed via stdin (one JSON blob) so the script body
|
|
163
|
+
* stays constant and testable; embedding it inline would bloat the assertion.
|
|
103
164
|
*/
|
|
104
165
|
export const WINDOWS_DISMISS_PS_SCRIPT = `
|
|
105
166
|
$ErrorActionPreference = 'Stop'
|
|
106
167
|
try {
|
|
107
|
-
if (-not ([System.Management.Automation.PSTypeName]'UnityOpenMcp.
|
|
168
|
+
if (-not ([System.Management.Automation.PSTypeName]'UnityOpenMcp.Dialogs.Dismisser').Type) {
|
|
108
169
|
Add-Type -TypeDefinition @"
|
|
109
170
|
using System;
|
|
110
171
|
using System.Collections.Generic;
|
|
111
172
|
using System.Runtime.InteropServices;
|
|
112
173
|
using System.Text;
|
|
113
|
-
namespace UnityOpenMcp.
|
|
174
|
+
namespace UnityOpenMcp.Dialogs {
|
|
114
175
|
public static class Dismisser {
|
|
115
176
|
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
|
|
116
177
|
[DllImport("user32.dll")] static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
|
|
@@ -121,12 +182,20 @@ namespace UnityOpenMcp.LaunchErrors {
|
|
|
121
182
|
[DllImport("user32.dll")] static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
|
|
122
183
|
[DllImport("user32.dll", CharSet=CharSet.Unicode)] static extern IntPtr SendMessageW(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
|
|
123
184
|
const uint BM_CLICK = 0x00F5;
|
|
124
|
-
static
|
|
125
|
-
|
|
126
|
-
|
|
185
|
+
static string Norm(string s) {
|
|
186
|
+
var sb = new StringBuilder(s.Length);
|
|
187
|
+
foreach (var ch in s) {
|
|
188
|
+
if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) {
|
|
189
|
+
sb.Append(char.ToLowerInvariant(ch));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return sb.ToString();
|
|
193
|
+
}
|
|
194
|
+
public static string TryDismiss(int[] unityPids, string tableJson) {
|
|
127
195
|
var unityPidSet = new HashSet<uint>();
|
|
128
196
|
for (int i = 0; i < unityPids.Length; i++) unityPidSet.Add((uint)unityPids[i]);
|
|
129
|
-
|
|
197
|
+
var table = System.Text.Json.JsonSerializer.Deserialize<Types.Table>(tableJson);
|
|
198
|
+
var candidates = new List<IntPtr>();
|
|
130
199
|
var sb = new StringBuilder(512);
|
|
131
200
|
EnumWindows((hWnd, lParam) => {
|
|
132
201
|
if (!IsWindowVisible(hWnd)) return true;
|
|
@@ -134,35 +203,50 @@ namespace UnityOpenMcp.LaunchErrors {
|
|
|
134
203
|
if (!unityPidSet.Contains(procId)) return true;
|
|
135
204
|
sb.Length = 0;
|
|
136
205
|
GetWindowTextW(hWnd, sb, sb.Capacity);
|
|
137
|
-
|
|
138
|
-
foreach (var frag in TitleFragments) {
|
|
139
|
-
if (text.IndexOf(frag, StringComparison.OrdinalIgnoreCase) >= 0) {
|
|
140
|
-
matchedDialog = hWnd;
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
206
|
+
candidates.Add(hWnd);
|
|
144
207
|
return true;
|
|
145
208
|
}, IntPtr.Zero);
|
|
146
|
-
|
|
147
|
-
IntPtr matchedButton = IntPtr.Zero;
|
|
148
|
-
EnumChildWindows(matchedDialog, (hWnd, lParam) => {
|
|
149
|
-
sb.Length = 0;
|
|
150
|
-
GetClassNameW(hWnd, sb, sb.Capacity);
|
|
151
|
-
if (sb.ToString() != "Button") return true;
|
|
209
|
+
foreach (var hWnd in candidates) {
|
|
152
210
|
sb.Length = 0;
|
|
153
211
|
GetWindowTextW(hWnd, sb, sb.Capacity);
|
|
154
|
-
var
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
212
|
+
var title = sb.ToString();
|
|
213
|
+
var norm = Norm(title);
|
|
214
|
+
string kind = null;
|
|
215
|
+
foreach (var kv in table.kinds) {
|
|
216
|
+
foreach (var frag in kv.Value.fragments) {
|
|
217
|
+
if (norm.Contains(frag)) { kind = kv.Key; break; }
|
|
159
218
|
}
|
|
219
|
+
if (kind != null) break;
|
|
160
220
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
221
|
+
string[] tokens = null;
|
|
222
|
+
if (kind != null) {
|
|
223
|
+
if (table.blocked.Contains(kind)) return "blocked:" + kind;
|
|
224
|
+
if (!table.kinds[kind].tokensSpecified) continue;
|
|
225
|
+
tokens = table.kinds[kind].tokens;
|
|
226
|
+
} else {
|
|
227
|
+
if (table.genericTokens.Length == 0) continue;
|
|
228
|
+
tokens = table.genericTokens;
|
|
229
|
+
}
|
|
230
|
+
IntPtr matchedButton = IntPtr.Zero;
|
|
231
|
+
string matchedText = null;
|
|
232
|
+
EnumChildWindows(hWnd, (hChild, lParam) => {
|
|
233
|
+
sb.Length = 0;
|
|
234
|
+
GetClassNameW(hChild, sb, sb.Capacity);
|
|
235
|
+
if (sb.ToString() != "Button") return true;
|
|
236
|
+
sb.Length = 0;
|
|
237
|
+
GetWindowTextW(hChild, sb, sb.Capacity);
|
|
238
|
+
var text = sb.ToString();
|
|
239
|
+
var textNorm = Norm(text);
|
|
240
|
+
foreach (var token in tokens) {
|
|
241
|
+
if (textNorm.Contains(token)) { matchedButton = hChild; matchedText = text; return false; }
|
|
242
|
+
}
|
|
243
|
+
return true;
|
|
244
|
+
}, IntPtr.Zero);
|
|
245
|
+
if (matchedButton == IntPtr.Zero) continue;
|
|
246
|
+
SendMessageW(matchedButton, BM_CLICK, IntPtr.Zero, IntPtr.Zero);
|
|
247
|
+
return "dismissed:" + matchedText + ":" + (kind ?? "unknown");
|
|
248
|
+
}
|
|
249
|
+
return "not-found";
|
|
166
250
|
}
|
|
167
251
|
}
|
|
168
252
|
}
|
|
@@ -170,39 +254,87 @@ namespace UnityOpenMcp.LaunchErrors {
|
|
|
170
254
|
}
|
|
171
255
|
$unityPids = @(Get-Process -Name 'Unity' -ErrorAction SilentlyContinue | ForEach-Object { [int]$_.Id })
|
|
172
256
|
if ($unityPids.Count -eq 0) { Write-Output 'not-found'; return }
|
|
173
|
-
|
|
257
|
+
$tableJson = [Console]::In.ReadToEnd();
|
|
258
|
+
Write-Output ([UnityOpenMcp.Dialogs.Dismisser]::TryDismiss([int[]]$unityPids, $tableJson))
|
|
174
259
|
} catch {
|
|
175
260
|
Write-Output ('error:' + $_.Exception.Message)
|
|
176
261
|
}
|
|
177
262
|
`;
|
|
178
|
-
|
|
263
|
+
// JSON shape the PowerShell script deserializes. System.Text.Json requires
|
|
264
|
+
// parameterless ctors + settable props; the `tokensSpecified` flag lets the
|
|
265
|
+
// C# distinguish "null tokens" (decline) from "empty tokens".
|
|
266
|
+
// (Kept in a comment because the C# lives inside the PS string above; this
|
|
267
|
+
// documents the contract for the table-builder + tests.)
|
|
268
|
+
async function tryDismissWindows(opts) {
|
|
269
|
+
const table = buildTokenTable(opts);
|
|
270
|
+
// The C# uses System.Text.Json which serializes `null` arrays as missing
|
|
271
|
+
// properties unless we mark them nullable. Mirror the C# contract: emit
|
|
272
|
+
// `tokens: []` for null-token (decline) kinds so tokensSpecified=false
|
|
273
|
+
// maps cleanly. The blocked list already covers the genuine declines.
|
|
274
|
+
const payload = JSON.stringify({
|
|
275
|
+
kinds: Object.fromEntries(Object.entries(table.kinds).map(([k, v]) => [
|
|
276
|
+
k,
|
|
277
|
+
{ fragments: v.fragments, tokens: v.tokens ?? [] },
|
|
278
|
+
])),
|
|
279
|
+
blocked: table.blocked,
|
|
280
|
+
genericTokens: table.genericTokens,
|
|
281
|
+
});
|
|
179
282
|
return new Promise((resolve) => {
|
|
180
|
-
execFile("powershell", ["-NoProfile", "-NonInteractive", "-Command", WINDOWS_DISMISS_PS_SCRIPT], { timeout: 5000, windowsHide: true }, (err, stdout) => {
|
|
283
|
+
const child = execFile("powershell", ["-NoProfile", "-NonInteractive", "-Command", WINDOWS_DISMISS_PS_SCRIPT], { timeout: 5000, windowsHide: true }, (err, stdout) => {
|
|
181
284
|
if (err) {
|
|
182
|
-
// ETIMEDOUT, ENOENT (powershell missing), etc. Treat as transient.
|
|
183
285
|
resolve({ kind: "error", message: err.message });
|
|
184
286
|
return;
|
|
185
287
|
}
|
|
186
288
|
resolve(parseDismissOutput(stdout));
|
|
187
289
|
});
|
|
290
|
+
// Pipe the token table via stdin.
|
|
291
|
+
if (child.stdin) {
|
|
292
|
+
child.stdin.end(payload);
|
|
293
|
+
}
|
|
188
294
|
});
|
|
189
295
|
}
|
|
190
296
|
// ---------------------------------------------------------------------------
|
|
191
297
|
// macOS — AppleScript via osascript
|
|
192
298
|
// ---------------------------------------------------------------------------
|
|
193
299
|
/**
|
|
194
|
-
* The AppleScript
|
|
195
|
-
*
|
|
300
|
+
* The AppleScript template used for the macOS dismiss path. Exposed as a
|
|
301
|
+
* function of the token table so tests can assert the script shape without
|
|
302
|
+
* launching osascript.
|
|
196
303
|
*
|
|
197
|
-
* Strategy: iterate every window of the Unity
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
304
|
+
* Strategy: iterate every window of the Unity process, normalize its title,
|
|
305
|
+
* classify it against the table, and click the first button whose normalized
|
|
306
|
+
* label contains a policy token. If the kind is blocked, emit `blocked:<kind>`
|
|
307
|
+
* without clicking. If Unity is not running OR no matching button exists, the
|
|
308
|
+
* script reports `not-found`. Any AppleScript exception (e.g. Accessibility
|
|
309
|
+
* permission not granted) is reported as `error:<msg>`.
|
|
201
310
|
*
|
|
202
311
|
* Requires the Terminal / `node` binary to have been granted Accessibility
|
|
203
312
|
* permission in System Settings → Privacy & Security → Accessibility.
|
|
313
|
+
*
|
|
314
|
+
* The token table is JSON-escaped into the script header.
|
|
204
315
|
*/
|
|
205
|
-
export
|
|
316
|
+
export function macosDismissAppleScript(opts) {
|
|
317
|
+
// The macOS path cannot do per-button selection as precisely as the Windows
|
|
318
|
+
// path (AppleScript's named-button click works but is brittle across
|
|
319
|
+
// Unity versions); instead it classifies the window title and presses
|
|
320
|
+
// Return to click the FOCUSED (default) button — which under the default /
|
|
321
|
+
// auto / ignore / recover policies IS the safe choice (Ignore on
|
|
322
|
+
// launch-errors, Continue on non-matching-editor, OK on auto-graphics-api).
|
|
323
|
+
// Project Upgrade is detected and reported as `blocked` (never Return-clicked
|
|
324
|
+
// without the explicit opt-in). The token table from buildTokenTable is
|
|
325
|
+
// consulted only to decide whether the policy declines a kind entirely
|
|
326
|
+
// (manual / safe-mode on a kind with no safe button → no click, not-found);
|
|
327
|
+
// when it declines, the script returns not-found for that kind.
|
|
328
|
+
const launchFrags = DIALOG_TITLE_FRAGMENTS.launch_errors;
|
|
329
|
+
const nonMatchFrags = DIALOG_TITLE_FRAGMENTS.non_matching_editor;
|
|
330
|
+
const graphicsFrags = DIALOG_TITLE_FRAGMENTS.auto_graphics_api;
|
|
331
|
+
// Whether the active policy dismisses each safe kind at all. Under manual,
|
|
332
|
+
// or safe-mode on non_matching/auto_graphics (no safe button), the loop
|
|
333
|
+
// should NOT click — return not-found so polling continues.
|
|
334
|
+
const dismissesLaunch = preferenceTokensForPolicy("launch_errors", opts.policy, opts.allowProjectUpgrade) !== null;
|
|
335
|
+
const dismissesNonMatch = preferenceTokensForPolicy("non_matching_editor", opts.policy, opts.allowProjectUpgrade) !== null;
|
|
336
|
+
const dismissesGraphics = preferenceTokensForPolicy("auto_graphics_api", opts.policy, opts.allowProjectUpgrade) !== null;
|
|
337
|
+
return `
|
|
206
338
|
on run
|
|
207
339
|
try
|
|
208
340
|
tell application "System Events"
|
|
@@ -212,11 +344,18 @@ on run
|
|
|
212
344
|
tell process "Unity"
|
|
213
345
|
repeat with w in windows
|
|
214
346
|
try
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
end if
|
|
347
|
+
set wt to (title of w) as text
|
|
348
|
+
on error
|
|
349
|
+
set wt to ""
|
|
219
350
|
end try
|
|
351
|
+
-- Project Upgrade: NEVER click without the explicit opt-in, even
|
|
352
|
+
-- though the focused button is usually Confirm. Report blocked.
|
|
353
|
+
if (wt contains "Upgrade") and (wt contains "Project") then
|
|
354
|
+
return "blocked:" & "project_upgrade"
|
|
355
|
+
end if
|
|
356
|
+
${launchFrags.map((f) => fragmentCheck(f, "launch_errors", dismissesLaunch)).join("\n ")}
|
|
357
|
+
${nonMatchFrags.map((f) => fragmentCheck(f, "non_matching_editor", dismissesNonMatch)).join("\n ")}
|
|
358
|
+
${graphicsFrags.map((f) => fragmentCheck(f, "auto_graphics_api", dismissesGraphics)).join("\n ")}
|
|
220
359
|
end repeat
|
|
221
360
|
end tell
|
|
222
361
|
end tell
|
|
@@ -226,9 +365,41 @@ on run
|
|
|
226
365
|
end try
|
|
227
366
|
end run
|
|
228
367
|
`;
|
|
229
|
-
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Build the per-fragment AppleScript check block. When the policy dismisses
|
|
371
|
+
* the kind, the block activates the window + presses Return and returns the
|
|
372
|
+
* dismissed token; when the policy declines the kind (null tokens), the block
|
|
373
|
+
* is omitted entirely (the loop falls through to the next fragment).
|
|
374
|
+
*
|
|
375
|
+
* AppleScript `contains` is case-insensitive by default, so the lowercased
|
|
376
|
+
* fragment matches Unity's mixed-case titles ("Enter Safe Mode?" contains
|
|
377
|
+
* "entersafemode" → false, BUT "safemode" matches; the fragment list is built
|
|
378
|
+
* to have at least one case-insensitive hit per title).
|
|
379
|
+
*/
|
|
380
|
+
function fragmentCheck(fragment, kind, dismisses) {
|
|
381
|
+
if (!dismisses)
|
|
382
|
+
return `-- policy declines ${kind}; skip`;
|
|
383
|
+
return `if wt contains "${fragment}" then
|
|
384
|
+
set frontmost to true
|
|
385
|
+
key code 36
|
|
386
|
+
return "dismissed:Focus:${kind}"
|
|
387
|
+
end if`;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Kept for M13 T4.5 back-compat — the original launch-errors-only AppleScript
|
|
391
|
+
* constant some external tests reference. Delegates to the generalized
|
|
392
|
+
* template under the default policy.
|
|
393
|
+
* @deprecated Use {@link macosDismissAppleScript} instead.
|
|
394
|
+
*/
|
|
395
|
+
export const MACOS_DISMISS_APPLESCRIPT = macosDismissAppleScript({
|
|
396
|
+
platform: "darwin",
|
|
397
|
+
policy: "ignore",
|
|
398
|
+
allowProjectUpgrade: false,
|
|
399
|
+
});
|
|
400
|
+
async function tryDismissMacOS(opts) {
|
|
230
401
|
return new Promise((resolve) => {
|
|
231
|
-
execFile("osascript", ["-e",
|
|
402
|
+
execFile("osascript", ["-e", macosDismissAppleScript(opts)], { timeout: 5000 }, (err, stdout) => {
|
|
232
403
|
if (err) {
|
|
233
404
|
resolve({ kind: "error", message: err.message });
|
|
234
405
|
return;
|
|
@@ -296,66 +467,103 @@ function getUnityPidsLinux() {
|
|
|
296
467
|
return [];
|
|
297
468
|
}
|
|
298
469
|
}
|
|
299
|
-
async function tryDismissLinuxX11() {
|
|
470
|
+
async function tryDismissLinuxX11(opts) {
|
|
300
471
|
if (!isXdotoolAvailable()) {
|
|
301
472
|
return {
|
|
302
473
|
kind: "error",
|
|
303
|
-
message: `${LINUX_XDOTOOL_MISSING_PREFIX}. Install it (e.g. \`sudo apt-get install xdotool\`) to enable Unity
|
|
474
|
+
message: `${LINUX_XDOTOOL_MISSING_PREFIX}. Install it (e.g. \`sudo apt-get install xdotool\`) to enable Unity startup-dialog auto-dismiss on Linux/X11. Wayland is not yet supported.`,
|
|
304
475
|
};
|
|
305
476
|
}
|
|
306
477
|
const unityPids = new Set(getUnityPidsLinux());
|
|
307
478
|
if (unityPids.size === 0) {
|
|
308
479
|
return { kind: "not-found" };
|
|
309
480
|
}
|
|
310
|
-
//
|
|
311
|
-
//
|
|
312
|
-
//
|
|
313
|
-
//
|
|
314
|
-
//
|
|
315
|
-
//
|
|
316
|
-
//
|
|
317
|
-
//
|
|
481
|
+
// Classify by title fragment: walk the per-kind fragment table, find the
|
|
482
|
+
// first kind whose xdotool search surfaces a Unity-owned window.
|
|
483
|
+
// - blocked kinds (project_upgrade without opt-in) → report blocked.
|
|
484
|
+
// - decline kinds (tokens === null) → skip (treat as not-found).
|
|
485
|
+
// - otherwise activate the window + send Return to click the focused
|
|
486
|
+
// (default) button. Under default/auto/ignore/recover the default
|
|
487
|
+
// button is the safe choice for launch_errors / non_matching_editor /
|
|
488
|
+
// auto_graphics_api. Project upgrade is never clicked here (blocked).
|
|
489
|
+
const blocked = new Set(blockedKindsForPolicy(opts.policy, opts.allowProjectUpgrade));
|
|
490
|
+
const kinds = Object.keys(DIALOG_TITLE_FRAGMENTS);
|
|
491
|
+
// Prefer launch_errors first (the common stall), then the others.
|
|
492
|
+
const order = [
|
|
493
|
+
"launch_errors",
|
|
494
|
+
"non_matching_editor",
|
|
495
|
+
"auto_graphics_api",
|
|
496
|
+
"project_upgrade",
|
|
497
|
+
];
|
|
498
|
+
void kinds;
|
|
318
499
|
return new Promise((resolve) => {
|
|
319
|
-
const fragments = LAUNCH_ERROR_DIALOG_TITLE_FRAGMENTS;
|
|
320
500
|
let idx = 0;
|
|
321
|
-
const
|
|
322
|
-
if (idx >=
|
|
501
|
+
const tryNextKind = () => {
|
|
502
|
+
if (idx >= order.length) {
|
|
323
503
|
resolve({ kind: "not-found" });
|
|
324
504
|
return;
|
|
325
505
|
}
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
506
|
+
const kind = order[idx++];
|
|
507
|
+
const tokens = preferenceTokensForPolicy(kind, opts.policy, opts.allowProjectUpgrade);
|
|
508
|
+
const fragments = DIALOG_TITLE_FRAGMENTS[kind];
|
|
509
|
+
// Probe this kind's fragments one at a time.
|
|
510
|
+
let fIdx = 0;
|
|
511
|
+
const tryNextFragment = () => {
|
|
512
|
+
if (fIdx >= fragments.length) {
|
|
513
|
+
tryNextKind();
|
|
330
514
|
return;
|
|
331
515
|
}
|
|
332
|
-
const
|
|
333
|
-
|
|
334
|
-
if (!
|
|
335
|
-
|
|
516
|
+
const fragment = fragments[fIdx++];
|
|
517
|
+
execFile("xdotool", ["search", "--name", regexEscapeForXdotool(fragment)], { timeout: 2000 }, (err, stdout) => {
|
|
518
|
+
if (err || !stdout.trim()) {
|
|
519
|
+
tryNextFragment();
|
|
336
520
|
return;
|
|
337
521
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
522
|
+
const candidateIds = stdout.trim().split(/\s+/).filter(Boolean);
|
|
523
|
+
findUnityOwnedWindow(candidateIds, unityPids, (winId) => {
|
|
524
|
+
if (!winId) {
|
|
525
|
+
tryNextFragment();
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
if (blocked.has(kind) || tokens === null) {
|
|
529
|
+
// Found the dialog but the policy declines. Report blocked
|
|
530
|
+
// only for genuinely blocked kinds (project_upgrade); a null-
|
|
531
|
+
// token decline (manual / safe-mode on a kind with no safe
|
|
532
|
+
// button) is reported as not-found so the loop keeps ticking.
|
|
533
|
+
if (blocked.has(kind)) {
|
|
534
|
+
resolve({
|
|
535
|
+
kind: "blocked",
|
|
536
|
+
dialog: kind,
|
|
537
|
+
message: `Policy '${opts.policy}' declines to dismiss ${kind} dialog`,
|
|
538
|
+
});
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
tryNextKind();
|
|
351
542
|
return;
|
|
352
543
|
}
|
|
353
|
-
|
|
544
|
+
execFile("xdotool", [
|
|
545
|
+
"windowactivate",
|
|
546
|
+
"--sync",
|
|
547
|
+
winId,
|
|
548
|
+
"key",
|
|
549
|
+
"--clearmodifiers",
|
|
550
|
+
"Return",
|
|
551
|
+
], { timeout: 2000 }, (activateErr) => {
|
|
552
|
+
if (activateErr) {
|
|
553
|
+
resolve({
|
|
554
|
+
kind: "error",
|
|
555
|
+
message: `xdotool failed to dismiss window ${winId}: ${activateErr.message}`,
|
|
556
|
+
});
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
resolve({ kind: "dismissed", button: "Focus", dialog: kind });
|
|
560
|
+
});
|
|
354
561
|
});
|
|
355
562
|
});
|
|
356
|
-
}
|
|
563
|
+
};
|
|
564
|
+
tryNextFragment();
|
|
357
565
|
};
|
|
358
|
-
|
|
566
|
+
tryNextKind();
|
|
359
567
|
});
|
|
360
568
|
}
|
|
361
569
|
/**
|
|
@@ -397,11 +605,13 @@ function findUnityOwnedWindow(candidateIds, unityPids, done) {
|
|
|
397
605
|
* the result as `not-found`.
|
|
398
606
|
*
|
|
399
607
|
* Contract:
|
|
400
|
-
* - `dismissed:<button>` → `{ kind: "dismissed", button }`
|
|
401
|
-
* - `
|
|
402
|
-
* - `
|
|
403
|
-
* -
|
|
404
|
-
*
|
|
608
|
+
* - `dismissed:<button>:<kind>` → `{ kind: "dismissed", button, dialog }`
|
|
609
|
+
* - `dismissed:<button>` → back-compat (T4.5) → launch_errors
|
|
610
|
+
* - `blocked:<kind>` → `{ kind: "blocked", dialog, message }`
|
|
611
|
+
* - `not-found` → `{ kind: "not-found" }`
|
|
612
|
+
* - `error:<message>` → `{ kind: "error", message }`
|
|
613
|
+
* - any other / empty → `{ kind: "not-found" }` (defensive — a
|
|
614
|
+
* transient parse miss is treated as "not yet visible" rather than abort)
|
|
405
615
|
*/
|
|
406
616
|
export function parseDismissOutput(stdout) {
|
|
407
617
|
const lines = stdout
|
|
@@ -414,20 +624,47 @@ export function parseDismissOutput(stdout) {
|
|
|
414
624
|
if (last === "not-found")
|
|
415
625
|
return { kind: "not-found" };
|
|
416
626
|
if (last.startsWith("dismissed:")) {
|
|
417
|
-
const
|
|
418
|
-
|
|
627
|
+
const rest = last.substring("dismissed:".length);
|
|
628
|
+
const parts = rest.split(":");
|
|
629
|
+
if (parts.length >= 2) {
|
|
630
|
+
// dismissed:<button>:<kind>
|
|
631
|
+
const dialog = parts[parts.length - 1];
|
|
632
|
+
const button = parts.slice(0, -1).join(":") || DISMISS_BUTTON_LABEL;
|
|
633
|
+
return {
|
|
634
|
+
kind: "dismissed",
|
|
635
|
+
button,
|
|
636
|
+
dialog: isDialogKind(dialog) ? dialog : "launch_errors",
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
// Back-compat: T4.5 single-field form `dismissed:<button>`.
|
|
640
|
+
const button = rest || DISMISS_BUTTON_LABEL;
|
|
641
|
+
return { kind: "dismissed", button, dialog: "launch_errors" };
|
|
642
|
+
}
|
|
643
|
+
if (last.startsWith("blocked:")) {
|
|
644
|
+
const dialog = last.substring("blocked:".length);
|
|
645
|
+
return {
|
|
646
|
+
kind: "blocked",
|
|
647
|
+
dialog: isDialogKind(dialog) ? dialog : "project_upgrade",
|
|
648
|
+
message: `Policy declined to dismiss ${dialog} dialog`,
|
|
649
|
+
};
|
|
419
650
|
}
|
|
420
651
|
if (last.startsWith("error:")) {
|
|
421
652
|
return { kind: "error", message: last.substring("error:".length) };
|
|
422
653
|
}
|
|
423
654
|
return { kind: "not-found" };
|
|
424
655
|
}
|
|
656
|
+
function isDialogKind(s) {
|
|
657
|
+
return (s === "launch_errors" ||
|
|
658
|
+
s === "non_matching_editor" ||
|
|
659
|
+
s === "project_upgrade" ||
|
|
660
|
+
s === "auto_graphics_api");
|
|
661
|
+
}
|
|
425
662
|
// ===========================================================================
|
|
426
663
|
// Polling loop + config
|
|
427
664
|
// ===========================================================================
|
|
428
|
-
/** Default dismiss probe timeout
|
|
665
|
+
/** Default dismiss probe timeout (30s overall budget). */
|
|
429
666
|
export const DEFAULT_DISMISS_TIMEOUT_MS = 30_000;
|
|
430
|
-
/** Default dismiss probe poll interval
|
|
667
|
+
/** Default dismiss probe poll interval (1.5s tick). */
|
|
431
668
|
export const DEFAULT_DISMISS_INTERVAL_MS = 1_500;
|
|
432
669
|
/**
|
|
433
670
|
* Substring markers that identify a `kind: "error"` outcome as permanent for
|
|
@@ -443,11 +680,14 @@ function isPermanentDismissError(message) {
|
|
|
443
680
|
return PERMANENT_DISMISS_ERROR_MARKERS.some((m) => message.includes(m));
|
|
444
681
|
}
|
|
445
682
|
export function readDismissConfig(env = process.env) {
|
|
446
|
-
const
|
|
683
|
+
const policy = parseDialogPolicy(env);
|
|
684
|
+
const killSwitchOff = env.UNITY_OPEN_MCP_NO_AUTO_DISMISS_LAUNCH_ERRORS === "1";
|
|
447
685
|
return {
|
|
448
|
-
enabled,
|
|
686
|
+
enabled: !killSwitchOff && policy !== "manual",
|
|
449
687
|
timeoutMs: parsePositiveInt(env.UNITY_OPEN_MCP_DISMISS_TIMEOUT_MS, DEFAULT_DISMISS_TIMEOUT_MS),
|
|
450
688
|
intervalMs: parsePositiveInt(env.UNITY_OPEN_MCP_DISMISS_INTERVAL_MS, DEFAULT_DISMISS_INTERVAL_MS),
|
|
689
|
+
policy,
|
|
690
|
+
allowProjectUpgrade: env.UNITY_OPEN_MCP_ALLOW_PROJECT_UPGRADE === "1",
|
|
451
691
|
};
|
|
452
692
|
}
|
|
453
693
|
function parsePositiveInt(raw, fallback) {
|
|
@@ -462,32 +702,32 @@ function defaultDismissLog(line) {
|
|
|
462
702
|
console.error(line);
|
|
463
703
|
}
|
|
464
704
|
/**
|
|
465
|
-
* Poll the OS desktop for
|
|
466
|
-
* every time the probe reports it as found. Returns once the
|
|
467
|
-
* has fired (authoritative readiness), the overall timeout has
|
|
468
|
-
* a permanent platform error has been observed.
|
|
705
|
+
* Poll the OS desktop for any Unity startup dialog and click the policy-
|
|
706
|
+
* selected button every time the probe reports it as found. Returns once the
|
|
707
|
+
* abort signal has fired (authoritative readiness), the overall timeout has
|
|
708
|
+
* elapsed, or a permanent platform error has been observed.
|
|
469
709
|
*
|
|
470
|
-
* Re-entrant dismissals are supported: when
|
|
710
|
+
* Re-entrant dismissals are supported: when a dialog re-appears after a
|
|
471
711
|
* successful click (resolver-fix → dialog-reappears cycle), each subsequent
|
|
472
712
|
* dismissal emits its own log line so the recurrence shows in the audit log.
|
|
473
713
|
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
477
|
-
* budget.
|
|
714
|
+
* `blocked` outcomes (project_upgrade without opt-in) are logged once per
|
|
715
|
+
* occurrence and the loop keeps polling — a human still needs to dismiss that
|
|
716
|
+
* dialog, and the loop should not exit before the readiness abort fires.
|
|
478
717
|
*
|
|
479
|
-
*
|
|
480
|
-
*
|
|
481
|
-
*
|
|
482
|
-
* is the authoritative "no more launch dialog" signal and aborts this loop.
|
|
718
|
+
* Never throws. Transient platform errors are logged once then suppressed;
|
|
719
|
+
* permanent errors bail out after the first occurrence so the helper does
|
|
720
|
+
* not spawn doomed tool invocations on a fixed budget.
|
|
483
721
|
*/
|
|
484
|
-
export async function
|
|
722
|
+
export async function pollAndDismissDialogs(opts) {
|
|
485
723
|
const platform = opts.platform ?? nodePlatform();
|
|
486
|
-
const probe = opts.probe ??
|
|
724
|
+
const probe = opts.probe ??
|
|
725
|
+
((o) => tryDismissDialog(o));
|
|
487
726
|
const log = opts.log ?? defaultDismissLog;
|
|
488
727
|
const deadline = Date.now() + Math.max(0, opts.timeoutMs);
|
|
489
728
|
const interval = Math.max(50, opts.intervalMs);
|
|
490
729
|
const seenErrorMessages = new Set();
|
|
730
|
+
const seenBlocked = new Set();
|
|
491
731
|
let aborted = opts.abortSignal?.aborted ?? false;
|
|
492
732
|
const onAbort = () => {
|
|
493
733
|
aborted = true;
|
|
@@ -495,22 +735,39 @@ export async function pollAndDismissLaunchErrors(opts) {
|
|
|
495
735
|
opts.abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
496
736
|
try {
|
|
497
737
|
while (Date.now() < deadline && !aborted) {
|
|
498
|
-
const outcome = await probe(
|
|
738
|
+
const outcome = await probe({
|
|
739
|
+
platform,
|
|
740
|
+
policy: opts.policy,
|
|
741
|
+
allowProjectUpgrade: opts.allowProjectUpgrade,
|
|
742
|
+
});
|
|
499
743
|
// Re-check exit conditions BEFORE applying the outcome: if abort fired
|
|
500
744
|
// (or the deadline lapsed) while `probe` was in flight, the in-flight
|
|
501
745
|
// result is stale and applying it would emit a misleading log.
|
|
502
746
|
if (aborted || Date.now() >= deadline)
|
|
503
747
|
break;
|
|
504
748
|
if (outcome.kind === "dismissed") {
|
|
505
|
-
log(`[unity-open-mcp] dismissed Unity
|
|
506
|
-
`(button=${outcome.button}, platform=${platform})`);
|
|
749
|
+
log(`[unity-open-mcp] dismissed Unity ${outcome.dialog} dialog ` +
|
|
750
|
+
`(button=${outcome.button}, policy=${opts.policy}, platform=${platform})`);
|
|
507
751
|
// Keep polling — the dialog may re-appear after the resolver fixes
|
|
508
752
|
// one error and surfaces the next.
|
|
509
753
|
}
|
|
754
|
+
else if (outcome.kind === "blocked") {
|
|
755
|
+
// Project-upgrade (or future blocked kind): log once per kind per
|
|
756
|
+
// run, then keep polling. A human must dismiss it; exiting would
|
|
757
|
+
// hide the stall behind a clean-looking readiness abort.
|
|
758
|
+
if (!seenBlocked.has(outcome.dialog)) {
|
|
759
|
+
seenBlocked.add(outcome.dialog);
|
|
760
|
+
log(`[unity-open-mcp] dialog auto-dismiss blocked on ${outcome.dialog} ` +
|
|
761
|
+
`(policy=${opts.policy}): ${outcome.message}. ` +
|
|
762
|
+
(outcome.dialog === "project_upgrade"
|
|
763
|
+
? "Set UNITY_OPEN_MCP_ALLOW_PROJECT_UPGRADE=1 to opt in to auto-confirm (irreversible)."
|
|
764
|
+
: "Dismiss it manually or change UNITY_OPEN_MCP_DIALOG_POLICY."));
|
|
765
|
+
}
|
|
766
|
+
}
|
|
510
767
|
else if (outcome.kind === "error") {
|
|
511
768
|
if (!seenErrorMessages.has(outcome.message)) {
|
|
512
769
|
seenErrorMessages.add(outcome.message);
|
|
513
|
-
log(`[unity-open-mcp]
|
|
770
|
+
log(`[unity-open-mcp] startup-dialog auto-dismiss: ${outcome.message}`);
|
|
514
771
|
}
|
|
515
772
|
if (isPermanentDismissError(outcome.message)) {
|
|
516
773
|
// No point ticking again — bail out.
|