@akiojin/unity-mcp-server 2.14.17 → 2.16.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/LICENSE +0 -0
- package/README.md +142 -99
- package/package.json +4 -3
- package/src/core/codeIndex.js +0 -0
- package/src/core/codeIndexDb.js +0 -0
- package/src/core/config.js +50 -15
- package/src/core/indexWatcher.js +2 -3
- package/src/core/projectInfo.js +27 -20
- package/src/core/unityConnection.js +3 -2
- package/src/handlers/analysis/AnalyzeSceneContentsToolHandler.js +1 -1
- package/src/handlers/analysis/FindByComponentToolHandler.js +2 -2
- package/src/handlers/analysis/GetAnimatorStateToolHandler.js +1 -1
- package/src/handlers/analysis/GetComponentValuesToolHandler.js +2 -2
- package/src/handlers/analysis/GetGameObjectDetailsToolHandler.js +1 -1
- package/src/handlers/analysis/GetInputActionsStateToolHandler.js +1 -1
- package/src/handlers/analysis/GetObjectReferencesToolHandler.js +2 -2
- package/src/handlers/asset/{AssetDatabaseToolHandler.js → AssetDatabaseManageToolHandler.js} +2 -2
- package/src/handlers/asset/{AssetDependencyToolHandler.js → AssetDependencyAnalyzeToolHandler.js} +2 -2
- package/src/handlers/asset/{AssetImportSettingsToolHandler.js → AssetImportSettingsManageToolHandler.js} +2 -2
- package/src/handlers/asset/{CreateMaterialToolHandler.js → AssetMaterialCreateToolHandler.js} +2 -2
- package/src/handlers/asset/{ModifyMaterialToolHandler.js → AssetMaterialModifyToolHandler.js} +2 -2
- package/src/handlers/asset/{CreatePrefabToolHandler.js → AssetPrefabCreateToolHandler.js} +2 -2
- package/src/handlers/asset/{ExitPrefabModeToolHandler.js → AssetPrefabExitModeToolHandler.js} +2 -2
- package/src/handlers/asset/{InstantiatePrefabToolHandler.js → AssetPrefabInstantiateToolHandler.js} +2 -2
- package/src/handlers/asset/{ModifyPrefabToolHandler.js → AssetPrefabModifyToolHandler.js} +2 -2
- package/src/handlers/asset/{OpenPrefabToolHandler.js → AssetPrefabOpenToolHandler.js} +2 -2
- package/src/handlers/asset/{SavePrefabToolHandler.js → AssetPrefabSaveToolHandler.js} +2 -2
- package/src/handlers/base/BaseToolHandler.js +0 -0
- package/src/handlers/compilation/{GetCompilationStateToolHandler.js → CompilationGetStateToolHandler.js} +2 -2
- package/src/handlers/component/{AddComponentToolHandler.js → ComponentAddToolHandler.js} +2 -2
- package/src/handlers/component/{GetComponentTypesToolHandler.js → ComponentGetTypesToolHandler.js} +2 -2
- package/src/handlers/component/{ListComponentsToolHandler.js → ComponentListToolHandler.js} +2 -2
- package/src/handlers/component/{ModifyComponentToolHandler.js → ComponentModifyToolHandler.js} +2 -2
- package/src/handlers/component/{RemoveComponentToolHandler.js → ComponentRemoveToolHandler.js} +2 -2
- package/src/handlers/console/{ClearConsoleToolHandler.js → ConsoleClearToolHandler.js} +2 -2
- package/src/handlers/console/{ReadConsoleToolHandler.js → ConsoleReadToolHandler.js} +2 -2
- package/src/handlers/editor/{LayerManagementToolHandler.js → EditorLayersManageToolHandler.js} +2 -2
- package/src/handlers/editor/{SelectionToolHandler.js → EditorSelectionManageToolHandler.js} +2 -2
- package/src/handlers/editor/{TagManagementToolHandler.js → EditorTagsManageToolHandler.js} +2 -2
- package/src/handlers/editor/{ToolManagementToolHandler.js → EditorToolsManageToolHandler.js} +2 -2
- package/src/handlers/editor/{WindowManagementToolHandler.js → EditorWindowsManageToolHandler.js} +2 -2
- package/src/handlers/gameobject/{CreateGameObjectToolHandler.js → GameObjectCreateToolHandler.js} +3 -3
- package/src/handlers/gameobject/{DeleteGameObjectToolHandler.js → GameObjectDeleteToolHandler.js} +3 -3
- package/src/handlers/gameobject/{FindGameObjectToolHandler.js → GameObjectFindToolHandler.js} +3 -3
- package/src/handlers/gameobject/{GetHierarchyToolHandler.js → GameObjectGetHierarchyToolHandler.js} +3 -3
- package/src/handlers/gameobject/{ModifyGameObjectToolHandler.js → GameObjectModifyToolHandler.js} +3 -3
- package/src/handlers/index.js +230 -213
- package/src/handlers/input/{AddInputActionToolHandler.js → InputActionAddToolHandler.js} +2 -2
- package/src/handlers/input/{CreateActionMapToolHandler.js → InputActionMapCreateToolHandler.js} +2 -2
- package/src/handlers/input/{RemoveActionMapToolHandler.js → InputActionMapRemoveToolHandler.js} +2 -2
- package/src/handlers/input/{RemoveInputActionToolHandler.js → InputActionRemoveToolHandler.js} +2 -2
- package/src/handlers/input/{AddInputBindingToolHandler.js → InputBindingAddToolHandler.js} +2 -2
- package/src/handlers/input/{CreateCompositeBindingToolHandler.js → InputBindingCompositeCreateToolHandler.js} +2 -2
- package/src/handlers/input/{RemoveAllBindingsToolHandler.js → InputBindingRemoveAllToolHandler.js} +2 -2
- package/src/handlers/input/{RemoveInputBindingToolHandler.js → InputBindingRemoveToolHandler.js} +2 -2
- package/src/handlers/input/{ManageControlSchemesToolHandler.js → InputControlSchemesManageToolHandler.js} +2 -2
- package/src/handlers/input/{GamepadSimulationHandler.js → InputGamepadSimulateToolHandler.js} +3 -3
- package/src/handlers/input/{KeyboardSimulationHandler.js → InputKeyboardSimulateToolHandler.js} +3 -3
- package/src/handlers/input/{MouseSimulationHandler.js → InputMouseSimulateToolHandler.js} +3 -3
- package/src/handlers/input/{InputSystemHandler.js → InputSystemControlToolHandler.js} +4 -4
- package/src/handlers/input/{TouchSimulationHandler.js → InputTouchSimulateToolHandler.js} +3 -3
- package/src/handlers/menu/{ExecuteMenuItemToolHandler.js → MenuItemExecuteToolHandler.js} +2 -2
- package/src/handlers/package/PackageManagerToolHandler.js +1 -1
- package/src/handlers/package/RegistryConfigToolHandler.js +1 -1
- package/src/handlers/playmode/{GetEditorStateToolHandler.js → PlaymodeGetStateToolHandler.js} +2 -2
- package/src/handlers/playmode/{PauseToolHandler.js → PlaymodePauseToolHandler.js} +3 -3
- package/src/handlers/playmode/{PlayToolHandler.js → PlaymodePlayToolHandler.js} +4 -4
- package/src/handlers/playmode/{StopToolHandler.js → PlaymodeStopToolHandler.js} +4 -4
- package/src/handlers/playmode/{WaitForEditorStateToolHandler.js → PlaymodeWaitForStateToolHandler.js} +3 -3
- package/src/handlers/scene/GetSceneInfoToolHandler.js +1 -1
- package/src/handlers/scene/{CreateSceneToolHandler.js → SceneCreateToolHandler.js} +2 -2
- package/src/handlers/scene/{ListScenesToolHandler.js → SceneListToolHandler.js} +2 -2
- package/src/handlers/scene/{LoadSceneToolHandler.js → SceneLoadToolHandler.js} +2 -2
- package/src/handlers/scene/{SaveSceneToolHandler.js → SceneSaveToolHandler.js} +2 -2
- package/src/handlers/screenshot/{AnalyzeScreenshotToolHandler.js → ScreenshotAnalyzeToolHandler.js} +2 -2
- package/src/handlers/screenshot/{CaptureScreenshotToolHandler.js → ScreenshotCaptureToolHandler.js} +2 -2
- package/src/handlers/script/{BuildCodeIndexToolHandler.js → CodeIndexBuildToolHandler.js} +4 -4
- package/src/handlers/script/CodeIndexUpdateToolHandler.js +234 -0
- package/src/handlers/script/{ScriptCreateClassFileToolHandler.js → ScriptCreateClassToolHandler.js} +2 -2
- package/src/handlers/script/ScriptEditSnippetToolHandler.js +272 -0
- package/src/handlers/script/ScriptEditStructuredToolHandler.js +0 -0
- package/src/handlers/script/ScriptIndexStatusToolHandler.js +2 -2
- package/src/handlers/script/ScriptPackagesListToolHandler.js +0 -0
- package/src/handlers/script/ScriptReadToolHandler.js +0 -0
- package/src/handlers/script/ScriptRefactorRenameToolHandler.js +0 -0
- package/src/handlers/script/ScriptRefsFindToolHandler.js +0 -0
- package/src/handlers/script/ScriptRemoveSymbolToolHandler.js +0 -0
- package/src/handlers/script/ScriptSearchToolHandler.js +0 -0
- package/src/handlers/script/ScriptSymbolFindToolHandler.js +0 -0
- package/src/handlers/script/ScriptSymbolsGetToolHandler.js +0 -0
- package/src/handlers/settings/{GetProjectSettingsToolHandler.js → SettingsGetToolHandler.js} +2 -2
- package/src/handlers/settings/{UpdateProjectSettingsToolHandler.js → SettingsUpdateToolHandler.js} +2 -2
- package/src/handlers/system/{GetCommandStatsToolHandler.js → SystemGetCommandStatsToolHandler.js} +2 -3
- package/src/handlers/system/{PingToolHandler.js → SystemPingToolHandler.js} +3 -3
- package/src/handlers/system/{RefreshAssetsToolHandler.js → SystemRefreshAssetsToolHandler.js} +3 -3
- package/src/handlers/test/TestGetStatusToolHandler.js +79 -0
- package/src/handlers/test/TestRunToolHandler.js +153 -0
- package/src/handlers/ui/{ClickUIElementToolHandler.js → UIClickElementToolHandler.js} +2 -2
- package/src/handlers/ui/{FindUIElementsToolHandler.js → UIFindElementsToolHandler.js} +2 -2
- package/src/handlers/ui/{GetUIElementStateToolHandler.js → UIGetElementStateToolHandler.js} +2 -2
- package/src/handlers/ui/{SetUIElementValueToolHandler.js → UISetElementValueToolHandler.js} +2 -2
- package/src/handlers/ui/{SimulateUIInputToolHandler.js → UISimulateInputToolHandler.js} +2 -2
- package/src/handlers/video/{CaptureVideoForToolHandler.js → VideoCaptureForToolHandler.js} +8 -8
- package/src/handlers/video/{CaptureVideoStartToolHandler.js → VideoCaptureStartToolHandler.js} +2 -2
- package/src/handlers/video/{CaptureVideoStatusToolHandler.js → VideoCaptureStatusToolHandler.js} +2 -2
- package/src/handlers/video/{CaptureVideoStopToolHandler.js → VideoCaptureStopToolHandler.js} +3 -3
- package/src/lsp/CSharpLspUtils.js +68 -10
- package/src/lsp/LspProcessManager.js +0 -0
- package/src/lsp/LspRpcClient.js +14 -0
- package/src/tools/analysis/analyzeSceneContents.js +3 -3
- package/src/tools/analysis/findByComponent.js +3 -3
- package/src/tools/analysis/getAnimatorState.js +6 -6
- package/src/tools/analysis/getComponentValues.js +3 -3
- package/src/tools/analysis/getGameObjectDetails.js +3 -3
- package/src/tools/analysis/getInputActionsState.js +4 -4
- package/src/tools/analysis/getObjectReferences.js +3 -3
- package/src/tools/input/inputActionsEditor.js +18 -18
- package/src/tools/scene/createScene.js +3 -3
- package/src/tools/scene/getSceneInfo.js +3 -3
- package/src/tools/scene/listScenes.js +3 -3
- package/src/tools/scene/loadScene.js +3 -3
- package/src/tools/scene/saveScene.js +3 -3
- package/src/tools/system/ping.js +5 -5
- package/src/tools/video/recordFor.js +2 -2
- package/src/tools/video/recordPlayMode.js +0 -0
- package/src/utils/csharpParse.js +0 -0
- package/src/utils/validators.js +0 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handler for getting Unity test execution status
|
|
5
|
+
* Works with non-blocking test execution from RunUnityTestsToolHandler
|
|
6
|
+
*/
|
|
7
|
+
export class TestGetStatusToolHandler extends BaseToolHandler {
|
|
8
|
+
constructor(unityConnection) {
|
|
9
|
+
super(
|
|
10
|
+
'test_get_status',
|
|
11
|
+
'Get current Unity test execution status and results',
|
|
12
|
+
{
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: {}
|
|
15
|
+
}
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
this.unityConnection = unityConnection;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Gets current test execution status
|
|
23
|
+
* @param {Object} params - The validated input parameters
|
|
24
|
+
* @returns {Promise<Object>} Test execution status and results
|
|
25
|
+
*/
|
|
26
|
+
async execute(params) {
|
|
27
|
+
// Ensure connection to Unity
|
|
28
|
+
if (!this.unityConnection.isConnected()) {
|
|
29
|
+
await this.unityConnection.connect();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Send command to Unity
|
|
33
|
+
const response = await this.unityConnection.sendCommand('get_test_status', params);
|
|
34
|
+
|
|
35
|
+
// Handle Unity response
|
|
36
|
+
if (response.error) {
|
|
37
|
+
throw new Error(response.error);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Return status directly if still running or idle
|
|
41
|
+
if (response.status === 'running' || response.status === 'idle') {
|
|
42
|
+
return response;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Format completed results
|
|
46
|
+
if (response.status === 'completed') {
|
|
47
|
+
const result = {
|
|
48
|
+
status: 'completed',
|
|
49
|
+
success: response.success,
|
|
50
|
+
totalTests: response.totalTests,
|
|
51
|
+
passedTests: response.passedTests,
|
|
52
|
+
failedTests: response.failedTests,
|
|
53
|
+
skippedTests: response.skippedTests,
|
|
54
|
+
inconclusiveTests: response.inconclusiveTests,
|
|
55
|
+
summary: `${response.passedTests}/${response.totalTests} tests passed`,
|
|
56
|
+
failures: response.failures || [],
|
|
57
|
+
tests: response.tests || []
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Error status
|
|
64
|
+
return response;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Gets example usage for this tool
|
|
69
|
+
* @returns {Object} Example usage scenarios
|
|
70
|
+
*/
|
|
71
|
+
getExamples() {
|
|
72
|
+
return {
|
|
73
|
+
checkStatus: {
|
|
74
|
+
description: 'Check current test execution status',
|
|
75
|
+
params: {}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handler for running Unity NUnit tests via Test Runner API
|
|
5
|
+
* Implements SPEC-e7c9b50c: Unity Test Execution Feature
|
|
6
|
+
*/
|
|
7
|
+
export class TestRunToolHandler extends BaseToolHandler {
|
|
8
|
+
constructor(unityConnection) {
|
|
9
|
+
super(
|
|
10
|
+
'test_run',
|
|
11
|
+
'Run Unity NUnit tests in the current project',
|
|
12
|
+
{
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: {
|
|
15
|
+
testMode: {
|
|
16
|
+
type: 'string',
|
|
17
|
+
enum: ['EditMode', 'PlayMode', 'All'],
|
|
18
|
+
default: 'EditMode',
|
|
19
|
+
description: 'Test mode to run (EditMode: editor tests, PlayMode: runtime tests, All: both)'
|
|
20
|
+
},
|
|
21
|
+
filter: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'Filter tests by class name (e.g., "PlayerControllerTests")'
|
|
24
|
+
},
|
|
25
|
+
category: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
description: 'Filter tests by category attribute (e.g., "Integration")'
|
|
28
|
+
},
|
|
29
|
+
namespace: {
|
|
30
|
+
type: 'string',
|
|
31
|
+
description: 'Filter tests by namespace (e.g., "MyGame.Tests.Player")'
|
|
32
|
+
},
|
|
33
|
+
includeDetails: {
|
|
34
|
+
type: 'boolean',
|
|
35
|
+
default: false,
|
|
36
|
+
description: 'Include detailed test results for each individual test'
|
|
37
|
+
},
|
|
38
|
+
exportPath: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
description: 'Export test results to NUnit XML file at specified path'
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
this.unityConnection = unityConnection;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Executes Unity tests based on specified parameters
|
|
51
|
+
* @param {Object} params - The validated input parameters
|
|
52
|
+
* @returns {Promise<Object>} Test execution results
|
|
53
|
+
*/
|
|
54
|
+
async execute(params) {
|
|
55
|
+
// Ensure connection to Unity
|
|
56
|
+
if (!this.unityConnection.isConnected()) {
|
|
57
|
+
await this.unityConnection.connect();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Send command to Unity
|
|
61
|
+
const response = await this.unityConnection.sendCommand('run_tests', params);
|
|
62
|
+
|
|
63
|
+
// Handle Unity response
|
|
64
|
+
if (response.error) {
|
|
65
|
+
throw new Error(response.error);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Handle new non-blocking response format (status: "running")
|
|
69
|
+
if (response.status === 'running') {
|
|
70
|
+
return {
|
|
71
|
+
status: 'running',
|
|
72
|
+
message: response.message || 'Test execution started. Use get_test_status to check progress.'
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Legacy format support (for backwards compatibility)
|
|
77
|
+
// Format and return result
|
|
78
|
+
const result = {
|
|
79
|
+
success: response.success,
|
|
80
|
+
totalTests: response.totalTests,
|
|
81
|
+
passedTests: response.passedTests,
|
|
82
|
+
failedTests: response.failedTests,
|
|
83
|
+
skippedTests: response.skippedTests,
|
|
84
|
+
inconclusiveTests: response.inconclusiveTests,
|
|
85
|
+
duration: response.duration,
|
|
86
|
+
summary: `${response.passedTests}/${response.totalTests} tests passed in ${response.duration}s`,
|
|
87
|
+
failures: response.failures || []
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// Include detailed test results if requested
|
|
91
|
+
if (params.includeDetails && response.tests) {
|
|
92
|
+
result.tests = response.tests;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Gets example usage for this tool
|
|
100
|
+
* @returns {Object} Example usage scenarios
|
|
101
|
+
*/
|
|
102
|
+
getExamples() {
|
|
103
|
+
return {
|
|
104
|
+
runAllEditModeTests: {
|
|
105
|
+
description: 'Run all Edit Mode tests',
|
|
106
|
+
params: {
|
|
107
|
+
testMode: 'EditMode'
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
runSpecificClass: {
|
|
111
|
+
description: 'Run tests in a specific class',
|
|
112
|
+
params: {
|
|
113
|
+
testMode: 'EditMode',
|
|
114
|
+
filter: 'PlayerControllerTests'
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
runCategoryTests: {
|
|
118
|
+
description: 'Run tests in a specific category',
|
|
119
|
+
params: {
|
|
120
|
+
testMode: 'EditMode',
|
|
121
|
+
category: 'Integration'
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
runWithDetails: {
|
|
125
|
+
description: 'Run tests with detailed results for each test',
|
|
126
|
+
params: {
|
|
127
|
+
testMode: 'EditMode',
|
|
128
|
+
includeDetails: true
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
runAndExport: {
|
|
132
|
+
description: 'Run tests and export results to XML',
|
|
133
|
+
params: {
|
|
134
|
+
testMode: 'EditMode',
|
|
135
|
+
exportPath: 'TestResults/results.xml'
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
runPlayModeTests: {
|
|
139
|
+
description: 'Run Play Mode tests (requires Play Mode)',
|
|
140
|
+
params: {
|
|
141
|
+
testMode: 'PlayMode'
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
runAllTests: {
|
|
145
|
+
description: 'Run both Edit Mode and Play Mode tests',
|
|
146
|
+
params: {
|
|
147
|
+
testMode: 'All',
|
|
148
|
+
includeDetails: true
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
2
2
|
|
|
3
|
-
export class
|
|
3
|
+
export class UIClickElementToolHandler extends BaseToolHandler {
|
|
4
4
|
constructor(unityConnection) {
|
|
5
5
|
super(
|
|
6
|
-
'
|
|
6
|
+
'ui_click_element',
|
|
7
7
|
'Simulate clicking on UI elements',
|
|
8
8
|
{
|
|
9
9
|
type: 'object',
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
2
2
|
|
|
3
|
-
export class
|
|
3
|
+
export class UIFindElementsToolHandler extends BaseToolHandler {
|
|
4
4
|
constructor(unityConnection) {
|
|
5
5
|
super(
|
|
6
|
-
'
|
|
6
|
+
'ui_find_elements',
|
|
7
7
|
'Find UI elements by component type, tag, or name pattern.',
|
|
8
8
|
{
|
|
9
9
|
type: 'object',
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
2
2
|
|
|
3
|
-
export class
|
|
3
|
+
export class UIGetElementStateToolHandler extends BaseToolHandler {
|
|
4
4
|
constructor(unityConnection) {
|
|
5
5
|
super(
|
|
6
|
-
'
|
|
6
|
+
'ui_get_element_state',
|
|
7
7
|
'Get detailed state information about UI elements',
|
|
8
8
|
{
|
|
9
9
|
type: 'object',
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
2
2
|
|
|
3
|
-
export class
|
|
3
|
+
export class UISetElementValueToolHandler extends BaseToolHandler {
|
|
4
4
|
constructor(unityConnection) {
|
|
5
5
|
super(
|
|
6
|
-
'
|
|
6
|
+
'ui_set_element_value',
|
|
7
7
|
'Set values for UI input elements',
|
|
8
8
|
{
|
|
9
9
|
type: 'object',
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
2
2
|
|
|
3
|
-
export class
|
|
3
|
+
export class UISimulateInputToolHandler extends BaseToolHandler {
|
|
4
4
|
constructor(unityConnection) {
|
|
5
5
|
super(
|
|
6
|
-
'
|
|
6
|
+
'ui_simulate_input',
|
|
7
7
|
'Simulate complex UI interactions and input sequences',
|
|
8
8
|
{
|
|
9
9
|
type: 'object',
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
6
6
|
|
|
7
|
-
export class
|
|
7
|
+
export class VideoCaptureForToolHandler extends BaseToolHandler {
|
|
8
8
|
constructor(unityConnection) {
|
|
9
9
|
super(
|
|
10
|
-
'
|
|
10
|
+
'video_capture_for',
|
|
11
11
|
'Record video for a fixed duration (auto-stop). Optionally enters Play Mode first.',
|
|
12
12
|
{
|
|
13
13
|
type: 'object',
|
|
@@ -34,12 +34,12 @@ export class CaptureVideoForToolHandler extends BaseToolHandler {
|
|
|
34
34
|
let needPlay = !!params.play;
|
|
35
35
|
if (params.play === undefined) {
|
|
36
36
|
try {
|
|
37
|
-
const s0 = await this.unityConnection.sendCommand('
|
|
37
|
+
const s0 = await this.unityConnection.sendCommand('playmode_get_state', {});
|
|
38
38
|
needPlay = !(s0 && s0.isPlaying);
|
|
39
39
|
} catch { needPlay = true; }
|
|
40
40
|
}
|
|
41
41
|
if (needPlay) {
|
|
42
|
-
await this.unityConnection.sendCommand('
|
|
42
|
+
await this.unityConnection.sendCommand('playmode_play', {});
|
|
43
43
|
for (let i = 0; i < 60; i++) {
|
|
44
44
|
const s = await this.unityConnection.sendCommand('get_editor_state', {});
|
|
45
45
|
if (s && s.isPlaying) { enteredPlay = true; break; }
|
|
@@ -49,7 +49,7 @@ export class CaptureVideoForToolHandler extends BaseToolHandler {
|
|
|
49
49
|
|
|
50
50
|
// Start with auto-stop
|
|
51
51
|
const { WORKSPACE_ROOT } = await import('../../core/config.js');
|
|
52
|
-
const startResp = await this.unityConnection.sendCommand('
|
|
52
|
+
const startResp = await this.unityConnection.sendCommand('video_capture_start', {
|
|
53
53
|
captureMode: params.captureMode || 'game',
|
|
54
54
|
width: params.width ?? 1280,
|
|
55
55
|
height: params.height ?? 720,
|
|
@@ -65,14 +65,14 @@ export class CaptureVideoForToolHandler extends BaseToolHandler {
|
|
|
65
65
|
const deadline = Date.now() + Math.max(0, Math.floor((params.durationSec || 0) * 1000)) + 1500; // small buffer
|
|
66
66
|
let lastStatus = null;
|
|
67
67
|
while (Date.now() < deadline) {
|
|
68
|
-
lastStatus = await this.unityConnection.sendCommand('
|
|
68
|
+
lastStatus = await this.unityConnection.sendCommand('video_capture_status', {});
|
|
69
69
|
if (lastStatus && lastStatus.isRecording === false) break;
|
|
70
70
|
await sleep(250);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
// Safety stop if still recording after deadline
|
|
74
74
|
if (lastStatus && lastStatus.isRecording) {
|
|
75
|
-
await this.unityConnection.sendCommand('
|
|
75
|
+
await this.unityConnection.sendCommand('video_capture_stop', {});
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
// Final stop result
|
|
@@ -88,7 +88,7 @@ export class CaptureVideoForToolHandler extends BaseToolHandler {
|
|
|
88
88
|
return { error: e.message, code: 'CLIENT_ERROR' };
|
|
89
89
|
} finally {
|
|
90
90
|
// If we entered play, attempt to leave play (best-effort)
|
|
91
|
-
try { if (enteredPlay) await this.unityConnection.sendCommand('
|
|
91
|
+
try { if (enteredPlay) await this.unityConnection.sendCommand('playmode_stop', {}); } catch {}
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
}
|
package/src/handlers/video/{CaptureVideoStartToolHandler.js → VideoCaptureStartToolHandler.js}
RENAMED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
5
5
|
|
|
6
|
-
export class
|
|
6
|
+
export class VideoCaptureStartToolHandler extends BaseToolHandler {
|
|
7
7
|
constructor(unityConnection) {
|
|
8
8
|
super(
|
|
9
|
-
'
|
|
9
|
+
'video_capture_start',
|
|
10
10
|
'Start video recording (Game view). Requires com.unity.recorder.',
|
|
11
11
|
{
|
|
12
12
|
type: 'object',
|
package/src/handlers/video/{CaptureVideoStatusToolHandler.js → VideoCaptureStatusToolHandler.js}
RENAMED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
5
5
|
|
|
6
|
-
export class
|
|
6
|
+
export class VideoCaptureStatusToolHandler extends BaseToolHandler {
|
|
7
7
|
constructor(unityConnection) {
|
|
8
8
|
super(
|
|
9
|
-
'
|
|
9
|
+
'video_capture_status',
|
|
10
10
|
'Get current video recording status.',
|
|
11
11
|
{
|
|
12
12
|
type: 'object',
|
package/src/handlers/video/{CaptureVideoStopToolHandler.js → VideoCaptureStopToolHandler.js}
RENAMED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Handler for
|
|
2
|
+
* Handler for the video_capture_stop tool
|
|
3
3
|
*/
|
|
4
4
|
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
5
5
|
|
|
6
|
-
export class
|
|
6
|
+
export class VideoCaptureStopToolHandler extends BaseToolHandler {
|
|
7
7
|
constructor(unityConnection) {
|
|
8
8
|
super(
|
|
9
|
-
'
|
|
9
|
+
'video_capture_stop',
|
|
10
10
|
'Stop current video recording and finalize the file.',
|
|
11
11
|
{
|
|
12
12
|
type: 'object',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
3
4
|
import { logger } from '../core/config.js';
|
|
4
5
|
import { WORKSPACE_ROOT } from '../core/config.js';
|
|
5
6
|
|
|
@@ -21,29 +22,86 @@ export class CSharpLspUtils {
|
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
getExecutableName() {
|
|
26
|
+
return process.platform === 'win32' ? 'server.exe' : 'server';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getPrimaryToolRoot() {
|
|
30
|
+
const envRoot = process.env.UNITY_MCP_TOOLS_ROOT;
|
|
31
|
+
if (envRoot && envRoot.trim().length > 0) {
|
|
32
|
+
return path.resolve(envRoot.trim());
|
|
33
|
+
}
|
|
34
|
+
return path.join(os.homedir(), '.unity', 'tools');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getLegacyToolRoot() {
|
|
25
38
|
const root = WORKSPACE_ROOT || process.cwd();
|
|
26
|
-
|
|
27
|
-
|
|
39
|
+
return path.resolve(root, '.unity', 'tools');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
resolveToolPaths(rid) {
|
|
43
|
+
const exe = this.getExecutableName();
|
|
44
|
+
const primary = path.resolve(this.getPrimaryToolRoot(), 'csharp-lsp', rid, exe);
|
|
45
|
+
const legacy = path.resolve(this.getLegacyToolRoot(), 'csharp-lsp', rid, exe);
|
|
46
|
+
return { primary, legacy };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
resolveVersionPaths(rid) {
|
|
50
|
+
const { primary, legacy } = this.resolveToolPaths(rid);
|
|
51
|
+
return {
|
|
52
|
+
primary: path.resolve(path.dirname(primary), 'VERSION'),
|
|
53
|
+
legacy: path.resolve(path.dirname(legacy), 'VERSION')
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
migrateLegacyIfNeeded(rid) {
|
|
58
|
+
const { primary, legacy } = this.resolveToolPaths(rid);
|
|
59
|
+
if (!fs.existsSync(legacy)) return;
|
|
60
|
+
if (fs.existsSync(primary)) return;
|
|
61
|
+
try {
|
|
62
|
+
fs.mkdirSync(path.dirname(primary), { recursive: true });
|
|
63
|
+
fs.copyFileSync(legacy, primary);
|
|
64
|
+
const { primary: primaryVersion, legacy: legacyVersion } = this.resolveVersionPaths(rid);
|
|
65
|
+
if (fs.existsSync(legacyVersion) && !fs.existsSync(primaryVersion)) {
|
|
66
|
+
try {
|
|
67
|
+
fs.copyFileSync(legacyVersion, primaryVersion);
|
|
68
|
+
} catch {}
|
|
69
|
+
}
|
|
70
|
+
logger.info(`[csharp-lsp] migrated legacy binary to ${path.dirname(primary)}`);
|
|
71
|
+
} catch (e) {
|
|
72
|
+
logger.warn(`[csharp-lsp] legacy migration failed: ${e.message}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
getLocalPath(rid) {
|
|
77
|
+
const { primary, legacy } = this.resolveToolPaths(rid);
|
|
78
|
+
this.migrateLegacyIfNeeded(rid);
|
|
79
|
+
if (fs.existsSync(primary)) return primary;
|
|
80
|
+
if (fs.existsSync(legacy)) return legacy;
|
|
81
|
+
return primary;
|
|
28
82
|
}
|
|
29
83
|
|
|
30
84
|
getVersionMarkerPath(rid) {
|
|
31
|
-
const
|
|
32
|
-
|
|
85
|
+
const { primary, legacy } = this.resolveVersionPaths(rid);
|
|
86
|
+
if (fs.existsSync(primary)) return primary;
|
|
87
|
+
if (fs.existsSync(legacy)) return legacy;
|
|
88
|
+
return primary;
|
|
33
89
|
}
|
|
34
90
|
|
|
35
91
|
readLocalVersion(rid) {
|
|
36
92
|
try {
|
|
37
|
-
const
|
|
38
|
-
if (fs.existsSync(
|
|
93
|
+
const { primary, legacy } = this.resolveVersionPaths(rid);
|
|
94
|
+
if (fs.existsSync(primary)) return fs.readFileSync(primary, 'utf8').trim();
|
|
95
|
+
if (fs.existsSync(legacy)) return fs.readFileSync(legacy, 'utf8').trim();
|
|
39
96
|
} catch {}
|
|
40
97
|
return null;
|
|
41
98
|
}
|
|
42
99
|
|
|
43
100
|
writeLocalVersion(rid, version) {
|
|
44
101
|
try {
|
|
45
|
-
const
|
|
46
|
-
fs.
|
|
102
|
+
const marker = this.getVersionMarkerPath(rid);
|
|
103
|
+
fs.mkdirSync(path.dirname(marker), { recursive: true });
|
|
104
|
+
fs.writeFileSync(marker, String(version || '').trim() + '\n', 'utf8');
|
|
47
105
|
} catch {}
|
|
48
106
|
}
|
|
49
107
|
|
|
@@ -67,7 +125,7 @@ export class CSharpLspUtils {
|
|
|
67
125
|
const entry = manifest?.assets?.[rid];
|
|
68
126
|
if (!entry?.url || !entry?.sha256) throw new Error(`manifest missing entry for ${rid}`);
|
|
69
127
|
|
|
70
|
-
const dest = this.
|
|
128
|
+
const { primary: dest } = this.resolveToolPaths(rid);
|
|
71
129
|
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
72
130
|
const tmp = dest + '.download';
|
|
73
131
|
await this.downloadTo(entry.url, tmp);
|
|
File without changes
|
package/src/lsp/LspRpcClient.js
CHANGED
|
@@ -99,6 +99,20 @@ export class LspRpcClient {
|
|
|
99
99
|
return await this.#requestWithRetry(method, params, 1);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
async validateText(relative, newText) {
|
|
103
|
+
const resp = await this.request('mcp/validateTextEdits', { relative, newText });
|
|
104
|
+
if (!resp) return [];
|
|
105
|
+
const payload = resp.result ?? resp;
|
|
106
|
+
const diagnostics = Array.isArray(payload?.diagnostics) ? payload.diagnostics : [];
|
|
107
|
+
return diagnostics.map((d) => ({
|
|
108
|
+
severity: d?.severity,
|
|
109
|
+
message: d?.message,
|
|
110
|
+
id: d?.id,
|
|
111
|
+
line: d?.line,
|
|
112
|
+
column: d?.column,
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
|
|
102
116
|
async #requestWithRetry(method, params, attempt) {
|
|
103
117
|
await this.ensure();
|
|
104
118
|
const id = this.seq++;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tool definition for
|
|
2
|
+
* Tool definition for analysis_scene_contents_analyze
|
|
3
3
|
*/
|
|
4
4
|
export const analyzeSceneContentsToolDefinition = {
|
|
5
|
-
name: '
|
|
5
|
+
name: 'analysis_scene_contents_analyze',
|
|
6
6
|
description: 'Analyze current scene: object counts, types, prefabs, and memory stats.',
|
|
7
7
|
inputSchema: {
|
|
8
8
|
type: 'object',
|
|
@@ -47,7 +47,7 @@ export async function analyzeSceneContentsHandler(unityConnection, args) {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
// Send command to Unity with provided parameters
|
|
50
|
-
const result = await unityConnection.sendCommand('
|
|
50
|
+
const result = await unityConnection.sendCommand('analysis_scene_contents_analyze', args);
|
|
51
51
|
|
|
52
52
|
// The unityConnection.sendCommand already extracts the result field
|
|
53
53
|
// from the response, so we access properties directly on result
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tool definition for
|
|
2
|
+
* Tool definition for analysis_component_find
|
|
3
3
|
*/
|
|
4
4
|
export const findByComponentToolDefinition = {
|
|
5
|
-
name: '
|
|
5
|
+
name: 'analysis_component_find',
|
|
6
6
|
description: 'Find GameObjects that have a specific component type (scene/prefabs/all).',
|
|
7
7
|
inputSchema: {
|
|
8
8
|
type: 'object',
|
|
@@ -48,7 +48,7 @@ export async function findByComponentHandler(unityConnection, args) {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
// Send command to Unity
|
|
51
|
-
const result = await unityConnection.sendCommand('
|
|
51
|
+
const result = await unityConnection.sendCommand('analysis_component_find', args);
|
|
52
52
|
|
|
53
53
|
// Handle Unity response
|
|
54
54
|
if (result.status === 'error') {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// Tool definition for
|
|
1
|
+
// Tool definition for analysis_animator_state_get
|
|
2
2
|
export const getAnimatorStateToolDefinition = {
|
|
3
|
-
name: '
|
|
3
|
+
name: 'analysis_animator_state_get',
|
|
4
4
|
description: 'Get Animator state: layers, transitions, and parameter values for a GameObject.',
|
|
5
5
|
inputSchema: {
|
|
6
6
|
type: 'object',
|
|
@@ -39,9 +39,9 @@ export const getAnimatorStateToolDefinition = {
|
|
|
39
39
|
}
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
// Tool definition for
|
|
42
|
+
// Tool definition for analysis_animator_runtime_info_get
|
|
43
43
|
export const getAnimatorRuntimeInfoToolDefinition = {
|
|
44
|
-
name: '
|
|
44
|
+
name: 'analysis_animator_runtime_info_get',
|
|
45
45
|
description: 'Get Animator runtime info (IK, root motion, performance) — Play mode only.',
|
|
46
46
|
inputSchema: {
|
|
47
47
|
type: 'object',
|
|
@@ -100,7 +100,7 @@ export async function getAnimatorStateHandler(unityConnection, args) {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
// Send command to Unity
|
|
103
|
-
const result = await unityConnection.sendCommand('
|
|
103
|
+
const result = await unityConnection.sendCommand('analysis_animator_state_get', args);
|
|
104
104
|
|
|
105
105
|
// Check for errors
|
|
106
106
|
if (!result || typeof result === 'string') {
|
|
@@ -222,7 +222,7 @@ export async function getAnimatorRuntimeInfoHandler(unityConnection, args) {
|
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
// Send command to Unity
|
|
225
|
-
const result = await unityConnection.sendCommand('
|
|
225
|
+
const result = await unityConnection.sendCommand('analysis_animator_runtime_info_get', args);
|
|
226
226
|
|
|
227
227
|
// Check for errors
|
|
228
228
|
if (!result || typeof result === 'string') {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tool definition for
|
|
2
|
+
* Tool definition for analysis_component_values_get
|
|
3
3
|
*/
|
|
4
4
|
export const getComponentValuesToolDefinition = {
|
|
5
|
-
name: '
|
|
5
|
+
name: 'analysis_component_values_get',
|
|
6
6
|
description: 'Get properties/values from a component on a GameObject (scene or prefab mode).',
|
|
7
7
|
inputSchema: {
|
|
8
8
|
type: 'object',
|
|
@@ -77,7 +77,7 @@ export async function getComponentValuesHandler(unityConnection, args) {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
// Send command to Unity
|
|
80
|
-
const result = await unityConnection.sendCommand('
|
|
80
|
+
const result = await unityConnection.sendCommand('analysis_component_values_get', args);
|
|
81
81
|
|
|
82
82
|
// The unityConnection.sendCommand already extracts the result field
|
|
83
83
|
// from the response, so we access properties directly on result
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tool definition for
|
|
2
|
+
* Tool definition for analysis_gameobject_details_get
|
|
3
3
|
*/
|
|
4
4
|
export const getGameObjectDetailsToolDefinition = {
|
|
5
|
-
name: '
|
|
5
|
+
name: 'analysis_gameobject_details_get',
|
|
6
6
|
description: 'Get details for a GameObject by name or path (children/components/materials).',
|
|
7
7
|
inputSchema: {
|
|
8
8
|
type: 'object',
|
|
@@ -106,7 +106,7 @@ export async function getGameObjectDetailsHandler(unityConnection, args) {
|
|
|
106
106
|
if (args.maxDepth !== undefined) params.maxDepth = args.maxDepth;
|
|
107
107
|
|
|
108
108
|
// Send command to Unity
|
|
109
|
-
const result = await unityConnection.sendCommand('
|
|
109
|
+
const result = await unityConnection.sendCommand('analysis_gameobject_details_get', args);
|
|
110
110
|
|
|
111
111
|
// The unityConnection.sendCommand already extracts the result field
|
|
112
112
|
// from the response, so we access properties directly on result
|