@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.
- package/README.md +21 -0
- package/bin/unity-mcp-server +1 -1
- package/package.json +1 -1
- package/src/core/codeIndex.js +64 -15
- package/src/core/server.js +3 -34
- package/src/handlers/analysis/AnalyzeSceneContentsToolHandler.js +27 -24
- package/src/handlers/analysis/FindByComponentToolHandler.js +4 -1
- package/src/handlers/analysis/GetAnimatorStateToolHandler.js +5 -5
- package/src/handlers/analysis/GetComponentValuesToolHandler.js +4 -1
- package/src/handlers/analysis/GetGameObjectDetailsToolHandler.js +27 -24
- package/src/handlers/analysis/GetInputActionsStateToolHandler.js +5 -5
- package/src/handlers/analysis/GetObjectReferencesToolHandler.js +4 -1
- package/src/handlers/asset/AssetDatabaseManageToolHandler.js +24 -6
- package/src/handlers/asset/AssetDependencyAnalyzeToolHandler.js +21 -11
- package/src/handlers/asset/AssetImportSettingsManageToolHandler.js +7 -7
- package/src/handlers/asset/AssetMaterialCreateToolHandler.js +78 -81
- package/src/handlers/asset/AssetMaterialModifyToolHandler.js +57 -61
- package/src/handlers/asset/AssetPrefabCreateToolHandler.js +61 -64
- package/src/handlers/asset/AssetPrefabExitModeToolHandler.js +9 -13
- package/src/handlers/asset/AssetPrefabInstantiateToolHandler.js +110 -116
- package/src/handlers/asset/AssetPrefabModifyToolHandler.js +58 -58
- package/src/handlers/asset/AssetPrefabOpenToolHandler.js +7 -5
- package/src/handlers/asset/AssetPrefabSaveToolHandler.js +13 -6
- package/src/handlers/compilation/CompilationGetStateToolHandler.js +4 -3
- package/src/handlers/component/ComponentAddToolHandler.js +2 -2
- package/src/handlers/component/ComponentGetTypesToolHandler.js +17 -21
- package/src/handlers/component/ComponentListToolHandler.js +5 -3
- package/src/handlers/component/ComponentModifyToolHandler.js +3 -3
- package/src/handlers/component/ComponentRemoveToolHandler.js +2 -2
- package/src/handlers/console/ConsoleClearToolHandler.js +36 -46
- package/src/handlers/editor/EditorLayersManageToolHandler.js +7 -6
- package/src/handlers/editor/EditorTagsManageToolHandler.js +20 -11
- package/src/handlers/editor/EditorToolsManageToolHandler.js +2 -2
- package/src/handlers/editor/EditorWindowsManageToolHandler.js +6 -5
- package/src/handlers/gameobject/GameObjectCreateToolHandler.js +62 -66
- package/src/handlers/gameobject/GameObjectDeleteToolHandler.js +9 -9
- package/src/handlers/gameobject/GameObjectFindToolHandler.js +13 -11
- package/src/handlers/gameobject/GameObjectGetHierarchyToolHandler.js +22 -16
- package/src/handlers/input/InputActionAddToolHandler.js +2 -2
- package/src/handlers/input/InputActionMapCreateToolHandler.js +2 -2
- package/src/handlers/input/InputActionMapRemoveToolHandler.js +2 -2
- package/src/handlers/input/InputActionRemoveToolHandler.js +2 -2
- package/src/handlers/input/InputBindingAddToolHandler.js +2 -2
- package/src/handlers/input/InputBindingCompositeCreateToolHandler.js +2 -2
- package/src/handlers/input/InputBindingRemoveAllToolHandler.js +2 -2
- package/src/handlers/input/InputBindingRemoveToolHandler.js +2 -2
- package/src/handlers/input/InputControlSchemesManageToolHandler.js +2 -2
- package/src/handlers/package/PackageManagerToolHandler.js +41 -44
- package/src/handlers/package/RegistryConfigToolHandler.js +28 -7
- package/src/handlers/playmode/PlaymodeGetStateToolHandler.js +12 -16
- package/src/handlers/playmode/PlaymodePauseToolHandler.js +8 -12
- package/src/handlers/playmode/PlaymodeWaitForStateToolHandler.js +6 -3
- package/src/handlers/scene/GetSceneInfoToolHandler.js +11 -11
- package/src/handlers/scene/SceneCreateToolHandler.js +28 -31
- package/src/handlers/scene/SceneListToolHandler.js +21 -24
- package/src/handlers/scene/SceneLoadToolHandler.js +27 -29
- package/src/handlers/scene/SceneSaveToolHandler.js +19 -22
- package/src/handlers/screenshot/ScreenshotCaptureToolHandler.js +88 -66
- package/src/handlers/script/CodeIndexStatusToolHandler.js +4 -3
- package/src/handlers/script/CodeIndexUpdateToolHandler.js +24 -14
- package/src/handlers/script/ScriptCreateClassToolHandler.js +44 -9
- package/src/handlers/script/ScriptPackagesListToolHandler.js +91 -91
- package/src/handlers/script/ScriptRefactorRenameToolHandler.js +80 -71
- package/src/handlers/script/ScriptRemoveSymbolToolHandler.js +21 -7
- package/src/handlers/script/ScriptSearchToolHandler.js +299 -266
- package/src/handlers/script/ScriptSymbolsGetToolHandler.js +88 -79
- package/src/handlers/settings/SettingsGetToolHandler.js +28 -13
- package/src/handlers/settings/SettingsUpdateToolHandler.js +20 -6
- package/src/handlers/ui/UIClickElementToolHandler.js +87 -96
- package/src/handlers/ui/UIFindElementsToolHandler.js +45 -55
- package/src/handlers/ui/UIGetElementStateToolHandler.js +35 -43
- package/src/handlers/ui/UISetElementValueToolHandler.js +42 -49
- package/src/handlers/ui/UISimulateInputToolHandler.js +134 -136
- package/src/handlers/video/VideoCaptureForToolHandler.js +24 -7
- package/src/lsp/LspRpcClient.js +24 -12
- package/src/tools/analysis/analyzeSceneContents.js +85 -85
- package/src/tools/analysis/findByComponent.js +73 -73
- package/src/tools/analysis/getAnimatorState.js +287 -287
- package/src/tools/analysis/getComponentValues.js +161 -161
- package/src/tools/analysis/getGameObjectDetails.js +138 -138
- package/src/tools/analysis/getInputActionsState.js +291 -291
- package/src/tools/analysis/getObjectReferences.js +72 -72
- package/src/tools/input/inputActionsEditor.js +522 -474
- package/src/tools/scene/createScene.js +98 -97
- package/src/tools/scene/getSceneInfo.js +82 -81
- package/src/tools/scene/listScenes.js +70 -69
- package/src/tools/scene/loadScene.js +108 -106
- package/src/tools/scene/saveScene.js +78 -77
- package/src/tools/system/ping.js +9 -12
- package/src/utils/validators.js +2 -2
|
@@ -24,8 +24,9 @@ export class CodeIndexStatusToolHandler extends BaseToolHandler {
|
|
|
24
24
|
|
|
25
25
|
async execute() {
|
|
26
26
|
const jobManager = this.jobManager;
|
|
27
|
-
const buildJobs = jobManager
|
|
28
|
-
.
|
|
27
|
+
const buildJobs = jobManager
|
|
28
|
+
.getAllJobs()
|
|
29
|
+
.filter(job => typeof job?.id === 'string' && job.id.startsWith('build-'))
|
|
29
30
|
.sort((a, b) => new Date(b.startedAt || 0).getTime() - new Date(a.startedAt || 0).getTime());
|
|
30
31
|
const latestBuildJob = buildJobs.length > 0 ? buildJobs[0] : null;
|
|
31
32
|
|
|
@@ -61,7 +62,7 @@ export class CodeIndexStatusToolHandler extends BaseToolHandler {
|
|
|
61
62
|
let totalFiles = 0;
|
|
62
63
|
const breakdown = { assets: 0, packages: 0, packageCache: 0, other: 0 };
|
|
63
64
|
|
|
64
|
-
const visit =
|
|
65
|
+
const visit = targetPath => {
|
|
65
66
|
try {
|
|
66
67
|
if (!fs.existsSync(targetPath)) return;
|
|
67
68
|
const stats = fs.statSync(targetPath);
|
|
@@ -159,7 +159,9 @@ export class CodeIndexUpdateToolHandler extends BaseToolHandler {
|
|
|
159
159
|
let lastErr = null;
|
|
160
160
|
for (let attempt = 0; attempt <= retry; attempt += 1) {
|
|
161
161
|
try {
|
|
162
|
-
const res = await this.lsp.request('textDocument/documentSymbol', {
|
|
162
|
+
const res = await this.lsp.request('textDocument/documentSymbol', {
|
|
163
|
+
textDocument: { uri }
|
|
164
|
+
});
|
|
163
165
|
return res?.result ?? res;
|
|
164
166
|
} catch (err) {
|
|
165
167
|
lastErr = err;
|
|
@@ -212,23 +214,31 @@ export class CodeIndexUpdateToolHandler extends BaseToolHandler {
|
|
|
212
214
|
_toRelative(absPath, projectRoot) {
|
|
213
215
|
const normAbs = String(absPath).replace(/\\/g, '/');
|
|
214
216
|
const normRoot = String(projectRoot).replace(/\\/g, '/').replace(/\/$/, '');
|
|
215
|
-
return normAbs.startsWith(normRoot)
|
|
216
|
-
? normAbs.substring(normRoot.length + 1)
|
|
217
|
-
: normAbs;
|
|
217
|
+
return normAbs.startsWith(normRoot) ? normAbs.substring(normRoot.length + 1) : normAbs;
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
_kindFromLsp(kind) {
|
|
221
221
|
switch (kind) {
|
|
222
|
-
case 5:
|
|
223
|
-
|
|
224
|
-
case
|
|
225
|
-
|
|
226
|
-
case
|
|
227
|
-
|
|
228
|
-
case
|
|
229
|
-
|
|
230
|
-
case
|
|
231
|
-
|
|
222
|
+
case 5:
|
|
223
|
+
return 'class';
|
|
224
|
+
case 23:
|
|
225
|
+
return 'struct';
|
|
226
|
+
case 11:
|
|
227
|
+
return 'interface';
|
|
228
|
+
case 10:
|
|
229
|
+
return 'enum';
|
|
230
|
+
case 6:
|
|
231
|
+
return 'method';
|
|
232
|
+
case 7:
|
|
233
|
+
return 'property';
|
|
234
|
+
case 8:
|
|
235
|
+
return 'field';
|
|
236
|
+
case 3:
|
|
237
|
+
return 'namespace';
|
|
238
|
+
case 9:
|
|
239
|
+
return 'constructor';
|
|
240
|
+
default:
|
|
241
|
+
return 'symbol';
|
|
232
242
|
}
|
|
233
243
|
}
|
|
234
244
|
}
|
|
@@ -11,26 +11,54 @@ export class ScriptCreateClassToolHandler extends BaseToolHandler {
|
|
|
11
11
|
{
|
|
12
12
|
type: 'object',
|
|
13
13
|
properties: {
|
|
14
|
-
path: {
|
|
14
|
+
path: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: 'Project-relative C# file path (e.g., Assets/Scripts/MyClass.cs)'
|
|
17
|
+
},
|
|
15
18
|
className: { type: 'string', description: 'Class name' },
|
|
16
19
|
namespace: { type: 'string', description: 'Optional namespace' },
|
|
17
20
|
baseType: { type: 'string', description: 'Optional base type (e.g., MonoBehaviour)' },
|
|
18
|
-
usings: {
|
|
21
|
+
usings: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'Comma-separated using directives (e.g., System,Newtonsoft.Json)'
|
|
24
|
+
},
|
|
19
25
|
partial: { type: 'boolean', description: 'Create as partial class (default: false)' },
|
|
20
26
|
apply: { type: 'boolean', description: 'Apply immediately (default: false)' }
|
|
21
27
|
},
|
|
22
|
-
required: ['path','className']
|
|
28
|
+
required: ['path', 'className']
|
|
23
29
|
}
|
|
24
30
|
);
|
|
25
31
|
this.unityConnection = unityConnection;
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
async execute(params) {
|
|
29
|
-
const {
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
const {
|
|
36
|
+
path: rel,
|
|
37
|
+
className,
|
|
38
|
+
namespace: ns,
|
|
39
|
+
baseType,
|
|
40
|
+
usings,
|
|
41
|
+
partial = false,
|
|
42
|
+
apply = false
|
|
43
|
+
} = params;
|
|
44
|
+
const relative = String(rel).replace(/\\\\/g, '/').endsWith('.cs')
|
|
45
|
+
? String(rel).replace(/\\\\/g, '/')
|
|
46
|
+
: String(rel).replace(/\\\\/g, '/') + '.cs';
|
|
47
|
+
const code = this._buildSource({
|
|
48
|
+
className: String(className),
|
|
49
|
+
ns: ns ? String(ns) : null,
|
|
50
|
+
baseType: baseType ? String(baseType) : null,
|
|
51
|
+
usings: usings ? String(usings) : null,
|
|
52
|
+
partial: !!partial
|
|
53
|
+
});
|
|
32
54
|
if (!apply) {
|
|
33
|
-
return {
|
|
55
|
+
return {
|
|
56
|
+
success: true,
|
|
57
|
+
applied: false,
|
|
58
|
+
preview: code.slice(0, 1000),
|
|
59
|
+
previewTruncated: code.length > 1000,
|
|
60
|
+
relative: relative
|
|
61
|
+
};
|
|
34
62
|
}
|
|
35
63
|
const full = this._resolveFullPath(relative);
|
|
36
64
|
fs.mkdirSync(path.dirname(full), { recursive: true });
|
|
@@ -46,8 +74,15 @@ export class ScriptCreateClassToolHandler extends BaseToolHandler {
|
|
|
46
74
|
|
|
47
75
|
_buildSource({ className, ns, baseType, usings, partial }) {
|
|
48
76
|
const useList = [];
|
|
49
|
-
if (usings)
|
|
50
|
-
|
|
77
|
+
if (usings)
|
|
78
|
+
useList.push(
|
|
79
|
+
...usings
|
|
80
|
+
.split(',')
|
|
81
|
+
.map(s => s.trim())
|
|
82
|
+
.filter(Boolean)
|
|
83
|
+
);
|
|
84
|
+
if (baseType === 'MonoBehaviour' && !useList.includes('UnityEngine'))
|
|
85
|
+
useList.push('UnityEngine');
|
|
51
86
|
const header = useList.length ? useList.map(u => `using ${u};`).join('\n') + '\n\n' : '';
|
|
52
87
|
const partialKw = partial ? ' partial' : '';
|
|
53
88
|
const baseClause = baseType ? ` : ${baseType}` : '';
|
|
@@ -5,99 +5,99 @@ import { ProjectInfoProvider } from '../../core/projectInfo.js';
|
|
|
5
5
|
import { logger } from '../../core/config.js';
|
|
6
6
|
|
|
7
7
|
export class ScriptPackagesListToolHandler extends BaseToolHandler {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
8
|
+
constructor(unityConnection) {
|
|
9
|
+
super(
|
|
10
|
+
'script_packages_list',
|
|
11
|
+
'List Unity packages in the project (optionally include built‑in). BEST PRACTICES: Use to discover available packages and their paths. Set includeBuiltIn=false to see only user packages. Returns package IDs, versions, and resolved paths. Embedded packages can be edited directly. Essential for understanding project dependencies.',
|
|
12
|
+
{
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: {
|
|
15
|
+
includeBuiltIn: {
|
|
16
|
+
type: 'boolean',
|
|
17
|
+
description: 'If true, includes built‑in packages in results (default: false).'
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
required: []
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
this.unityConnection = unityConnection;
|
|
24
|
+
this.projectInfo = new ProjectInfoProvider(unityConnection);
|
|
25
|
+
}
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
async execute(params) {
|
|
28
|
+
const { includeBuiltIn = false } = params;
|
|
29
|
+
const info = await this.projectInfo.get();
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
} else if (fs.existsSync(manifestPath)) {
|
|
67
|
-
const man = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
68
|
-
const deps = man?.dependencies || {};
|
|
69
|
-
for (const [name, spec] of Object.entries(deps)) {
|
|
70
|
-
let source = 'registry';
|
|
71
|
-
let version = String(spec);
|
|
72
|
-
let resolvedPath = null;
|
|
73
|
-
let isEmbedded = false;
|
|
74
|
-
if (version.startsWith('file:')) {
|
|
75
|
-
source = 'embedded';
|
|
76
|
-
isEmbedded = true;
|
|
77
|
-
const folder = version.substring('file:'.length);
|
|
78
|
-
resolvedPath = path.join(info.projectRoot, 'Packages', folder).replace(/\\/g, '/');
|
|
79
|
-
}
|
|
80
|
-
if (!includeBuiltIn && source === 'builtin') continue;
|
|
81
|
-
results.push({
|
|
82
|
-
packageId: `${name}@${version}`,
|
|
83
|
-
name,
|
|
84
|
-
displayName: name,
|
|
85
|
-
version,
|
|
86
|
-
source,
|
|
87
|
-
isEmbedded,
|
|
88
|
-
resolvedPath
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
} else {
|
|
92
|
-
return { success: true, packages: [], totalCount: 0 };
|
|
93
|
-
}
|
|
94
|
-
} catch (e) {
|
|
95
|
-
logger.error(`[script_packages_list] local parse failed: ${e.message}`);
|
|
96
|
-
return { error: e.message };
|
|
31
|
+
// Prefer packages-lock.json for authoritative list (includes builtin/embedded/registry)
|
|
32
|
+
const lockPath = path.join(info.projectRoot, 'Packages', 'packages-lock.json');
|
|
33
|
+
const manifestPath = path.join(info.projectRoot, 'Packages', 'manifest.json');
|
|
34
|
+
let results = [];
|
|
35
|
+
try {
|
|
36
|
+
if (fs.existsSync(lockPath)) {
|
|
37
|
+
const json = JSON.parse(fs.readFileSync(lockPath, 'utf8'));
|
|
38
|
+
const deps = json?.dependencies || {};
|
|
39
|
+
for (const [name, meta] of Object.entries(deps)) {
|
|
40
|
+
const source = String(meta.source || '').toLowerCase();
|
|
41
|
+
if (!includeBuiltIn && source === 'builtin') continue;
|
|
42
|
+
const version = String(meta.version || '');
|
|
43
|
+
let resolvedPath = null;
|
|
44
|
+
let isEmbedded = source === 'embedded';
|
|
45
|
+
if (isEmbedded) {
|
|
46
|
+
// For embedded, manifest specifies file:folder
|
|
47
|
+
try {
|
|
48
|
+
const man = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
49
|
+
const spec = man?.dependencies?.[name];
|
|
50
|
+
if (typeof spec === 'string' && spec.startsWith('file:')) {
|
|
51
|
+
const folder = spec.substring('file:'.length);
|
|
52
|
+
resolvedPath = path.join(info.projectRoot, 'Packages', folder).replace(/\\/g, '/');
|
|
53
|
+
}
|
|
54
|
+
} catch {}
|
|
55
|
+
}
|
|
56
|
+
results.push({
|
|
57
|
+
packageId: `${name}@${version}`,
|
|
58
|
+
name,
|
|
59
|
+
displayName: name,
|
|
60
|
+
version,
|
|
61
|
+
source,
|
|
62
|
+
isEmbedded,
|
|
63
|
+
resolvedPath
|
|
64
|
+
});
|
|
97
65
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
66
|
+
} else if (fs.existsSync(manifestPath)) {
|
|
67
|
+
const man = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
68
|
+
const deps = man?.dependencies || {};
|
|
69
|
+
for (const [name, spec] of Object.entries(deps)) {
|
|
70
|
+
let source = 'registry';
|
|
71
|
+
let version = String(spec);
|
|
72
|
+
let resolvedPath = null;
|
|
73
|
+
let isEmbedded = false;
|
|
74
|
+
if (version.startsWith('file:')) {
|
|
75
|
+
source = 'embedded';
|
|
76
|
+
isEmbedded = true;
|
|
77
|
+
const folder = version.substring('file:'.length);
|
|
78
|
+
resolvedPath = path.join(info.projectRoot, 'Packages', folder).replace(/\\/g, '/');
|
|
79
|
+
}
|
|
80
|
+
if (!includeBuiltIn && source === 'builtin') continue;
|
|
81
|
+
results.push({
|
|
82
|
+
packageId: `${name}@${version}`,
|
|
83
|
+
name,
|
|
84
|
+
displayName: name,
|
|
85
|
+
version,
|
|
86
|
+
source,
|
|
87
|
+
isEmbedded,
|
|
88
|
+
resolvedPath
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
return { success: true, packages: [], totalCount: 0 };
|
|
93
|
+
}
|
|
94
|
+
} catch (e) {
|
|
95
|
+
logger.error(`[script_packages_list] local parse failed: ${e.message}`);
|
|
96
|
+
return { error: e.message };
|
|
102
97
|
}
|
|
98
|
+
|
|
99
|
+
// Sort by name
|
|
100
|
+
results.sort((a, b) => a.name.localeCompare(b.name));
|
|
101
|
+
return { success: true, packages: results, totalCount: results.length };
|
|
102
|
+
}
|
|
103
103
|
}
|
|
@@ -3,81 +3,90 @@ import { LspRpcClient } from '../../lsp/LspRpcClient.js';
|
|
|
3
3
|
import { ProjectInfoProvider } from '../../core/projectInfo.js';
|
|
4
4
|
|
|
5
5
|
export class ScriptRefactorRenameToolHandler extends BaseToolHandler {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
6
|
+
constructor(unityConnection) {
|
|
7
|
+
super(
|
|
8
|
+
'script_refactor_rename',
|
|
9
|
+
'Refactor: rename a symbol across the project using the bundled C# LSP. Required params: relative (file path starting with Assets/ or Packages/), namePath (container path like Outer/Nested/Member), newName. Guidance: resolve targets first (script_symbols_get/script_symbol_find), prefer fully-qualified namePath to avoid ambiguity, and use preview for diagnostics only (apply proceeds even if diagnostics exist; errors are returned in response). Responses are summarized (errors≤30, message≤200 chars, large text≤1000 chars).',
|
|
10
|
+
{
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
relative: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
description: 'Project-relative file path (Assets/ or Packages/)'
|
|
16
|
+
},
|
|
17
|
+
namePath: { type: 'string', description: 'Symbol path like Class/Method' },
|
|
18
|
+
newName: { type: 'string', description: 'New name' },
|
|
19
|
+
preview: {
|
|
20
|
+
type: 'boolean',
|
|
21
|
+
description: 'Preview changes before applying (default: true)'
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
required: ['relative', 'namePath', 'newName']
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
this.projectInfo = new ProjectInfoProvider(unityConnection);
|
|
28
|
+
this.lsp = null;
|
|
29
|
+
}
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
validate(params) {
|
|
32
|
+
super.validate(params);
|
|
33
|
+
const { relative, namePath, newName } = params;
|
|
34
|
+
if (!relative || !namePath || !newName)
|
|
35
|
+
throw new Error('relative, namePath, newName are required');
|
|
36
|
+
}
|
|
30
37
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
async execute(params) {
|
|
39
|
+
const { relative, namePath, newName, preview = true } = params;
|
|
40
|
+
const info = await this.projectInfo.get();
|
|
41
|
+
if (!this.lsp) this.lsp = new LspRpcClient(info.projectRoot);
|
|
42
|
+
const resp = await this.lsp.request('mcp/renameByNamePath', {
|
|
43
|
+
relative: String(relative).replace(/\\\\/g, '/'),
|
|
44
|
+
namePath: String(namePath),
|
|
45
|
+
newName: String(newName),
|
|
46
|
+
apply: !preview
|
|
47
|
+
});
|
|
48
|
+
const r = resp?.result ?? resp;
|
|
49
|
+
return this._summarizeResult(r);
|
|
50
|
+
}
|
|
44
51
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
});
|
|
66
|
-
out.errorCount = trimmed.length;
|
|
67
|
-
out.totalErrors = res.errors.length;
|
|
68
|
-
out.errors = trimmed;
|
|
52
|
+
_summarizeResult(res) {
|
|
53
|
+
if (!res || typeof res !== 'object') return res;
|
|
54
|
+
const MAX_ERRORS = 30;
|
|
55
|
+
const MAX_MSG_LEN = 200;
|
|
56
|
+
const MAX_TEXT_LEN = 1000;
|
|
57
|
+
const out = {};
|
|
58
|
+
if ('id' in res) out.id = res.id;
|
|
59
|
+
if ('success' in res) out.success = !!res.success;
|
|
60
|
+
if ('applied' in res) out.applied = !!res.applied;
|
|
61
|
+
if (Array.isArray(res.errors)) {
|
|
62
|
+
const trimmed = res.errors.slice(0, MAX_ERRORS).map(e => {
|
|
63
|
+
const o = {};
|
|
64
|
+
if (e && typeof e === 'object') {
|
|
65
|
+
if ('id' in e) o.id = e.id;
|
|
66
|
+
if ('message' in e) o.message = String(e.message).slice(0, MAX_MSG_LEN);
|
|
67
|
+
if ('file' in e) o.file = String(e.file).slice(0, 260);
|
|
68
|
+
if ('line' in e) o.line = e.line;
|
|
69
|
+
if ('column' in e) o.column = e.column;
|
|
70
|
+
} else {
|
|
71
|
+
o.message = String(e).slice(0, MAX_MSG_LEN);
|
|
69
72
|
}
|
|
70
|
-
|
|
73
|
+
return o;
|
|
74
|
+
});
|
|
75
|
+
out.errorCount = trimmed.length;
|
|
76
|
+
out.totalErrors = res.errors.length;
|
|
77
|
+
out.errors = trimmed;
|
|
78
|
+
}
|
|
79
|
+
// workspace情報は返さない(厳格: .sln必須のため)
|
|
71
80
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
return Object.keys(out).length ? out : res;
|
|
81
|
+
for (const k of ['preview', 'diff', 'text', 'content']) {
|
|
82
|
+
if (typeof res[k] === 'string' && res[k].length > 0) {
|
|
83
|
+
out[k] = res[k].slice(0, MAX_TEXT_LEN);
|
|
84
|
+
if (res[k].length > MAX_TEXT_LEN) out[`${k}Truncated`] = true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
for (const k of ['operation', 'path', 'relative', 'symbolName']) {
|
|
88
|
+
if (res[k] !== undefined) out[k] = res[k];
|
|
82
89
|
}
|
|
90
|
+
return Object.keys(out).length ? out : res;
|
|
91
|
+
}
|
|
83
92
|
}
|
|
@@ -14,10 +14,16 @@ export class ScriptRemoveSymbolToolHandler extends BaseToolHandler {
|
|
|
14
14
|
path: { type: 'string', description: 'Project-relative C# file path' },
|
|
15
15
|
namePath: { type: 'string', description: 'Symbol path like Outer/Nested/Member' },
|
|
16
16
|
apply: { type: 'boolean', description: 'Apply changes immediately (default: false)' },
|
|
17
|
-
failOnReferences: {
|
|
18
|
-
|
|
17
|
+
failOnReferences: {
|
|
18
|
+
type: 'boolean',
|
|
19
|
+
description: 'Fail if symbol has references (default: true)'
|
|
20
|
+
},
|
|
21
|
+
removeEmptyFile: {
|
|
22
|
+
type: 'boolean',
|
|
23
|
+
description: 'Remove file if it becomes empty (default: false)'
|
|
24
|
+
}
|
|
19
25
|
},
|
|
20
|
-
required: ['path','namePath']
|
|
26
|
+
required: ['path', 'namePath']
|
|
21
27
|
}
|
|
22
28
|
);
|
|
23
29
|
this.projectInfo = new ProjectInfoProvider(unityConnection);
|
|
@@ -25,7 +31,13 @@ export class ScriptRemoveSymbolToolHandler extends BaseToolHandler {
|
|
|
25
31
|
}
|
|
26
32
|
|
|
27
33
|
async execute(params) {
|
|
28
|
-
const {
|
|
34
|
+
const {
|
|
35
|
+
path,
|
|
36
|
+
namePath,
|
|
37
|
+
apply = false,
|
|
38
|
+
failOnReferences = true,
|
|
39
|
+
removeEmptyFile = false
|
|
40
|
+
} = params;
|
|
29
41
|
const info = await this.projectInfo.get();
|
|
30
42
|
if (!this.lsp) this.lsp = new LspRpcClient(info.projectRoot);
|
|
31
43
|
const resp = await this.lsp.request('mcp/removeSymbol', {
|
|
@@ -56,7 +68,9 @@ export class ScriptRemoveSymbolToolHandler extends BaseToolHandler {
|
|
|
56
68
|
if ('file' in e) o.file = String(e.file).slice(0, 260);
|
|
57
69
|
if ('line' in e) o.line = e.line;
|
|
58
70
|
if ('column' in e) o.column = e.column;
|
|
59
|
-
} else {
|
|
71
|
+
} else {
|
|
72
|
+
o.message = String(e).slice(0, MAX_MSG_LEN);
|
|
73
|
+
}
|
|
60
74
|
return o;
|
|
61
75
|
});
|
|
62
76
|
out.errorCount = trimmed.length;
|
|
@@ -65,13 +79,13 @@ export class ScriptRemoveSymbolToolHandler extends BaseToolHandler {
|
|
|
65
79
|
}
|
|
66
80
|
// workspace情報は返さない(厳格: .sln必須のため)
|
|
67
81
|
|
|
68
|
-
for (const k of ['preview','diff','text','content']) {
|
|
82
|
+
for (const k of ['preview', 'diff', 'text', 'content']) {
|
|
69
83
|
if (typeof res[k] === 'string' && res[k].length > 0) {
|
|
70
84
|
out[k] = res[k].slice(0, MAX_TEXT_LEN);
|
|
71
85
|
if (res[k].length > MAX_TEXT_LEN) out[`${k}Truncated`] = true;
|
|
72
86
|
}
|
|
73
87
|
}
|
|
74
|
-
for (const k of ['operation','path','relative','symbolName']) {
|
|
88
|
+
for (const k of ['operation', 'path', 'relative', 'symbolName']) {
|
|
75
89
|
if (res[k] !== undefined) out[k] = res[k];
|
|
76
90
|
}
|
|
77
91
|
return Object.keys(out).length ? out : res;
|