@akiojin/unity-mcp-server 2.40.2 → 2.40.3

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.
Files changed (90) hide show
  1. package/README.md +21 -0
  2. package/bin/unity-mcp-server +1 -1
  3. package/package.json +1 -1
  4. package/src/core/codeIndex.js +64 -15
  5. package/src/core/server.js +3 -34
  6. package/src/handlers/analysis/AnalyzeSceneContentsToolHandler.js +27 -24
  7. package/src/handlers/analysis/FindByComponentToolHandler.js +4 -1
  8. package/src/handlers/analysis/GetAnimatorStateToolHandler.js +5 -5
  9. package/src/handlers/analysis/GetComponentValuesToolHandler.js +4 -1
  10. package/src/handlers/analysis/GetGameObjectDetailsToolHandler.js +27 -24
  11. package/src/handlers/analysis/GetInputActionsStateToolHandler.js +5 -5
  12. package/src/handlers/analysis/GetObjectReferencesToolHandler.js +4 -1
  13. package/src/handlers/asset/AssetDatabaseManageToolHandler.js +24 -6
  14. package/src/handlers/asset/AssetDependencyAnalyzeToolHandler.js +21 -11
  15. package/src/handlers/asset/AssetImportSettingsManageToolHandler.js +7 -7
  16. package/src/handlers/asset/AssetMaterialCreateToolHandler.js +78 -81
  17. package/src/handlers/asset/AssetMaterialModifyToolHandler.js +57 -61
  18. package/src/handlers/asset/AssetPrefabCreateToolHandler.js +61 -64
  19. package/src/handlers/asset/AssetPrefabExitModeToolHandler.js +9 -13
  20. package/src/handlers/asset/AssetPrefabInstantiateToolHandler.js +110 -116
  21. package/src/handlers/asset/AssetPrefabModifyToolHandler.js +58 -58
  22. package/src/handlers/asset/AssetPrefabOpenToolHandler.js +7 -5
  23. package/src/handlers/asset/AssetPrefabSaveToolHandler.js +13 -6
  24. package/src/handlers/compilation/CompilationGetStateToolHandler.js +4 -3
  25. package/src/handlers/component/ComponentAddToolHandler.js +2 -2
  26. package/src/handlers/component/ComponentGetTypesToolHandler.js +17 -21
  27. package/src/handlers/component/ComponentListToolHandler.js +5 -3
  28. package/src/handlers/component/ComponentModifyToolHandler.js +3 -3
  29. package/src/handlers/component/ComponentRemoveToolHandler.js +2 -2
  30. package/src/handlers/console/ConsoleClearToolHandler.js +36 -46
  31. package/src/handlers/editor/EditorLayersManageToolHandler.js +7 -6
  32. package/src/handlers/editor/EditorTagsManageToolHandler.js +20 -11
  33. package/src/handlers/editor/EditorToolsManageToolHandler.js +2 -2
  34. package/src/handlers/editor/EditorWindowsManageToolHandler.js +6 -5
  35. package/src/handlers/gameobject/GameObjectCreateToolHandler.js +62 -66
  36. package/src/handlers/gameobject/GameObjectDeleteToolHandler.js +9 -9
  37. package/src/handlers/gameobject/GameObjectFindToolHandler.js +13 -11
  38. package/src/handlers/gameobject/GameObjectGetHierarchyToolHandler.js +22 -16
  39. package/src/handlers/input/InputActionAddToolHandler.js +2 -2
  40. package/src/handlers/input/InputActionMapCreateToolHandler.js +2 -2
  41. package/src/handlers/input/InputActionMapRemoveToolHandler.js +2 -2
  42. package/src/handlers/input/InputActionRemoveToolHandler.js +2 -2
  43. package/src/handlers/input/InputBindingAddToolHandler.js +2 -2
  44. package/src/handlers/input/InputBindingCompositeCreateToolHandler.js +2 -2
  45. package/src/handlers/input/InputBindingRemoveAllToolHandler.js +2 -2
  46. package/src/handlers/input/InputBindingRemoveToolHandler.js +2 -2
  47. package/src/handlers/input/InputControlSchemesManageToolHandler.js +2 -2
  48. package/src/handlers/package/PackageManagerToolHandler.js +41 -44
  49. package/src/handlers/package/RegistryConfigToolHandler.js +28 -7
  50. package/src/handlers/playmode/PlaymodeGetStateToolHandler.js +12 -16
  51. package/src/handlers/playmode/PlaymodePauseToolHandler.js +8 -12
  52. package/src/handlers/playmode/PlaymodeWaitForStateToolHandler.js +6 -3
  53. package/src/handlers/scene/GetSceneInfoToolHandler.js +11 -11
  54. package/src/handlers/scene/SceneCreateToolHandler.js +28 -31
  55. package/src/handlers/scene/SceneListToolHandler.js +21 -24
  56. package/src/handlers/scene/SceneLoadToolHandler.js +27 -29
  57. package/src/handlers/scene/SceneSaveToolHandler.js +19 -22
  58. package/src/handlers/screenshot/ScreenshotCaptureToolHandler.js +88 -66
  59. package/src/handlers/script/CodeIndexStatusToolHandler.js +4 -3
  60. package/src/handlers/script/CodeIndexUpdateToolHandler.js +24 -14
  61. package/src/handlers/script/ScriptCreateClassToolHandler.js +44 -9
  62. package/src/handlers/script/ScriptPackagesListToolHandler.js +91 -91
  63. package/src/handlers/script/ScriptRefactorRenameToolHandler.js +80 -71
  64. package/src/handlers/script/ScriptRemoveSymbolToolHandler.js +21 -7
  65. package/src/handlers/script/ScriptSearchToolHandler.js +299 -266
  66. package/src/handlers/script/ScriptSymbolsGetToolHandler.js +88 -79
  67. package/src/handlers/settings/SettingsGetToolHandler.js +28 -13
  68. package/src/handlers/settings/SettingsUpdateToolHandler.js +20 -6
  69. package/src/handlers/ui/UIClickElementToolHandler.js +87 -96
  70. package/src/handlers/ui/UIFindElementsToolHandler.js +45 -55
  71. package/src/handlers/ui/UIGetElementStateToolHandler.js +35 -43
  72. package/src/handlers/ui/UISetElementValueToolHandler.js +42 -49
  73. package/src/handlers/ui/UISimulateInputToolHandler.js +134 -136
  74. package/src/handlers/video/VideoCaptureForToolHandler.js +24 -7
  75. package/src/lsp/LspRpcClient.js +24 -12
  76. package/src/tools/analysis/analyzeSceneContents.js +85 -85
  77. package/src/tools/analysis/findByComponent.js +73 -73
  78. package/src/tools/analysis/getAnimatorState.js +287 -287
  79. package/src/tools/analysis/getComponentValues.js +161 -161
  80. package/src/tools/analysis/getGameObjectDetails.js +138 -138
  81. package/src/tools/analysis/getInputActionsState.js +291 -291
  82. package/src/tools/analysis/getObjectReferences.js +72 -72
  83. package/src/tools/input/inputActionsEditor.js +522 -474
  84. package/src/tools/scene/createScene.js +98 -97
  85. package/src/tools/scene/getSceneInfo.js +82 -81
  86. package/src/tools/scene/listScenes.js +70 -69
  87. package/src/tools/scene/loadScene.js +108 -106
  88. package/src/tools/scene/saveScene.js +78 -77
  89. package/src/tools/system/ping.js +9 -12
  90. package/src/utils/validators.js +2 -2
@@ -1,50 +1,42 @@
1
1
  import { BaseToolHandler } from '../base/BaseToolHandler.js';
2
2
 
3
3
  export class UIGetElementStateToolHandler extends BaseToolHandler {
4
- constructor(unityConnection) {
5
- super(
6
- 'ui_get_element_state',
7
- 'Get detailed state information about UI elements',
8
- {
9
- type: 'object',
10
- properties: {
11
- elementPath: {
12
- type: 'string',
13
- description: 'Full hierarchy path to the UI element'
14
- },
15
- includeChildren: {
16
- type: 'boolean',
17
- description: 'Include child element states (default: false)'
18
- },
19
- includeInteractableInfo: {
20
- type: 'boolean',
21
- description: 'Include interaction capabilities (default: true)'
22
- }
23
- },
24
- required: ['elementPath']
25
- }
26
- );
27
- this.unityConnection = unityConnection;
28
- }
29
-
30
- async execute(params) {
31
- const {
32
- elementPath,
33
- includeChildren = false,
34
- includeInteractableInfo = true
35
- } = params;
36
-
37
- // Ensure connected
38
- if (!this.unityConnection.isConnected()) {
39
- await this.unityConnection.connect();
4
+ constructor(unityConnection) {
5
+ super('ui_get_element_state', 'Get detailed state information about UI elements', {
6
+ type: 'object',
7
+ properties: {
8
+ elementPath: {
9
+ type: 'string',
10
+ description: 'Full hierarchy path to the UI element'
11
+ },
12
+ includeChildren: {
13
+ type: 'boolean',
14
+ description: 'Include child element states (default: false)'
15
+ },
16
+ includeInteractableInfo: {
17
+ type: 'boolean',
18
+ description: 'Include interaction capabilities (default: true)'
40
19
  }
20
+ },
21
+ required: ['elementPath']
22
+ });
23
+ this.unityConnection = unityConnection;
24
+ }
41
25
 
42
- const result = await this.unityConnection.sendCommand('get_ui_element_state', {
43
- elementPath,
44
- includeChildren,
45
- includeInteractableInfo
46
- });
26
+ async execute(params) {
27
+ const { elementPath, includeChildren = false, includeInteractableInfo = true } = params;
47
28
 
48
- return result;
29
+ // Ensure connected
30
+ if (!this.unityConnection.isConnected()) {
31
+ await this.unityConnection.connect();
49
32
  }
50
- }
33
+
34
+ const result = await this.unityConnection.sendCommand('get_ui_element_state', {
35
+ elementPath,
36
+ includeChildren,
37
+ includeInteractableInfo
38
+ });
39
+
40
+ return result;
41
+ }
42
+ }
@@ -1,57 +1,50 @@
1
1
  import { BaseToolHandler } from '../base/BaseToolHandler.js';
2
2
 
3
3
  export class UISetElementValueToolHandler extends BaseToolHandler {
4
- constructor(unityConnection) {
5
- super(
6
- 'ui_set_element_value',
7
- 'Set values for UI input elements',
8
- {
9
- type: 'object',
10
- properties: {
11
- elementPath: {
12
- type: 'string',
13
- description: 'Full hierarchy path to the UI element'
14
- },
15
- value: {
16
- anyOf: [
17
- { type: 'string' },
18
- { type: 'number' },
19
- { type: 'boolean' },
20
- { type: 'object' },
21
- { type: 'array' },
22
- { type: 'null' }
23
- ],
24
- description: 'New value to set. Supports string, number, boolean, object, array, or null depending on the UI element type.'
25
- },
26
- triggerEvents: {
27
- type: 'boolean',
28
- description: 'Whether to trigger associated events (default: true)'
29
- }
30
- },
31
- required: ['elementPath', 'value']
32
- }
33
- );
34
- this.unityConnection = unityConnection;
35
- }
36
-
37
- async execute(params) {
38
- const {
39
- elementPath,
40
- value,
41
- triggerEvents = true
42
- } = params;
43
-
44
- // Ensure connected
45
- if (!this.unityConnection.isConnected()) {
46
- await this.unityConnection.connect();
4
+ constructor(unityConnection) {
5
+ super('ui_set_element_value', 'Set values for UI input elements', {
6
+ type: 'object',
7
+ properties: {
8
+ elementPath: {
9
+ type: 'string',
10
+ description: 'Full hierarchy path to the UI element'
11
+ },
12
+ value: {
13
+ anyOf: [
14
+ { type: 'string' },
15
+ { type: 'number' },
16
+ { type: 'boolean' },
17
+ { type: 'object' },
18
+ { type: 'array' },
19
+ { type: 'null' }
20
+ ],
21
+ description:
22
+ 'New value to set. Supports string, number, boolean, object, array, or null depending on the UI element type.'
23
+ },
24
+ triggerEvents: {
25
+ type: 'boolean',
26
+ description: 'Whether to trigger associated events (default: true)'
47
27
  }
28
+ },
29
+ required: ['elementPath', 'value']
30
+ });
31
+ this.unityConnection = unityConnection;
32
+ }
48
33
 
49
- const result = await this.unityConnection.sendCommand('set_ui_element_value', {
50
- elementPath,
51
- value,
52
- triggerEvents
53
- });
34
+ async execute(params) {
35
+ const { elementPath, value, triggerEvents = true } = params;
54
36
 
55
- return result;
37
+ // Ensure connected
38
+ if (!this.unityConnection.isConnected()) {
39
+ await this.unityConnection.connect();
56
40
  }
41
+
42
+ const result = await this.unityConnection.sendCommand('set_ui_element_value', {
43
+ elementPath,
44
+ value,
45
+ triggerEvents
46
+ });
47
+
48
+ return result;
49
+ }
57
50
  }
@@ -1,156 +1,154 @@
1
1
  import { BaseToolHandler } from '../base/BaseToolHandler.js';
2
2
 
3
3
  export class UISimulateInputToolHandler extends BaseToolHandler {
4
- constructor(unityConnection) {
5
- super(
6
- 'ui_simulate_input',
7
- 'Simulate complex UI interactions and input sequences',
8
- {
4
+ constructor(unityConnection) {
5
+ super('ui_simulate_input', 'Simulate complex UI interactions and input sequences', {
6
+ type: 'object',
7
+ properties: {
8
+ // Option 1: Simple single input
9
+ elementPath: {
10
+ type: 'string',
11
+ description: 'Target UI element path (for simple input)'
12
+ },
13
+ inputType: {
14
+ type: 'string',
15
+ enum: ['click', 'doubleclick', 'rightclick', 'hover', 'focus', 'type'],
16
+ description: 'Type of input to simulate (for simple input)'
17
+ },
18
+ inputData: {
19
+ type: 'string',
20
+ description: 'Data for input (e.g., text to type)'
21
+ },
22
+ // Option 2: Complex sequence
23
+ inputSequence: {
24
+ type: 'array',
25
+ items: {
26
+ type: 'object',
27
+ properties: {
28
+ type: {
29
+ type: 'string',
30
+ description: 'Action type (click, setvalue)'
31
+ },
32
+ params: {
9
33
  type: 'object',
10
- properties: {
11
- // Option 1: Simple single input
12
- elementPath: {
13
- type: 'string',
14
- description: 'Target UI element path (for simple input)'
15
- },
16
- inputType: {
17
- type: 'string',
18
- enum: ['click', 'doubleclick', 'rightclick', 'hover', 'focus', 'type'],
19
- description: 'Type of input to simulate (for simple input)'
20
- },
21
- inputData: {
22
- type: 'string',
23
- description: 'Data for input (e.g., text to type)'
24
- },
25
- // Option 2: Complex sequence
26
- inputSequence: {
27
- type: 'array',
28
- items: {
29
- type: 'object',
30
- properties: {
31
- type: {
32
- type: 'string',
33
- description: 'Action type (click, setvalue)'
34
- },
35
- params: {
36
- type: 'object',
37
- description: 'Parameters for the action'
38
- }
39
- },
40
- required: ['type', 'params']
41
- },
42
- description: 'Array of input actions to perform (for complex input)'
43
- },
44
- waitBetween: {
45
- type: 'number',
46
-
47
- minimum: 0,
48
- maximum: 10000,
49
- description: 'Delay between actions in milliseconds'
50
- },
51
- validateState: {
52
- type: 'boolean',
53
- description: 'Validate UI state between actions (default: true)'
54
- }
55
- }
56
- }
57
- );
58
- this.unityConnection = unityConnection;
34
+ description: 'Parameters for the action'
35
+ }
36
+ },
37
+ required: ['type', 'params']
38
+ },
39
+ description: 'Array of input actions to perform (for complex input)'
40
+ },
41
+ waitBetween: {
42
+ type: 'number',
43
+
44
+ minimum: 0,
45
+ maximum: 10000,
46
+ description: 'Delay between actions in milliseconds'
47
+ },
48
+ validateState: {
49
+ type: 'boolean',
50
+ description: 'Validate UI state between actions (default: true)'
51
+ }
52
+ }
53
+ });
54
+ this.unityConnection = unityConnection;
55
+ }
56
+
57
+ validate(params) {
58
+ // Check if using simple mode or complex mode
59
+ const hasSimpleParams = params.elementPath && params.inputType;
60
+ const hasComplexParams = params.inputSequence;
61
+
62
+ if (!hasSimpleParams && !hasComplexParams) {
63
+ throw new Error('Either (elementPath + inputType) or inputSequence is required');
59
64
  }
60
65
 
61
- validate(params) {
62
- // Check if using simple mode or complex mode
63
- const hasSimpleParams = params.elementPath && params.inputType;
64
- const hasComplexParams = params.inputSequence;
66
+ if (hasSimpleParams && hasComplexParams) {
67
+ throw new Error('Cannot use both simple and complex input modes simultaneously');
68
+ }
65
69
 
66
- if (!hasSimpleParams && !hasComplexParams) {
67
- throw new Error('Either (elementPath + inputType) or inputSequence is required');
68
- }
70
+ // Validate simple mode
71
+ if (hasSimpleParams) {
72
+ if (!params.elementPath || typeof params.elementPath !== 'string') {
73
+ throw new Error('elementPath must be a non-empty string');
74
+ }
69
75
 
70
- if (hasSimpleParams && hasComplexParams) {
71
- throw new Error('Cannot use both simple and complex input modes simultaneously');
72
- }
76
+ const validInputTypes = ['click', 'doubleclick', 'rightclick', 'hover', 'focus', 'type'];
77
+ if (!validInputTypes.includes(params.inputType)) {
78
+ throw new Error(`inputType must be one of: ${validInputTypes.join(', ')}`);
79
+ }
73
80
 
74
- // Validate simple mode
75
- if (hasSimpleParams) {
76
- if (!params.elementPath || typeof params.elementPath !== 'string') {
77
- throw new Error('elementPath must be a non-empty string');
78
- }
81
+ if (params.inputType === 'type' && !params.inputData) {
82
+ throw new Error('inputData is required when inputType is "type"');
83
+ }
84
+ }
79
85
 
80
- const validInputTypes = ['click', 'doubleclick', 'rightclick', 'hover', 'focus', 'type'];
81
- if (!validInputTypes.includes(params.inputType)) {
82
- throw new Error(`inputType must be one of: ${validInputTypes.join(', ')}`);
83
- }
86
+ // Validate complex mode
87
+ if (hasComplexParams) {
88
+ if (!Array.isArray(params.inputSequence)) {
89
+ throw new Error('inputSequence must be an array');
90
+ }
84
91
 
85
- if (params.inputType === 'type' && !params.inputData) {
86
- throw new Error('inputData is required when inputType is "type"');
87
- }
88
- }
92
+ if (params.inputSequence.length === 0) {
93
+ throw new Error('inputSequence must contain at least one action');
94
+ }
89
95
 
90
- // Validate complex mode
91
- if (hasComplexParams) {
92
- if (!Array.isArray(params.inputSequence)) {
93
- throw new Error('inputSequence must be an array');
94
- }
95
-
96
- if (params.inputSequence.length === 0) {
97
- throw new Error('inputSequence must contain at least one action');
98
- }
99
-
100
- // Validate each action
101
- for (const action of params.inputSequence) {
102
- if (!action.type || !action.params) {
103
- throw new Error('Each action must have type and params');
104
- }
105
- }
96
+ // Validate each action
97
+ for (const action of params.inputSequence) {
98
+ if (!action.type || !action.params) {
99
+ throw new Error('Each action must have type and params');
106
100
  }
101
+ }
102
+ }
107
103
 
108
- // Validate waitBetween range
109
- if (params.waitBetween !== undefined) {
110
- const wait = params.waitBetween;
111
- if (typeof wait !== 'number' || wait < 0 || wait > 10000) {
112
- throw new Error('waitBetween must be between 0 and 10000 milliseconds');
113
- }
114
- }
104
+ // Validate waitBetween range
105
+ if (params.waitBetween !== undefined) {
106
+ const wait = params.waitBetween;
107
+ if (typeof wait !== 'number' || wait < 0 || wait > 10000) {
108
+ throw new Error('waitBetween must be between 0 and 10000 milliseconds');
109
+ }
110
+ }
111
+ }
112
+
113
+ async execute(params) {
114
+ const {
115
+ elementPath,
116
+ inputType,
117
+ inputData,
118
+ inputSequence,
119
+ waitBetween = 100,
120
+ validateState = true
121
+ } = params;
122
+
123
+ // Ensure connected
124
+ if (!this.unityConnection.isConnected()) {
125
+ await this.unityConnection.connect();
115
126
  }
116
127
 
117
- async execute(params) {
118
- const {
119
- elementPath,
120
- inputType,
121
- inputData,
122
- inputSequence,
123
- waitBetween = 100,
124
- validateState = true
125
- } = params;
126
-
127
- // Ensure connected
128
- if (!this.unityConnection.isConnected()) {
129
- await this.unityConnection.connect();
130
- }
128
+ let actualInputSequence;
131
129
 
132
- let actualInputSequence;
133
-
134
- // Handle simple mode - convert to sequence format
135
- if (elementPath && inputType) {
136
- actualInputSequence = [{
137
- type: inputType,
138
- params: {
139
- elementPath,
140
- inputData: inputData || null
141
- }
142
- }];
143
- } else {
144
- // Use provided sequence
145
- actualInputSequence = inputSequence;
130
+ // Handle simple mode - convert to sequence format
131
+ if (elementPath && inputType) {
132
+ actualInputSequence = [
133
+ {
134
+ type: inputType,
135
+ params: {
136
+ elementPath,
137
+ inputData: inputData || null
138
+ }
146
139
  }
140
+ ];
141
+ } else {
142
+ // Use provided sequence
143
+ actualInputSequence = inputSequence;
144
+ }
147
145
 
148
- const result = await this.unityConnection.sendCommand('simulate_ui_input', {
149
- inputSequence: actualInputSequence,
150
- waitBetween,
151
- validateState
152
- });
146
+ const result = await this.unityConnection.sendCommand('simulate_ui_input', {
147
+ inputSequence: actualInputSequence,
148
+ waitBetween,
149
+ validateState
150
+ });
153
151
 
154
- return result;
155
- }
156
- }
152
+ return result;
153
+ }
154
+ }
@@ -12,12 +12,19 @@ export class VideoCaptureForToolHandler extends BaseToolHandler {
12
12
  {
13
13
  type: 'object',
14
14
  properties: {
15
- captureMode: { type: 'string', enum: ['game'], description: 'Capture source. Currently only "game" supported.' },
15
+ captureMode: {
16
+ type: 'string',
17
+ enum: ['game'],
18
+ description: 'Capture source. Currently only "game" supported.'
19
+ },
16
20
  width: { type: 'number', description: 'Output width (0 = default 1280)' },
17
21
  height: { type: 'number', description: 'Output height (0 = default 720)' },
18
22
  fps: { type: 'number', description: 'Frames per second (default 30)' },
19
23
  durationSec: { type: 'number', description: 'Duration to record in seconds' },
20
- play: { type: 'boolean', description: 'Enter Play Mode before recording (default true if not already playing)' }
24
+ play: {
25
+ type: 'boolean',
26
+ description: 'Enter Play Mode before recording (default true if not already playing)'
27
+ }
21
28
  },
22
29
  required: ['durationSec']
23
30
  }
@@ -36,13 +43,18 @@ export class VideoCaptureForToolHandler extends BaseToolHandler {
36
43
  try {
37
44
  const s0 = await this.unityConnection.sendCommand('playmode_get_state', {});
38
45
  needPlay = !(s0 && s0.isPlaying);
39
- } catch { needPlay = true; }
46
+ } catch {
47
+ needPlay = true;
48
+ }
40
49
  }
41
50
  if (needPlay) {
42
51
  await this.unityConnection.sendCommand('playmode_play', {});
43
52
  for (let i = 0; i < 60; i++) {
44
53
  const s = await this.unityConnection.sendCommand('get_editor_state', {});
45
- if (s && s.isPlaying) { enteredPlay = true; break; }
54
+ if (s && s.isPlaying) {
55
+ enteredPlay = true;
56
+ break;
57
+ }
46
58
  await sleep(250);
47
59
  }
48
60
  }
@@ -62,7 +74,8 @@ export class VideoCaptureForToolHandler extends BaseToolHandler {
62
74
  }
63
75
 
64
76
  // Wait until stopped (status reports isRecording=false)
65
- const deadline = Date.now() + Math.max(0, Math.floor((params.durationSec || 0) * 1000)) + 1500; // small buffer
77
+ const deadline =
78
+ Date.now() + Math.max(0, Math.floor((params.durationSec || 0) * 1000)) + 1500; // small buffer
66
79
  let lastStatus = null;
67
80
  while (Date.now() < deadline) {
68
81
  lastStatus = await this.unityConnection.sendCommand('video_capture_status', {});
@@ -88,9 +101,13 @@ export class VideoCaptureForToolHandler extends BaseToolHandler {
88
101
  return { error: e.message, code: 'CLIENT_ERROR' };
89
102
  } finally {
90
103
  // If we entered play, attempt to leave play (best-effort)
91
- try { if (enteredPlay) await this.unityConnection.sendCommand('playmode_stop', {}); } catch {}
104
+ try {
105
+ if (enteredPlay) await this.unityConnection.sendCommand('playmode_stop', {});
106
+ } catch {}
92
107
  }
93
108
  }
94
109
  }
95
110
 
96
- function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
111
+ function sleep(ms) {
112
+ return new Promise(r => setTimeout(r, ms));
113
+ }
@@ -18,14 +18,18 @@ export class LspRpcClient {
18
18
  this.proc = await this.mgr.ensureStarted();
19
19
  // Attach data handler once per process
20
20
  if (this.boundOnData) {
21
- try { this.proc.stdout.off('data', this.boundOnData); } catch {}
21
+ try {
22
+ this.proc.stdout.off('data', this.boundOnData);
23
+ } catch {}
22
24
  }
23
- this.boundOnData = (chunk) => this.onData(chunk);
25
+ this.boundOnData = chunk => this.onData(chunk);
24
26
  this.proc.stdout.on('data', this.boundOnData);
25
27
  // On process close: reject all pending and reset state
26
28
  this.proc.on('close', () => {
27
29
  for (const [id, p] of Array.from(this.pending.entries())) {
28
- try { p.reject(new Error('LSP process exited')); } catch {}
30
+ try {
31
+ p.reject(new Error('LSP process exited'));
32
+ } catch {}
29
33
  this.pending.delete(id);
30
34
  }
31
35
  this.initialized = false;
@@ -53,7 +57,9 @@ export class LspRpcClient {
53
57
  this.pending.get(msg.id).resolve(msg);
54
58
  this.pending.delete(msg.id);
55
59
  }
56
- } catch { /* ignore */ }
60
+ } catch {
61
+ /* ignore */
62
+ }
57
63
  }
58
64
  }
59
65
 
@@ -72,9 +78,9 @@ export class LspRpcClient {
72
78
  method: 'initialize',
73
79
  params: {
74
80
  processId: process.pid,
75
- rootUri: this.projectRoot ? ('file://' + String(this.projectRoot).replace(/\\/g, '/')) : null,
81
+ rootUri: this.projectRoot ? 'file://' + String(this.projectRoot).replace(/\\/g, '/') : null,
76
82
  capabilities: {},
77
- workspaceFolders: null,
83
+ workspaceFolders: null
78
84
  }
79
85
  };
80
86
  const timeoutMs = Math.max(5000, Math.min(60000, config.lsp?.requestTimeoutMs || 60000));
@@ -104,12 +110,12 @@ export class LspRpcClient {
104
110
  if (!resp) return [];
105
111
  const payload = resp.result ?? resp;
106
112
  const diagnostics = Array.isArray(payload?.diagnostics) ? payload.diagnostics : [];
107
- return diagnostics.map((d) => ({
113
+ return diagnostics.map(d => ({
108
114
  severity: d?.severity,
109
115
  message: d?.message,
110
116
  id: d?.id,
111
117
  line: d?.line,
112
- column: d?.column,
118
+ column: d?.column
113
119
  }));
114
120
  }
115
121
 
@@ -130,17 +136,23 @@ export class LspRpcClient {
130
136
  this.writeMessage({ jsonrpc: '2.0', id, method, params });
131
137
  return await p;
132
138
  } catch (e) {
133
- const msg = String(e && e.message || e);
139
+ const msg = String((e && e.message) || e);
134
140
  const recoverable = /timed out|LSP process exited/i.test(msg);
135
141
  if (recoverable && attempt === 1) {
136
142
  // Auto-reinit and retry once
137
- try { await this.mgr.stop(0); } catch {}
138
- this.proc = null; this.initialized = false; this.buf = Buffer.alloc(0);
143
+ try {
144
+ await this.mgr.stop(0);
145
+ } catch {}
146
+ this.proc = null;
147
+ this.initialized = false;
148
+ this.buf = Buffer.alloc(0);
139
149
  logger.warn(`[csharp-lsp] recoverable error on ${method}: ${msg}. Retrying once...`);
140
150
  return await this.#requestWithRetry(method, params, attempt + 1);
141
151
  }
142
152
  // Standardize error message
143
- const hint = recoverable ? 'The server was restarted. Try again if the issue persists.' : 'Check request parameters or increase lsp.requestTimeoutMs.';
153
+ const hint = recoverable
154
+ ? 'The server was restarted. Try again if the issue persists.'
155
+ : 'Check request parameters or increase lsp.requestTimeoutMs.';
144
156
  throw new Error(`[${method}] failed: ${msg}. ${hint}`);
145
157
  }
146
158
  }