godot-mcp-runtime 2.2.3 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -93
- package/dist/dispatch.d.ts +1 -11
- package/dist/dispatch.d.ts.map +1 -1
- package/dist/dispatch.js +7 -8
- package/dist/dispatch.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -10
- package/dist/index.js.map +1 -1
- package/dist/scripts/godot_operations.gd +134 -283
- package/dist/scripts/mcp_bridge.gd +210 -43
- package/dist/tools/autoload-tools.d.ts +51 -0
- package/dist/tools/autoload-tools.d.ts.map +1 -0
- package/dist/tools/autoload-tools.js +187 -0
- package/dist/tools/autoload-tools.js.map +1 -0
- package/dist/tools/node-tools.d.ts +9 -78
- package/dist/tools/node-tools.d.ts.map +1 -1
- package/dist/tools/node-tools.js +114 -310
- package/dist/tools/node-tools.js.map +1 -1
- package/dist/tools/project-tools.d.ts +0 -168
- package/dist/tools/project-tools.d.ts.map +1 -1
- package/dist/tools/project-tools.js +120 -1192
- package/dist/tools/project-tools.js.map +1 -1
- package/dist/tools/runtime-tools.d.ts +108 -0
- package/dist/tools/runtime-tools.d.ts.map +1 -0
- package/dist/tools/runtime-tools.js +808 -0
- package/dist/tools/runtime-tools.js.map +1 -0
- package/dist/tools/scene-tools.d.ts +6 -48
- package/dist/tools/scene-tools.d.ts.map +1 -1
- package/dist/tools/scene-tools.js +67 -211
- package/dist/tools/scene-tools.js.map +1 -1
- package/dist/tools/validate-tools.d.ts.map +1 -1
- package/dist/tools/validate-tools.js +35 -29
- package/dist/tools/validate-tools.js.map +1 -1
- package/dist/utils/autoload-ini.d.ts +32 -0
- package/dist/utils/autoload-ini.d.ts.map +1 -0
- package/dist/utils/autoload-ini.js +111 -0
- package/dist/utils/autoload-ini.js.map +1 -0
- package/dist/utils/bridge-manager.d.ts +29 -0
- package/dist/utils/bridge-manager.d.ts.map +1 -0
- package/dist/utils/bridge-manager.js +136 -0
- package/dist/utils/bridge-manager.js.map +1 -0
- package/dist/utils/bridge-protocol.d.ts +34 -0
- package/dist/utils/bridge-protocol.d.ts.map +1 -0
- package/dist/utils/bridge-protocol.js +65 -0
- package/dist/utils/bridge-protocol.js.map +1 -0
- package/dist/utils/godot-runner.d.ts +70 -15
- package/dist/utils/godot-runner.d.ts.map +1 -1
- package/dist/utils/godot-runner.js +309 -277
- package/dist/utils/godot-runner.js.map +1 -1
- package/dist/utils/handler-helpers.d.ts +34 -0
- package/dist/utils/handler-helpers.d.ts.map +1 -0
- package/dist/utils/handler-helpers.js +55 -0
- package/dist/utils/handler-helpers.js.map +1 -0
- package/dist/utils/logger.d.ts +3 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +11 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +7 -4
package/dist/tools/node-tools.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { existsSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
|
-
import { normalizeParameters, convertCamelToSnakeCase, validatePath, createErrorResponse,
|
|
3
|
+
import { normalizeParameters, convertCamelToSnakeCase, validatePath, createErrorResponse, validateSceneArgs, } from '../utils/godot-runner.js';
|
|
4
|
+
import { executeSceneOp } from '../utils/handler-helpers.js';
|
|
4
5
|
// --- Tool definitions ---
|
|
5
6
|
export const nodeToolDefinitions = [
|
|
6
7
|
{
|
|
7
|
-
name: '
|
|
8
|
-
description: 'Remove
|
|
8
|
+
name: 'delete_nodes',
|
|
9
|
+
description: 'Remove one or more nodes (and their descendants) from a scene file. Always-array: pass a single-element nodePaths array for one-off deletes. Saves once at the end. Cannot delete the scene root — that entry returns an error and the rest still process. Returns { results: [{ nodePath, success?, error? }] }.',
|
|
10
|
+
annotations: { destructiveHint: true },
|
|
9
11
|
inputSchema: {
|
|
10
12
|
type: 'object',
|
|
11
13
|
properties: {
|
|
@@ -14,35 +16,19 @@ export const nodeToolDefinitions = [
|
|
|
14
16
|
type: 'string',
|
|
15
17
|
description: 'Scene file path relative to the project (e.g. "scenes/main.tscn")',
|
|
16
18
|
},
|
|
17
|
-
|
|
18
|
-
type: '
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
},
|
|
22
|
-
required: ['projectPath', 'scenePath', 'nodePath'],
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
name: 'set_node_property',
|
|
27
|
-
description: 'Set a property on a node in a Godot scene file. Saves automatically. Primitives (string, number, boolean, array, object) are passed as-is. Vector2 ({"x","y"}), Vector3 ({"x","y","z"}), and Color ({"r","g","b","a"}) are automatically converted. Use run_script for other complex GDScript types.',
|
|
28
|
-
inputSchema: {
|
|
29
|
-
type: 'object',
|
|
30
|
-
properties: {
|
|
31
|
-
projectPath: { type: 'string', description: 'Path to the Godot project directory' },
|
|
32
|
-
scenePath: { type: 'string', description: 'Scene file path relative to the project' },
|
|
33
|
-
nodePath: { type: 'string', description: 'Node path from scene root (e.g. "root/Player")' },
|
|
34
|
-
property: {
|
|
35
|
-
type: 'string',
|
|
36
|
-
description: 'GDScript property name in snake_case (e.g. "position", "modulate", "collision_layer"). Use get_node_properties to discover valid names.',
|
|
19
|
+
nodePaths: {
|
|
20
|
+
type: 'array',
|
|
21
|
+
items: { type: 'string' },
|
|
22
|
+
description: 'Node paths from scene root to delete (e.g. ["root/Player/Sprite2D"])',
|
|
37
23
|
},
|
|
38
|
-
value: { description: 'New property value' },
|
|
39
24
|
},
|
|
40
|
-
required: ['projectPath', 'scenePath', '
|
|
25
|
+
required: ['projectPath', 'scenePath', 'nodePaths'],
|
|
41
26
|
},
|
|
42
27
|
},
|
|
43
28
|
{
|
|
44
|
-
name: '
|
|
45
|
-
description: 'Set
|
|
29
|
+
name: 'set_node_properties',
|
|
30
|
+
description: 'Set one or more node properties on a scene in a single Godot process. Always-array: pass a single-element updates array for one-off edits. Vector2 ({x,y}), Vector3 ({x,y,z}), and Color ({r,g,b,a}) auto-convert; primitives pass through. For other complex GDScript types (Resource, NodePath, etc.), use run_script. abortOnError stops on first failure (default false continues). Saves once at the end. Returns { results: [{ nodePath, property, success?, error? }] }.',
|
|
31
|
+
annotations: { idempotentHint: true },
|
|
46
32
|
inputSchema: {
|
|
47
33
|
type: 'object',
|
|
48
34
|
properties: {
|
|
@@ -54,8 +40,14 @@ export const nodeToolDefinitions = [
|
|
|
54
40
|
items: {
|
|
55
41
|
type: 'object',
|
|
56
42
|
properties: {
|
|
57
|
-
nodePath: {
|
|
58
|
-
|
|
43
|
+
nodePath: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
description: 'Node path from scene root (e.g. "root/Player")',
|
|
46
|
+
},
|
|
47
|
+
property: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
description: 'GDScript property name in snake_case (e.g. "position", "modulate", "collision_layer")',
|
|
50
|
+
},
|
|
59
51
|
value: { description: 'New property value' },
|
|
60
52
|
},
|
|
61
53
|
required: ['nodePath', 'property', 'value'],
|
|
@@ -71,24 +63,8 @@ export const nodeToolDefinitions = [
|
|
|
71
63
|
},
|
|
72
64
|
{
|
|
73
65
|
name: 'get_node_properties',
|
|
74
|
-
description: "Read
|
|
75
|
-
|
|
76
|
-
type: 'object',
|
|
77
|
-
properties: {
|
|
78
|
-
projectPath: { type: 'string', description: 'Path to the Godot project directory' },
|
|
79
|
-
scenePath: { type: 'string', description: 'Scene file path relative to the project' },
|
|
80
|
-
nodePath: { type: 'string', description: 'Node path from scene root (e.g. "root/Player")' },
|
|
81
|
-
changedOnly: {
|
|
82
|
-
type: 'boolean',
|
|
83
|
-
description: 'Only return properties whose values differ from their class defaults (default: false)',
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
required: ['projectPath', 'scenePath', 'nodePath'],
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
name: 'batch_get_node_properties',
|
|
91
|
-
description: 'Get properties from multiple nodes in a single Godot process. Returns { results: [{ nodePath, nodeType, properties?, error? }] }.',
|
|
66
|
+
description: "Read one or more nodes' current property values from a scene file in a single Godot process. Always-array: pass a single-element nodes array for one-off reads. Per-node changedOnly:true filters out properties matching class defaults (useful for compact diffs). Returns { results: [{ nodePath, nodeType, properties?, error? }] }; failed reads include error and omit properties.",
|
|
67
|
+
annotations: { readOnlyHint: true },
|
|
92
68
|
inputSchema: {
|
|
93
69
|
type: 'object',
|
|
94
70
|
properties: {
|
|
@@ -100,7 +76,10 @@ export const nodeToolDefinitions = [
|
|
|
100
76
|
items: {
|
|
101
77
|
type: 'object',
|
|
102
78
|
properties: {
|
|
103
|
-
nodePath: {
|
|
79
|
+
nodePath: {
|
|
80
|
+
type: 'string',
|
|
81
|
+
description: 'Node path from scene root (e.g. "root/Player")',
|
|
82
|
+
},
|
|
104
83
|
changedOnly: {
|
|
105
84
|
type: 'boolean',
|
|
106
85
|
description: 'Only return properties differing from defaults (default: false)',
|
|
@@ -115,7 +94,8 @@ export const nodeToolDefinitions = [
|
|
|
115
94
|
},
|
|
116
95
|
{
|
|
117
96
|
name: 'attach_script',
|
|
118
|
-
description: 'Attach
|
|
97
|
+
description: 'Attach an existing GDScript file to a node in a scene. Use after writing the script with the standard file tools and validating it via the validate tool. Replaces any previously attached script. Saves automatically. Errors if scriptPath does not exist or nodePath is not found. Returns { success, nodePath, scriptPath }.',
|
|
98
|
+
annotations: { idempotentHint: true },
|
|
119
99
|
inputSchema: {
|
|
120
100
|
type: 'object',
|
|
121
101
|
properties: {
|
|
@@ -132,7 +112,8 @@ export const nodeToolDefinitions = [
|
|
|
132
112
|
},
|
|
133
113
|
{
|
|
134
114
|
name: 'get_scene_tree',
|
|
135
|
-
description: 'Get the scene hierarchy as a tree
|
|
115
|
+
description: 'Get the scene hierarchy as a nested tree of { name, type, path, script, children }. Use maxDepth:1 for a shallow listing of direct children only; default -1 returns the full tree. parentPath scopes the result to a subtree. Returns the nested tree as JSON text. Errors if scene does not exist or parentPath is not found.',
|
|
116
|
+
annotations: { readOnlyHint: true },
|
|
136
117
|
inputSchema: {
|
|
137
118
|
type: 'object',
|
|
138
119
|
properties: {
|
|
@@ -152,7 +133,7 @@ export const nodeToolDefinitions = [
|
|
|
152
133
|
},
|
|
153
134
|
{
|
|
154
135
|
name: 'duplicate_node',
|
|
155
|
-
description: 'Duplicate a node and its
|
|
136
|
+
description: 'Duplicate a node and its descendants in a Godot scene. Use to clone a configured subtree without re-creating it node-by-node via add_node. newName defaults to the original name + "2"; targetParentPath defaults to the original parent. Saves automatically. Errors if nodePath does not exist or targetParentPath cannot accept children. Returns { success, originalPath, newPath }.',
|
|
156
137
|
inputSchema: {
|
|
157
138
|
type: 'object',
|
|
158
139
|
properties: {
|
|
@@ -173,7 +154,8 @@ export const nodeToolDefinitions = [
|
|
|
173
154
|
},
|
|
174
155
|
{
|
|
175
156
|
name: 'get_node_signals',
|
|
176
|
-
description: 'List all signals defined on a node and their current connections. Returns { nodePath, nodeType, signals: [{ name, connections: [{ signal, target, method }] }] }.
|
|
157
|
+
description: 'List all signals defined on a node and their current connections. Use before connect_signal/disconnect_signal to verify signal/method names. Returns { nodePath, nodeType, signals: [{ name, connections: [{ signal, target, method }] }] }. The target field uses Godot absolute path format (/root/Scene/Node) — convert to scene-root-relative (root/Node) before passing to connect/disconnect_signal. Errors if node not found.',
|
|
158
|
+
annotations: { readOnlyHint: true },
|
|
177
159
|
inputSchema: {
|
|
178
160
|
type: 'object',
|
|
179
161
|
properties: {
|
|
@@ -186,7 +168,7 @@ export const nodeToolDefinitions = [
|
|
|
186
168
|
},
|
|
187
169
|
{
|
|
188
170
|
name: 'connect_signal',
|
|
189
|
-
description: 'Connect a signal
|
|
171
|
+
description: 'Connect a signal on a source node to a method on a target node, persisting the connection in the .tscn. Use after get_node_signals to confirm the signal name on the source and the method name on the target. Connecting the same signal+method pair twice creates a duplicate connection — call get_node_signals first if uncertain. Saves automatically. Returns a plain-text confirmation naming the source, signal, target, and method. Errors if the signal does not exist on the source node or the method does not exist on the target node.',
|
|
190
172
|
inputSchema: {
|
|
191
173
|
type: 'object',
|
|
192
174
|
properties: {
|
|
@@ -211,7 +193,8 @@ export const nodeToolDefinitions = [
|
|
|
211
193
|
},
|
|
212
194
|
{
|
|
213
195
|
name: 'disconnect_signal',
|
|
214
|
-
description: '
|
|
196
|
+
description: 'Remove an existing signal connection between two nodes, persisting the change in the .tscn. Use get_node_signals first to confirm the connection exists; recovery requires reconnecting via connect_signal. Saves automatically. Returns a plain-text confirmation naming the disconnected signal and target. Errors if the connection does not exist.',
|
|
197
|
+
annotations: { destructiveHint: true },
|
|
215
198
|
inputSchema: {
|
|
216
199
|
type: 'object',
|
|
217
200
|
properties: {
|
|
@@ -227,71 +210,29 @@ export const nodeToolDefinitions = [
|
|
|
227
210
|
},
|
|
228
211
|
];
|
|
229
212
|
// --- Handlers ---
|
|
230
|
-
export async function
|
|
231
|
-
args = normalizeParameters(args);
|
|
232
|
-
const v = validateSceneArgs(args);
|
|
233
|
-
if ('isError' in v)
|
|
234
|
-
return v;
|
|
235
|
-
if (!args.nodePath || !validatePath(args.nodePath)) {
|
|
236
|
-
return createErrorResponse('Valid nodePath is required', [
|
|
237
|
-
'Provide the node path (e.g. "root/Player")',
|
|
238
|
-
]);
|
|
239
|
-
}
|
|
240
|
-
try {
|
|
241
|
-
const params = { scenePath: args.scenePath, nodePath: args.nodePath };
|
|
242
|
-
const { stdout, stderr } = await runner.executeOperation('delete_node', params, v.projectPath);
|
|
243
|
-
if (!stdout.trim()) {
|
|
244
|
-
return createErrorResponse(`Failed to delete node: ${extractGdError(stderr)}`, [
|
|
245
|
-
'Check if the node path is correct',
|
|
246
|
-
]);
|
|
247
|
-
}
|
|
248
|
-
return { content: [{ type: 'text', text: stdout }] };
|
|
249
|
-
}
|
|
250
|
-
catch (error) {
|
|
251
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
252
|
-
return createErrorResponse(`Failed to delete node: ${errorMessage}`, [
|
|
253
|
-
'Ensure Godot is installed correctly',
|
|
254
|
-
]);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
export async function handleSetNodeProperty(runner, args) {
|
|
213
|
+
export async function handleDeleteNodes(runner, args) {
|
|
258
214
|
args = normalizeParameters(args);
|
|
259
215
|
const v = validateSceneArgs(args);
|
|
260
216
|
if ('isError' in v)
|
|
261
217
|
return v;
|
|
262
|
-
if (!args.
|
|
263
|
-
return createErrorResponse('
|
|
264
|
-
'Provide
|
|
265
|
-
]);
|
|
266
|
-
}
|
|
267
|
-
if (!args.property || args.value === undefined) {
|
|
268
|
-
return createErrorResponse('property and value are required', [
|
|
269
|
-
'Provide both property name and value',
|
|
218
|
+
if (!args.nodePaths || !Array.isArray(args.nodePaths) || args.nodePaths.length === 0) {
|
|
219
|
+
return createErrorResponse('nodePaths array is required', [
|
|
220
|
+
'Provide a non-empty array of node paths (e.g. ["root/Player"])',
|
|
270
221
|
]);
|
|
271
222
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
property: args.property,
|
|
277
|
-
value: args.value,
|
|
278
|
-
};
|
|
279
|
-
const { stdout, stderr } = await runner.executeOperation('set_node_property', params, v.projectPath);
|
|
280
|
-
if (!stdout.trim()) {
|
|
281
|
-
return createErrorResponse(`Failed to update property: ${extractGdError(stderr)}`, [
|
|
282
|
-
'Check if the property name is valid for this node type',
|
|
223
|
+
for (const p of args.nodePaths) {
|
|
224
|
+
if (typeof p !== 'string' || !validatePath(p)) {
|
|
225
|
+
return createErrorResponse('Invalid nodePath in nodePaths', [
|
|
226
|
+
'Provide valid paths without ".." (e.g. "root/Player")',
|
|
283
227
|
]);
|
|
284
228
|
}
|
|
285
|
-
return { content: [{ type: 'text', text: stdout }] };
|
|
286
|
-
}
|
|
287
|
-
catch (error) {
|
|
288
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
289
|
-
return createErrorResponse(`Failed to set node property: ${errorMessage}`, [
|
|
290
|
-
'Ensure Godot is installed correctly',
|
|
291
|
-
]);
|
|
292
229
|
}
|
|
230
|
+
const params = { scenePath: args.scenePath, nodePaths: args.nodePaths };
|
|
231
|
+
return executeSceneOp(runner, 'delete_nodes', params, v.projectPath, 'Failed to delete nodes', [
|
|
232
|
+
'Check if the node paths are correct',
|
|
233
|
+
]);
|
|
293
234
|
}
|
|
294
|
-
export async function
|
|
235
|
+
export async function handleSetNodeProperties(runner, args) {
|
|
295
236
|
args = normalizeParameters(args);
|
|
296
237
|
const v = validateSceneArgs(args);
|
|
297
238
|
if ('isError' in v)
|
|
@@ -301,58 +242,15 @@ export async function handleBatchSetNodeProperties(runner, args) {
|
|
|
301
242
|
'Provide an array of { nodePath, property, value }',
|
|
302
243
|
]);
|
|
303
244
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
const { stdout, stderr } = await runner.executeOperation('batch_set_node_properties', params, v.projectPath);
|
|
312
|
-
if (!stdout.trim()) {
|
|
313
|
-
return createErrorResponse(`Batch update failed: ${extractGdError(stderr)}`, [
|
|
314
|
-
'Check node paths and property names',
|
|
315
|
-
]);
|
|
316
|
-
}
|
|
317
|
-
return { content: [{ type: 'text', text: stdout }] };
|
|
318
|
-
}
|
|
319
|
-
catch (error) {
|
|
320
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
321
|
-
return createErrorResponse(`Batch set properties failed: ${errorMessage}`, [
|
|
322
|
-
'Ensure Godot is installed correctly',
|
|
323
|
-
]);
|
|
324
|
-
}
|
|
245
|
+
const snakeUpdates = args.updates.map((u) => convertCamelToSnakeCase(u));
|
|
246
|
+
const params = {
|
|
247
|
+
scenePath: args.scenePath,
|
|
248
|
+
updates: snakeUpdates,
|
|
249
|
+
abortOnError: args.abortOnError ?? false,
|
|
250
|
+
};
|
|
251
|
+
return executeSceneOp(runner, 'set_node_properties', params, v.projectPath, 'Failed to set node properties', ['Check node paths and property names']);
|
|
325
252
|
}
|
|
326
253
|
export async function handleGetNodeProperties(runner, args) {
|
|
327
|
-
args = normalizeParameters(args);
|
|
328
|
-
const v = validateSceneArgs(args);
|
|
329
|
-
if ('isError' in v)
|
|
330
|
-
return v;
|
|
331
|
-
if (!args.nodePath || !validatePath(args.nodePath)) {
|
|
332
|
-
return createErrorResponse('Valid nodePath is required', [
|
|
333
|
-
'Provide the node path (e.g. "root/Player")',
|
|
334
|
-
]);
|
|
335
|
-
}
|
|
336
|
-
try {
|
|
337
|
-
const params = { scenePath: args.scenePath, nodePath: args.nodePath };
|
|
338
|
-
if (args.changedOnly)
|
|
339
|
-
params.changedOnly = args.changedOnly;
|
|
340
|
-
const { stdout, stderr } = await runner.executeOperation('get_node_properties', params, v.projectPath);
|
|
341
|
-
if (!stdout.trim()) {
|
|
342
|
-
return createErrorResponse(`Failed to get properties: ${extractGdError(stderr)}`, [
|
|
343
|
-
'Check if the node path is correct',
|
|
344
|
-
]);
|
|
345
|
-
}
|
|
346
|
-
return { content: [{ type: 'text', text: stdout }] };
|
|
347
|
-
}
|
|
348
|
-
catch (error) {
|
|
349
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
350
|
-
return createErrorResponse(`Failed to get node properties: ${errorMessage}`, [
|
|
351
|
-
'Ensure Godot is installed correctly',
|
|
352
|
-
]);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
export async function handleBatchGetNodeProperties(runner, args) {
|
|
356
254
|
args = normalizeParameters(args);
|
|
357
255
|
const v = validateSceneArgs(args);
|
|
358
256
|
if ('isError' in v)
|
|
@@ -362,23 +260,9 @@ export async function handleBatchGetNodeProperties(runner, args) {
|
|
|
362
260
|
'Provide an array of { nodePath, changedOnly? }',
|
|
363
261
|
]);
|
|
364
262
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
const { stdout, stderr } = await runner.executeOperation('batch_get_node_properties', params, v.projectPath);
|
|
369
|
-
if (!stdout.trim()) {
|
|
370
|
-
return createErrorResponse(`Batch get_properties failed: ${extractGdError(stderr)}`, [
|
|
371
|
-
'Check node paths',
|
|
372
|
-
]);
|
|
373
|
-
}
|
|
374
|
-
return { content: [{ type: 'text', text: stdout }] };
|
|
375
|
-
}
|
|
376
|
-
catch (error) {
|
|
377
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
378
|
-
return createErrorResponse(`Batch get properties failed: ${errorMessage}`, [
|
|
379
|
-
'Ensure Godot is installed correctly',
|
|
380
|
-
]);
|
|
381
|
-
}
|
|
263
|
+
const snakeNodes = args.nodes.map((n) => convertCamelToSnakeCase(n));
|
|
264
|
+
const params = { scenePath: args.scenePath, nodes: snakeNodes };
|
|
265
|
+
return executeSceneOp(runner, 'get_node_properties', params, v.projectPath, 'Failed to get node properties', ['Check node paths']);
|
|
382
266
|
}
|
|
383
267
|
export async function handleAttachScript(runner, args) {
|
|
384
268
|
args = normalizeParameters(args);
|
|
@@ -401,26 +285,14 @@ export async function handleAttachScript(runner, args) {
|
|
|
401
285
|
'Create the script file first',
|
|
402
286
|
]);
|
|
403
287
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
return createErrorResponse(`Failed to attach script: ${extractGdError(stderr)}`, [
|
|
413
|
-
'Ensure the script is valid for this node type',
|
|
414
|
-
]);
|
|
415
|
-
}
|
|
416
|
-
return { content: [{ type: 'text', text: stdout }] };
|
|
417
|
-
}
|
|
418
|
-
catch (error) {
|
|
419
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
420
|
-
return createErrorResponse(`Failed to attach script: ${errorMessage}`, [
|
|
421
|
-
'Ensure Godot is installed correctly',
|
|
422
|
-
]);
|
|
423
|
-
}
|
|
288
|
+
const params = {
|
|
289
|
+
scenePath: args.scenePath,
|
|
290
|
+
nodePath: args.nodePath,
|
|
291
|
+
scriptPath: args.scriptPath,
|
|
292
|
+
};
|
|
293
|
+
return executeSceneOp(runner, 'attach_script', params, v.projectPath, 'Failed to attach script', [
|
|
294
|
+
'Ensure the script is valid for this node type',
|
|
295
|
+
]);
|
|
424
296
|
}
|
|
425
297
|
export async function handleGetSceneTree(runner, args) {
|
|
426
298
|
args = normalizeParameters(args);
|
|
@@ -430,26 +302,12 @@ export async function handleGetSceneTree(runner, args) {
|
|
|
430
302
|
if (args.parentPath && !validatePath(args.parentPath)) {
|
|
431
303
|
return createErrorResponse('Invalid parentPath', ['Provide a valid path without ".."']);
|
|
432
304
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
const { stdout, stderr } = await runner.executeOperation('get_scene_tree', params, v.projectPath);
|
|
440
|
-
if (!stdout.trim()) {
|
|
441
|
-
return createErrorResponse(`Failed to get scene tree: ${extractGdError(stderr)}`, [
|
|
442
|
-
'Ensure the scene is valid',
|
|
443
|
-
]);
|
|
444
|
-
}
|
|
445
|
-
return { content: [{ type: 'text', text: stdout }] };
|
|
446
|
-
}
|
|
447
|
-
catch (error) {
|
|
448
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
449
|
-
return createErrorResponse(`Failed to get scene tree: ${errorMessage}`, [
|
|
450
|
-
'Ensure Godot is installed correctly',
|
|
451
|
-
]);
|
|
452
|
-
}
|
|
305
|
+
const params = { scenePath: args.scenePath };
|
|
306
|
+
if (args.parentPath)
|
|
307
|
+
params.parentPath = args.parentPath;
|
|
308
|
+
if (typeof args.maxDepth === 'number')
|
|
309
|
+
params.maxDepth = args.maxDepth;
|
|
310
|
+
return executeSceneOp(runner, 'get_scene_tree', params, v.projectPath, 'Failed to get scene tree', ['Ensure the scene is valid']);
|
|
453
311
|
}
|
|
454
312
|
export async function handleDuplicateNode(runner, args) {
|
|
455
313
|
args = normalizeParameters(args);
|
|
@@ -464,26 +322,12 @@ export async function handleDuplicateNode(runner, args) {
|
|
|
464
322
|
if (args.targetParentPath && !validatePath(args.targetParentPath)) {
|
|
465
323
|
return createErrorResponse('Invalid targetParentPath', ['Provide a valid path without ".."']);
|
|
466
324
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
const { stdout, stderr } = await runner.executeOperation('duplicate_node', params, v.projectPath);
|
|
474
|
-
if (!stdout.trim()) {
|
|
475
|
-
return createErrorResponse(`Failed to duplicate node: ${extractGdError(stderr)}`, [
|
|
476
|
-
'Check if the node path and target parent path are correct',
|
|
477
|
-
]);
|
|
478
|
-
}
|
|
479
|
-
return { content: [{ type: 'text', text: stdout }] };
|
|
480
|
-
}
|
|
481
|
-
catch (error) {
|
|
482
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
483
|
-
return createErrorResponse(`Failed to duplicate node: ${errorMessage}`, [
|
|
484
|
-
'Ensure Godot is installed correctly',
|
|
485
|
-
]);
|
|
486
|
-
}
|
|
325
|
+
const params = { scenePath: args.scenePath, nodePath: args.nodePath };
|
|
326
|
+
if (args.newName)
|
|
327
|
+
params.newName = args.newName;
|
|
328
|
+
if (args.targetParentPath)
|
|
329
|
+
params.targetParentPath = args.targetParentPath;
|
|
330
|
+
return executeSceneOp(runner, 'duplicate_node', params, v.projectPath, 'Failed to duplicate node', ['Check if the node path and target parent path are correct']);
|
|
487
331
|
}
|
|
488
332
|
export async function handleGetNodeSignals(runner, args) {
|
|
489
333
|
args = normalizeParameters(args);
|
|
@@ -495,25 +339,10 @@ export async function handleGetNodeSignals(runner, args) {
|
|
|
495
339
|
'Provide the node path (e.g. "root/Button")',
|
|
496
340
|
]);
|
|
497
341
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
const { stdout, stderr } = await runner.executeOperation('get_node_signals', params, v.projectPath);
|
|
501
|
-
if (!stdout.trim()) {
|
|
502
|
-
return createErrorResponse(`Failed to get signals: ${extractGdError(stderr)}`, [
|
|
503
|
-
'Check if the node path is correct',
|
|
504
|
-
]);
|
|
505
|
-
}
|
|
506
|
-
return { content: [{ type: 'text', text: stdout }] };
|
|
507
|
-
}
|
|
508
|
-
catch (error) {
|
|
509
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
510
|
-
return createErrorResponse(`Failed to get node signals: ${errorMessage}`, [
|
|
511
|
-
'Ensure Godot is installed correctly',
|
|
512
|
-
]);
|
|
513
|
-
}
|
|
342
|
+
const params = { scenePath: args.scenePath, nodePath: args.nodePath };
|
|
343
|
+
return executeSceneOp(runner, 'get_node_signals', params, v.projectPath, 'Failed to get node signals', ['Check if the node path is correct']);
|
|
514
344
|
}
|
|
515
|
-
|
|
516
|
-
args = normalizeParameters(args);
|
|
345
|
+
function validateSignalArgs(args) {
|
|
517
346
|
const v = validateSceneArgs(args);
|
|
518
347
|
if ('isError' in v)
|
|
519
348
|
return v;
|
|
@@ -528,66 +357,41 @@ export async function handleConnectSignal(runner, args) {
|
|
|
528
357
|
if (!validatePath(args.targetNodePath)) {
|
|
529
358
|
return createErrorResponse('Invalid targetNodePath', ['Provide a valid path without ".."']);
|
|
530
359
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
360
|
+
return {
|
|
361
|
+
projectPath: v.projectPath,
|
|
362
|
+
scenePath: v.scenePath,
|
|
363
|
+
nodePath: args.nodePath,
|
|
364
|
+
signal: args.signal,
|
|
365
|
+
targetNodePath: args.targetNodePath,
|
|
366
|
+
method: args.method,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
export async function handleConnectSignal(runner, args) {
|
|
370
|
+
args = normalizeParameters(args);
|
|
371
|
+
const v = validateSignalArgs(args);
|
|
372
|
+
if ('isError' in v)
|
|
373
|
+
return v;
|
|
374
|
+
const params = {
|
|
375
|
+
scenePath: v.scenePath,
|
|
376
|
+
nodePath: v.nodePath,
|
|
377
|
+
signal: v.signal,
|
|
378
|
+
targetNodePath: v.targetNodePath,
|
|
379
|
+
method: v.method,
|
|
380
|
+
};
|
|
381
|
+
return executeSceneOp(runner, 'connect_signal', params, v.projectPath, 'Failed to connect signal', ['Ensure the signal exists on the source node and the method exists on the target node']);
|
|
553
382
|
}
|
|
554
383
|
export async function handleDisconnectSignal(runner, args) {
|
|
555
384
|
args = normalizeParameters(args);
|
|
556
|
-
const v =
|
|
385
|
+
const v = validateSignalArgs(args);
|
|
557
386
|
if ('isError' in v)
|
|
558
387
|
return v;
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
if (!validatePath(args.targetNodePath)) {
|
|
568
|
-
return createErrorResponse('Invalid targetNodePath', ['Provide a valid path without ".."']);
|
|
569
|
-
}
|
|
570
|
-
try {
|
|
571
|
-
const params = {
|
|
572
|
-
scenePath: args.scenePath,
|
|
573
|
-
nodePath: args.nodePath,
|
|
574
|
-
signal: args.signal,
|
|
575
|
-
targetNodePath: args.targetNodePath,
|
|
576
|
-
method: args.method,
|
|
577
|
-
};
|
|
578
|
-
const { stdout, stderr } = await runner.executeOperation('disconnect_signal', params, v.projectPath);
|
|
579
|
-
if (!stdout.trim()) {
|
|
580
|
-
return createErrorResponse(`Failed to disconnect signal: ${extractGdError(stderr)}`, [
|
|
581
|
-
'Ensure the signal connection exists before trying to disconnect it',
|
|
582
|
-
]);
|
|
583
|
-
}
|
|
584
|
-
return { content: [{ type: 'text', text: stdout }] };
|
|
585
|
-
}
|
|
586
|
-
catch (error) {
|
|
587
|
-
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
588
|
-
return createErrorResponse(`Failed to disconnect signal: ${errorMessage}`, [
|
|
589
|
-
'Ensure Godot is installed correctly',
|
|
590
|
-
]);
|
|
591
|
-
}
|
|
388
|
+
const params = {
|
|
389
|
+
scenePath: v.scenePath,
|
|
390
|
+
nodePath: v.nodePath,
|
|
391
|
+
signal: v.signal,
|
|
392
|
+
targetNodePath: v.targetNodePath,
|
|
393
|
+
method: v.method,
|
|
394
|
+
};
|
|
395
|
+
return executeSceneOp(runner, 'disconnect_signal', params, v.projectPath, 'Failed to disconnect signal', ['Ensure the signal connection exists before trying to disconnect it']);
|
|
592
396
|
}
|
|
593
397
|
//# sourceMappingURL=node-tools.js.map
|