@skillcap/gdh 3.1.0 → 3.2.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/INSTALL-BUNDLE.json +1 -1
- package/RELEASE-SPAN-UPDATE-CONTRACTS.json +83 -0
- package/node_modules/@gdh/adapters/package.json +8 -8
- package/node_modules/@gdh/authoring/package.json +2 -2
- package/node_modules/@gdh/cli/dist/index.js.map +1 -1
- package/node_modules/@gdh/cli/package.json +11 -11
- package/node_modules/@gdh/core/dist/index.d.ts +5 -5
- package/node_modules/@gdh/core/dist/index.d.ts.map +1 -1
- package/node_modules/@gdh/core/dist/index.js +4 -4
- package/node_modules/@gdh/core/dist/index.js.map +1 -1
- package/node_modules/@gdh/core/package.json +1 -1
- package/node_modules/@gdh/docs/dist/guidance.d.ts.map +1 -1
- package/node_modules/@gdh/docs/dist/guidance.js +29 -0
- package/node_modules/@gdh/docs/dist/guidance.js.map +1 -1
- package/node_modules/@gdh/docs/dist/templates/guidance/editor-bridge.md.tpl +28 -0
- package/node_modules/@gdh/docs/package.json +2 -2
- package/node_modules/@gdh/editor/dist/index.d.ts +24 -3
- package/node_modules/@gdh/editor/dist/index.d.ts.map +1 -1
- package/node_modules/@gdh/editor/dist/index.js +323 -7
- package/node_modules/@gdh/editor/dist/index.js.map +1 -1
- package/node_modules/@gdh/editor/package.json +2 -2
- package/node_modules/@gdh/mcp/dist/index.d.ts.map +1 -1
- package/node_modules/@gdh/mcp/dist/index.js +290 -2
- package/node_modules/@gdh/mcp/dist/index.js.map +1 -1
- package/node_modules/@gdh/mcp/package.json +10 -10
- package/node_modules/@gdh/observability/package.json +2 -2
- package/node_modules/@gdh/runtime/dist/bridge-surface.js +1 -1
- package/node_modules/@gdh/runtime/package.json +3 -3
- package/node_modules/@gdh/scan/package.json +3 -3
- package/node_modules/@gdh/verify/package.json +7 -7
- package/package.json +12 -12
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# {{projectName}}: Editor Bridge
|
|
2
|
+
|
|
3
|
+
Use this unit when the task asks about the Godot editor, the currently open scene, scene tree inspection, node inspection, resource properties, or editor-backed scene/resource authoring.
|
|
4
|
+
|
|
5
|
+
Start with context before guessing:
|
|
6
|
+
|
|
7
|
+
- Use MCP `editor.state` to inspect the exact target/worktree editor session. In adopted-editor mode it reports current/open scene and selected nodes when the editor exposes them.
|
|
8
|
+
- Use MCP `editor.scene.tree` for a saved scene tree. It requires an explicit `scenePath`; if you need the active editor scene first, call `editor.state`.
|
|
9
|
+
- Use MCP `editor.node.inspect` for inspector-style node context from a saved scene: node summary plus requested property values or a bounded property list.
|
|
10
|
+
- Use MCP `editor.resource.properties` before `editor.resource.read` when you do not already know the resource property names.
|
|
11
|
+
- Use MCP `editor.resource.read` for targeted resource values. Nested arrays and dictionaries are bounded and resources are returned as handles when Godot exposes a resource path.
|
|
12
|
+
- Use MCP `editor.class.search` and `editor.class.info` for class discovery instead of guessing Godot class names or property names.
|
|
13
|
+
|
|
14
|
+
Use `editor.operation.run` only as the advanced escape hatch for operation kinds not covered by a focused MCP tool or for batched editor operations. Generic operation payloads dispatch on `operation.kind`, not `operation.type`.
|
|
15
|
+
|
|
16
|
+
Recover from bad editor-operation payloads by reading the returned `summary`, `reasons`, and `help.examples`. CLI smoke-test help is available with:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
gdh editor operation run --help
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Do not read `.godot/` cache files to answer live editor-state questions while GDH editor tools are available. `.godot/` remains generated editor/import state; use it only when GDH explicitly reports that editor context is unavailable and you surface that limitation.
|
|
23
|
+
|
|
24
|
+
Boundaries:
|
|
25
|
+
|
|
26
|
+
- Current editor context and selection are available only from adopted editor sessions that expose editor APIs. Managed headless editor operations can load saved scenes/resources, but they do not have a human editor selection.
|
|
27
|
+
- Scene/resource reads are bounded inspection and authoring support, not UI automation of the Godot editor.
|
|
28
|
+
- Arbitrary editor script execution, broad editor UI automation, animation editor operations, TileMap/TileSet editing, and generic file maintenance remain outside this guidance.
|
|
@@ -105,6 +105,14 @@ export type GdhEditorOperation = {
|
|
|
105
105
|
readonly scenePath: string;
|
|
106
106
|
readonly nodePath: string;
|
|
107
107
|
readonly propertyName: string;
|
|
108
|
+
} | {
|
|
109
|
+
readonly kind: "node.inspect";
|
|
110
|
+
readonly scenePath: string;
|
|
111
|
+
readonly nodePath?: string;
|
|
112
|
+
readonly propertyNames?: readonly string[];
|
|
113
|
+
readonly includePropertyList?: boolean;
|
|
114
|
+
readonly propertyQuery?: string;
|
|
115
|
+
readonly propertyLimit?: number;
|
|
108
116
|
} | {
|
|
109
117
|
readonly kind: "resource.create";
|
|
110
118
|
readonly resourcePath: string;
|
|
@@ -114,6 +122,11 @@ export type GdhEditorOperation = {
|
|
|
114
122
|
readonly kind: "resource.read";
|
|
115
123
|
readonly resourcePath: string;
|
|
116
124
|
readonly propertyNames?: readonly string[];
|
|
125
|
+
} | {
|
|
126
|
+
readonly kind: "resource.properties";
|
|
127
|
+
readonly resourcePath: string;
|
|
128
|
+
readonly propertyQuery?: string;
|
|
129
|
+
readonly propertyLimit?: number;
|
|
117
130
|
} | {
|
|
118
131
|
readonly kind: "resource.set_property";
|
|
119
132
|
readonly resourcePath: string;
|
|
@@ -142,14 +155,21 @@ export type GdhEditorOperation = {
|
|
|
142
155
|
readonly kind: "batch.apply";
|
|
143
156
|
readonly operations: readonly GdhEditorOperation[];
|
|
144
157
|
};
|
|
158
|
+
export type GdhEditorOperationPayload = Readonly<Record<string, GdhJsonValue>>;
|
|
159
|
+
export interface GdhEditorOperationHelp {
|
|
160
|
+
readonly usage: string;
|
|
161
|
+
readonly helpCommand: string;
|
|
162
|
+
readonly examples: readonly Readonly<Record<string, GdhJsonValue>>[];
|
|
163
|
+
}
|
|
145
164
|
export interface GdhEditorOperationResult {
|
|
146
165
|
readonly targetPath: string;
|
|
147
166
|
readonly state: GdhEditorOperationState;
|
|
148
167
|
readonly summary: string;
|
|
149
168
|
readonly reasons: readonly string[];
|
|
150
169
|
readonly session: GdhEditorSessionSummary;
|
|
151
|
-
readonly operation:
|
|
170
|
+
readonly operation: GdhEditorOperationPayload;
|
|
152
171
|
readonly output: GdhJsonValue;
|
|
172
|
+
readonly help?: GdhEditorOperationHelp | null;
|
|
153
173
|
readonly artifacts: {
|
|
154
174
|
readonly operationId: string;
|
|
155
175
|
readonly directory: string;
|
|
@@ -161,7 +181,7 @@ export interface GdhEditorOperationResult {
|
|
|
161
181
|
} | null;
|
|
162
182
|
}
|
|
163
183
|
export interface RunEditorOperationInput extends ResolveEditorBridgePathsInput {
|
|
164
|
-
readonly operation:
|
|
184
|
+
readonly operation: GdhEditorOperationPayload;
|
|
165
185
|
readonly mode?: GdhEditorSessionMode;
|
|
166
186
|
readonly timeoutMs?: number;
|
|
167
187
|
readonly godotEditorBin?: string | null;
|
|
@@ -186,7 +206,7 @@ export type InvokeAdoptedEditor = (input: {
|
|
|
186
206
|
readonly metadata: GdhEditorAdoptionMetadata;
|
|
187
207
|
readonly token: string;
|
|
188
208
|
readonly identity: GdhBridgeTargetIdentity;
|
|
189
|
-
readonly operation:
|
|
209
|
+
readonly operation: GdhEditorOperationPayload;
|
|
190
210
|
readonly timeoutMs: number;
|
|
191
211
|
}) => Promise<RunnerOutput>;
|
|
192
212
|
export interface GdhEditorRunnerOutput {
|
|
@@ -194,6 +214,7 @@ export interface GdhEditorRunnerOutput {
|
|
|
194
214
|
readonly summary?: string;
|
|
195
215
|
readonly reasons?: readonly string[];
|
|
196
216
|
readonly output?: GdhJsonValue;
|
|
217
|
+
readonly help?: GdhEditorOperationHelp | null;
|
|
197
218
|
}
|
|
198
219
|
type RunnerOutput = GdhEditorRunnerOutput;
|
|
199
220
|
export declare function resolveEditorBridgePaths(input: ResolveEditorBridgePathsInput): GdhEditorBridgePaths;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -117,8 +117,187 @@ export async function inspectEditorBridgeSession(input) {
|
|
|
117
117
|
adoptedEditor: null,
|
|
118
118
|
};
|
|
119
119
|
}
|
|
120
|
+
function validateEditorOperation(operation) {
|
|
121
|
+
const kind = readPayloadString(operation["kind"]);
|
|
122
|
+
const help = createEditorOperationHelp(kind);
|
|
123
|
+
if (kind === "") {
|
|
124
|
+
const typeValue = readPayloadString(operation["type"]);
|
|
125
|
+
const operationHelp = typeValue === "" ? help : createEditorOperationHelp(typeValue);
|
|
126
|
+
return {
|
|
127
|
+
summary: typeValue === ""
|
|
128
|
+
? `Editor operation payload is missing "kind". Use operation.kind, for example ${JSON.stringify(help.examples[0])}.`
|
|
129
|
+
: `Editor operation payload used "type": "${typeValue}", but GDH dispatches editor operations with "kind". Use ${JSON.stringify(operationHelp.examples[0])}.`,
|
|
130
|
+
reasons: typeValue === ""
|
|
131
|
+
? ["operation_kind_missing"]
|
|
132
|
+
: ["operation_kind_missing", "operation_type_unsupported"],
|
|
133
|
+
help: operationHelp,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
if (!KNOWN_EDITOR_OPERATION_KINDS.has(kind)) {
|
|
137
|
+
return {
|
|
138
|
+
summary: `Unsupported editor operation kind "${kind}". Use one of: ${[
|
|
139
|
+
...KNOWN_EDITOR_OPERATION_KINDS,
|
|
140
|
+
].join(", ")}.`,
|
|
141
|
+
reasons: ["operation_unsupported"],
|
|
142
|
+
help,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
const missingField = requiredFieldForOperation(kind, operation);
|
|
146
|
+
if (missingField !== null) {
|
|
147
|
+
return {
|
|
148
|
+
summary: `Editor operation "${kind}" requires "${missingField}". Example: ${JSON.stringify(createEditorOperationHelp(kind).examples[0])}.`,
|
|
149
|
+
reasons: [`${toSnakeCase(missingField)}_missing`],
|
|
150
|
+
help: createEditorOperationHelp(kind),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
if (kind === "batch.apply") {
|
|
154
|
+
const operations = operation["operations"];
|
|
155
|
+
if (!Array.isArray(operations)) {
|
|
156
|
+
return {
|
|
157
|
+
summary: 'Editor operation "batch.apply" requires "operations" as an array of operation payloads.',
|
|
158
|
+
reasons: ["batch_operations_invalid"],
|
|
159
|
+
help,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
for (const child of operations) {
|
|
163
|
+
if (child === null || Array.isArray(child) || typeof child !== "object") {
|
|
164
|
+
return {
|
|
165
|
+
summary: 'Editor operation "batch.apply" children must be operation objects.',
|
|
166
|
+
reasons: ["batch_child_operation_invalid"],
|
|
167
|
+
help,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
const childValidation = validateEditorOperation(child);
|
|
171
|
+
if (childValidation !== null)
|
|
172
|
+
return childValidation;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
const KNOWN_EDITOR_OPERATION_KINDS = new Set([
|
|
178
|
+
"scene.create",
|
|
179
|
+
"scene.tree",
|
|
180
|
+
"scene.save",
|
|
181
|
+
"node.add",
|
|
182
|
+
"node.remove",
|
|
183
|
+
"node.reparent",
|
|
184
|
+
"node.duplicate",
|
|
185
|
+
"node.set_property",
|
|
186
|
+
"node.get_property",
|
|
187
|
+
"node.inspect",
|
|
188
|
+
"resource.create",
|
|
189
|
+
"resource.read",
|
|
190
|
+
"resource.properties",
|
|
191
|
+
"resource.set_property",
|
|
192
|
+
"script.attach",
|
|
193
|
+
"class.search",
|
|
194
|
+
"class.info",
|
|
195
|
+
"editor.state",
|
|
196
|
+
"batch.apply",
|
|
197
|
+
]);
|
|
198
|
+
function requiredFieldForOperation(kind, operation) {
|
|
199
|
+
const require = (...fields) => fields.find((field) => readPayloadString(operation[field]) === "") ?? null;
|
|
200
|
+
switch (kind) {
|
|
201
|
+
case "scene.create":
|
|
202
|
+
case "scene.tree":
|
|
203
|
+
case "scene.save":
|
|
204
|
+
return require("scenePath");
|
|
205
|
+
case "node.add":
|
|
206
|
+
return require("scenePath", "nodeType", "nodeName");
|
|
207
|
+
case "node.remove":
|
|
208
|
+
case "node.reparent":
|
|
209
|
+
case "node.duplicate":
|
|
210
|
+
return require("scenePath", "nodePath");
|
|
211
|
+
case "node.set_property":
|
|
212
|
+
case "node.get_property":
|
|
213
|
+
return require("scenePath", "nodePath", "propertyName");
|
|
214
|
+
case "node.inspect":
|
|
215
|
+
return require("scenePath");
|
|
216
|
+
case "resource.create":
|
|
217
|
+
return require("resourcePath", "resourceType");
|
|
218
|
+
case "resource.read":
|
|
219
|
+
case "resource.properties":
|
|
220
|
+
return require("resourcePath");
|
|
221
|
+
case "resource.set_property":
|
|
222
|
+
return require("resourcePath", "propertyName");
|
|
223
|
+
case "script.attach":
|
|
224
|
+
return require("scenePath", "nodePath", "scriptPath");
|
|
225
|
+
case "class.info":
|
|
226
|
+
return require("className");
|
|
227
|
+
default:
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function createEditorOperationHelp(kind) {
|
|
232
|
+
const example = editorOperationExample(kind);
|
|
233
|
+
return {
|
|
234
|
+
usage: "Use editor.operation.run with an operation object that contains a kind field, or prefer focused MCP tools such as editor.state, editor.scene.tree, editor.resource.read, editor.resource.properties, editor.node.inspect, editor.class.search, and editor.class.info.",
|
|
235
|
+
helpCommand: 'gdh editor operation run --help; example: gdh editor operation run --input-json \'{"kind":"class.search","query":"Label"}\'',
|
|
236
|
+
examples: [example],
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
function editorOperationExample(kind) {
|
|
240
|
+
switch (kind) {
|
|
241
|
+
case "scene.tree":
|
|
242
|
+
return { kind: "scene.tree", scenePath: "res://path/to/scene.tscn", maxDepth: 3 };
|
|
243
|
+
case "node.inspect":
|
|
244
|
+
return {
|
|
245
|
+
kind: "node.inspect",
|
|
246
|
+
scenePath: "res://path/to/scene.tscn",
|
|
247
|
+
nodePath: ".",
|
|
248
|
+
includePropertyList: true,
|
|
249
|
+
propertyLimit: 40,
|
|
250
|
+
};
|
|
251
|
+
case "resource.read":
|
|
252
|
+
return {
|
|
253
|
+
kind: "resource.read",
|
|
254
|
+
resourcePath: "res://path/to/resource.tres",
|
|
255
|
+
propertyNames: ["name"],
|
|
256
|
+
};
|
|
257
|
+
case "resource.properties":
|
|
258
|
+
return { kind: "resource.properties", resourcePath: "res://path/to/resource.tres" };
|
|
259
|
+
case "class.search":
|
|
260
|
+
return { kind: "class.search", query: "Label" };
|
|
261
|
+
case "class.info":
|
|
262
|
+
return { kind: "class.info", className: "Label", propertyQuery: "text" };
|
|
263
|
+
case "editor.state":
|
|
264
|
+
return { kind: "editor.state" };
|
|
265
|
+
default:
|
|
266
|
+
return { kind: "editor.state" };
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function readPayloadString(value) {
|
|
270
|
+
return typeof value === "string" ? value : "";
|
|
271
|
+
}
|
|
272
|
+
function toSnakeCase(value) {
|
|
273
|
+
return value.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
274
|
+
}
|
|
120
275
|
export async function runEditorOperation(input) {
|
|
121
276
|
const paths = resolveEditorBridgePaths(input);
|
|
277
|
+
const operationValidation = validateEditorOperation(input.operation);
|
|
278
|
+
if (operationValidation !== null) {
|
|
279
|
+
return {
|
|
280
|
+
targetPath: paths.targetRootPath,
|
|
281
|
+
state: "failed",
|
|
282
|
+
summary: operationValidation.summary,
|
|
283
|
+
reasons: operationValidation.reasons,
|
|
284
|
+
session: {
|
|
285
|
+
targetPath: paths.targetRootPath,
|
|
286
|
+
godotProjectRootPath: paths.godotProjectRootPath,
|
|
287
|
+
mode: input.mode ?? "auto",
|
|
288
|
+
state: "blocked",
|
|
289
|
+
kind: null,
|
|
290
|
+
summary: "Editor operation was rejected before session startup.",
|
|
291
|
+
reasons: operationValidation.reasons,
|
|
292
|
+
identity: paths.identity,
|
|
293
|
+
adoptedEditor: null,
|
|
294
|
+
},
|
|
295
|
+
operation: input.operation,
|
|
296
|
+
output: null,
|
|
297
|
+
help: operationValidation.help,
|
|
298
|
+
artifacts: null,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
122
301
|
const session = await inspectEditorBridgeSession(input);
|
|
123
302
|
if (session.state !== "ready" || session.kind === null) {
|
|
124
303
|
return {
|
|
@@ -129,6 +308,7 @@ export async function runEditorOperation(input) {
|
|
|
129
308
|
session,
|
|
130
309
|
operation: input.operation,
|
|
131
310
|
output: null,
|
|
311
|
+
help: null,
|
|
132
312
|
artifacts: null,
|
|
133
313
|
};
|
|
134
314
|
}
|
|
@@ -145,6 +325,7 @@ export async function runEditorOperation(input) {
|
|
|
145
325
|
session,
|
|
146
326
|
operation: input.operation,
|
|
147
327
|
output: null,
|
|
328
|
+
help: null,
|
|
148
329
|
artifacts: null,
|
|
149
330
|
};
|
|
150
331
|
}
|
|
@@ -198,6 +379,7 @@ export async function runEditorOperation(input) {
|
|
|
198
379
|
session,
|
|
199
380
|
operation: input.operation,
|
|
200
381
|
output: null,
|
|
382
|
+
help: null,
|
|
201
383
|
artifacts,
|
|
202
384
|
};
|
|
203
385
|
}
|
|
@@ -210,6 +392,7 @@ export async function runEditorOperation(input) {
|
|
|
210
392
|
session,
|
|
211
393
|
operation: input.operation,
|
|
212
394
|
output: runnerOutput.output ?? null,
|
|
395
|
+
help: runnerOutput.help ?? null,
|
|
213
396
|
artifacts,
|
|
214
397
|
};
|
|
215
398
|
}
|
|
@@ -224,6 +407,7 @@ async function runAdoptedEditorOperation(input) {
|
|
|
224
407
|
session: input.session,
|
|
225
408
|
operation: input.input.operation,
|
|
226
409
|
output: null,
|
|
410
|
+
help: null,
|
|
227
411
|
artifacts: null,
|
|
228
412
|
};
|
|
229
413
|
}
|
|
@@ -259,6 +443,7 @@ async function runAdoptedEditorOperation(input) {
|
|
|
259
443
|
session: input.session,
|
|
260
444
|
operation: input.input.operation,
|
|
261
445
|
output: runnerOutput.output ?? null,
|
|
446
|
+
help: runnerOutput.help ?? null,
|
|
262
447
|
artifacts,
|
|
263
448
|
};
|
|
264
449
|
}
|
|
@@ -537,6 +722,11 @@ func run_editor_operation(operation: Dictionary) -> Dictionary:
|
|
|
537
722
|
|
|
538
723
|
func _dispatch_operation(operation: Dictionary) -> Dictionary:
|
|
539
724
|
var kind := str(operation.get("kind", ""))
|
|
725
|
+
if kind == "":
|
|
726
|
+
var type_value := str(operation.get("type", ""))
|
|
727
|
+
if type_value != "":
|
|
728
|
+
return _failure("Editor operation payload used type='" + type_value + "', but GDH dispatches editor operations with kind. Use operation.kind instead.", ["operation_kind_missing", "operation_type_unsupported"], _operation_help(type_value))
|
|
729
|
+
return _failure("Editor operation payload is missing kind.", ["operation_kind_missing"], _operation_help("editor.state"))
|
|
540
730
|
match kind:
|
|
541
731
|
"scene.create":
|
|
542
732
|
return _scene_create(operation)
|
|
@@ -556,10 +746,14 @@ func _dispatch_operation(operation: Dictionary) -> Dictionary:
|
|
|
556
746
|
return _node_set_property(operation)
|
|
557
747
|
"node.get_property":
|
|
558
748
|
return _node_get_property(operation)
|
|
749
|
+
"node.inspect":
|
|
750
|
+
return _node_inspect(operation)
|
|
559
751
|
"resource.create":
|
|
560
752
|
return _resource_create(operation)
|
|
561
753
|
"resource.read":
|
|
562
754
|
return _resource_read(operation)
|
|
755
|
+
"resource.properties":
|
|
756
|
+
return _resource_properties(operation)
|
|
563
757
|
"resource.set_property":
|
|
564
758
|
return _resource_set_property(operation)
|
|
565
759
|
"script.attach":
|
|
@@ -573,7 +767,7 @@ func _dispatch_operation(operation: Dictionary) -> Dictionary:
|
|
|
573
767
|
"batch.apply":
|
|
574
768
|
return _batch_apply(operation)
|
|
575
769
|
_:
|
|
576
|
-
return _failure("Unsupported editor operation: " + kind, ["operation_unsupported"])
|
|
770
|
+
return _failure("Unsupported editor operation: " + kind, ["operation_unsupported"], _operation_help(kind))
|
|
577
771
|
|
|
578
772
|
func _scene_create(operation: Dictionary) -> Dictionary:
|
|
579
773
|
var scene_path := _res_path(str(operation.get("scenePath", "")))
|
|
@@ -597,6 +791,8 @@ func _scene_create(operation: Dictionary) -> Dictionary:
|
|
|
597
791
|
|
|
598
792
|
func _scene_tree(operation: Dictionary) -> Dictionary:
|
|
599
793
|
var scene_path := _res_path(str(operation.get("scenePath", "")))
|
|
794
|
+
if scene_path == "res://":
|
|
795
|
+
return _failure("scene.tree requires scenePath.", ["scene_path_missing"], _operation_help("scene.tree"))
|
|
600
796
|
var loaded = load(scene_path)
|
|
601
797
|
if loaded == null or not (loaded is PackedScene):
|
|
602
798
|
return _failure("Scene could not be loaded: " + scene_path, ["scene_load_failed"])
|
|
@@ -739,6 +935,31 @@ func _node_get_property(operation: Dictionary) -> Dictionary:
|
|
|
739
935
|
root.queue_free()
|
|
740
936
|
return _success("Node property read.", {"scenePath": scene_path, "nodePath": node_path, "propertyName": property_name, "value": value})
|
|
741
937
|
|
|
938
|
+
func _node_inspect(operation: Dictionary) -> Dictionary:
|
|
939
|
+
var scene_path := _res_path(str(operation.get("scenePath", "")))
|
|
940
|
+
if scene_path == "res://":
|
|
941
|
+
return _failure("node.inspect requires scenePath.", ["scene_path_missing"], _operation_help("node.inspect"))
|
|
942
|
+
var root = _load_scene_root(scene_path)
|
|
943
|
+
if root == null:
|
|
944
|
+
return _failure("Scene could not be loaded: " + scene_path, ["scene_load_failed"])
|
|
945
|
+
var node_path := str(operation.get("nodePath", "."))
|
|
946
|
+
var node = _find_node(root, node_path)
|
|
947
|
+
if node == null:
|
|
948
|
+
root.queue_free()
|
|
949
|
+
return _failure("Node not found: " + node_path, ["node_not_found"])
|
|
950
|
+
var property_names = operation.get("propertyNames", [])
|
|
951
|
+
var properties := {}
|
|
952
|
+
if typeof(property_names) == TYPE_ARRAY:
|
|
953
|
+
for property_name in property_names:
|
|
954
|
+
var key := str(property_name)
|
|
955
|
+
properties[key] = _encode_value(node.get(key))
|
|
956
|
+
var property_list := []
|
|
957
|
+
if bool(operation.get("includePropertyList", false)):
|
|
958
|
+
property_list = _filter_property_list(node.get_property_list(), str(operation.get("propertyQuery", "")), int(operation.get("propertyLimit", 50)))
|
|
959
|
+
var summary := _node_summary(node, node_path, 0, 0)
|
|
960
|
+
root.queue_free()
|
|
961
|
+
return _success("Node inspected.", {"scenePath": scene_path, "nodePath": node_path, "node": summary, "properties": properties, "propertyList": property_list})
|
|
962
|
+
|
|
742
963
|
func _resource_create(operation: Dictionary) -> Dictionary:
|
|
743
964
|
var resource_path := _res_path(str(operation.get("resourcePath", "")))
|
|
744
965
|
var resource_type := str(operation.get("resourceType", ""))
|
|
@@ -754,6 +975,8 @@ func _resource_create(operation: Dictionary) -> Dictionary:
|
|
|
754
975
|
|
|
755
976
|
func _resource_read(operation: Dictionary) -> Dictionary:
|
|
756
977
|
var resource_path := _res_path(str(operation.get("resourcePath", "")))
|
|
978
|
+
if resource_path == "res://":
|
|
979
|
+
return _failure("resource.read requires resourcePath.", ["resource_path_missing"], _operation_help("resource.read"))
|
|
757
980
|
var resource = load(resource_path)
|
|
758
981
|
if resource == null or not (resource is Resource):
|
|
759
982
|
return _failure("Resource could not be loaded: " + resource_path, ["resource_load_failed"])
|
|
@@ -766,6 +989,17 @@ func _resource_read(operation: Dictionary) -> Dictionary:
|
|
|
766
989
|
var script = resource.get_script()
|
|
767
990
|
return _success("Resource read.", {"resourcePath": resource_path, "class": resource.get_class(), "scriptPath": script.resource_path if script else null, "properties": properties})
|
|
768
991
|
|
|
992
|
+
func _resource_properties(operation: Dictionary) -> Dictionary:
|
|
993
|
+
var resource_path := _res_path(str(operation.get("resourcePath", "")))
|
|
994
|
+
if resource_path == "res://":
|
|
995
|
+
return _failure("resource.properties requires resourcePath.", ["resource_path_missing"], _operation_help("resource.properties"))
|
|
996
|
+
var resource = load(resource_path)
|
|
997
|
+
if resource == null or not (resource is Resource):
|
|
998
|
+
return _failure("Resource could not be loaded: " + resource_path, ["resource_load_failed"])
|
|
999
|
+
var script = resource.get_script()
|
|
1000
|
+
var properties := _filter_property_list(resource.get_property_list(), str(operation.get("propertyQuery", "")), int(operation.get("propertyLimit", 80)))
|
|
1001
|
+
return _success("Resource properties loaded.", {"resourcePath": resource_path, "class": resource.get_class(), "scriptPath": script.resource_path if script else null, "properties": properties, "propertiesTruncated": properties.size() >= int(operation.get("propertyLimit", 80))})
|
|
1002
|
+
|
|
769
1003
|
func _resource_set_property(operation: Dictionary) -> Dictionary:
|
|
770
1004
|
var resource_path := _res_path(str(operation.get("resourcePath", "")))
|
|
771
1005
|
var resource = load(resource_path)
|
|
@@ -871,13 +1105,34 @@ func _class_info(operation: Dictionary) -> Dictionary:
|
|
|
871
1105
|
return _failure("Class not found: " + class_id, ["class_not_found"])
|
|
872
1106
|
|
|
873
1107
|
func _editor_state(_operation: Dictionary) -> Dictionary:
|
|
1108
|
+
var editor_interface = _editor_interface()
|
|
1109
|
+
var current_scene_path = null
|
|
1110
|
+
var open_scenes := []
|
|
1111
|
+
var selected_node_paths := []
|
|
1112
|
+
if editor_interface != null:
|
|
1113
|
+
if editor_interface.has_method("get_open_scenes"):
|
|
1114
|
+
for scene_path in editor_interface.get_open_scenes():
|
|
1115
|
+
open_scenes.append(str(scene_path))
|
|
1116
|
+
var edited_root = editor_interface.get_edited_scene_root()
|
|
1117
|
+
if edited_root != null:
|
|
1118
|
+
current_scene_path = edited_root.scene_file_path
|
|
1119
|
+
var selection = editor_interface.get_selection()
|
|
1120
|
+
if selection != null:
|
|
1121
|
+
for selected_node in selection.get_selected_nodes():
|
|
1122
|
+
if edited_root != null and selected_node is Node:
|
|
1123
|
+
selected_node_paths.append(str(edited_root.get_path_to(selected_node)))
|
|
1124
|
+
else:
|
|
1125
|
+
selected_node_paths.append(str(selected_node.get_path()))
|
|
874
1126
|
return _success("Editor state loaded.", {
|
|
875
1127
|
"projectName": ProjectSettings.get_setting("application/config/name", ""),
|
|
876
1128
|
"engineVersion": Engine.get_version_info().get("string", ""),
|
|
877
1129
|
"features": ProjectSettings.get_setting("application/config/features", []),
|
|
878
1130
|
"godotProjectRootPath": ProjectSettings.globalize_path("res://"),
|
|
1131
|
+
"editorContextAvailable": editor_interface != null,
|
|
1132
|
+
"currentScenePath": current_scene_path,
|
|
1133
|
+
"openScenes": open_scenes,
|
|
879
1134
|
"dirtyScenes": [],
|
|
880
|
-
"selectedNodePaths":
|
|
1135
|
+
"selectedNodePaths": selected_node_paths,
|
|
881
1136
|
})
|
|
882
1137
|
|
|
883
1138
|
func _batch_apply(operation: Dictionary) -> Dictionary:
|
|
@@ -940,23 +1195,67 @@ func _decode_value(value):
|
|
|
940
1195
|
return Color(float(color.get("r", 0.0)), float(color.get("g", 0.0)), float(color.get("b", 0.0)), float(color.get("a", 1.0)))
|
|
941
1196
|
return value
|
|
942
1197
|
|
|
943
|
-
func _encode_value(value):
|
|
1198
|
+
func _encode_value(value, depth := 0):
|
|
944
1199
|
if value == null:
|
|
945
1200
|
return null
|
|
1201
|
+
if depth >= 4:
|
|
1202
|
+
return {"$truncated": "max_depth", "text": str(value)}
|
|
946
1203
|
if value is Vector2:
|
|
947
1204
|
return {"$vector2": {"x": value.x, "y": value.y}}
|
|
948
1205
|
if value is Color:
|
|
949
1206
|
return {"$color": {"r": value.r, "g": value.g, "b": value.b, "a": value.a}}
|
|
950
1207
|
if value is Resource:
|
|
951
|
-
|
|
1208
|
+
var resource_path: String = value.resource_path
|
|
1209
|
+
return {"$resource": resource_path if resource_path != "" else null, "class": value.get_class(), "text": str(value)}
|
|
952
1210
|
var value_type := typeof(value)
|
|
953
|
-
if value_type in [TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING
|
|
1211
|
+
if value_type in [TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING]:
|
|
954
1212
|
return value
|
|
1213
|
+
if value_type == TYPE_ARRAY:
|
|
1214
|
+
var encoded := []
|
|
1215
|
+
var count := 0
|
|
1216
|
+
for item in value:
|
|
1217
|
+
if count >= 100:
|
|
1218
|
+
encoded.append({"$truncated": "max_items"})
|
|
1219
|
+
break
|
|
1220
|
+
encoded.append(_encode_value(item, depth + 1))
|
|
1221
|
+
count += 1
|
|
1222
|
+
return encoded
|
|
1223
|
+
if value_type == TYPE_DICTIONARY:
|
|
1224
|
+
var encoded_dict := {}
|
|
1225
|
+
var count := 0
|
|
1226
|
+
for key in value.keys():
|
|
1227
|
+
if count >= 100:
|
|
1228
|
+
encoded_dict["$truncated"] = "max_items"
|
|
1229
|
+
break
|
|
1230
|
+
encoded_dict[str(key)] = _encode_value(value[key], depth + 1)
|
|
1231
|
+
count += 1
|
|
1232
|
+
return encoded_dict
|
|
955
1233
|
return str(value)
|
|
956
1234
|
|
|
957
1235
|
func _property_summary(property: Dictionary) -> Dictionary:
|
|
958
1236
|
return {"name": str(property.get("name", "")), "type": int(property.get("type", TYPE_NIL)), "hint": int(property.get("hint", 0)), "usage": int(property.get("usage", 0))}
|
|
959
1237
|
|
|
1238
|
+
func _filter_property_list(property_list: Array, query: String, limit: int) -> Array:
|
|
1239
|
+
var lowered_query := query.to_lower()
|
|
1240
|
+
var effective_limit := limit if limit > 0 else 50
|
|
1241
|
+
var properties := []
|
|
1242
|
+
for property in property_list:
|
|
1243
|
+
var name := str(property.get("name", ""))
|
|
1244
|
+
if lowered_query != "" and not name.to_lower().contains(lowered_query):
|
|
1245
|
+
continue
|
|
1246
|
+
properties.append(_property_summary(property))
|
|
1247
|
+
if properties.size() >= effective_limit:
|
|
1248
|
+
break
|
|
1249
|
+
return properties
|
|
1250
|
+
|
|
1251
|
+
func _editor_interface():
|
|
1252
|
+
var plugin = get("_plugin")
|
|
1253
|
+
if plugin == null:
|
|
1254
|
+
return null
|
|
1255
|
+
if plugin.has_method("get_editor_interface"):
|
|
1256
|
+
return plugin.get_editor_interface()
|
|
1257
|
+
return null
|
|
1258
|
+
|
|
960
1259
|
func _find_script_class(class_id: String) -> Dictionary:
|
|
961
1260
|
for entry in ProjectSettings.get_global_class_list():
|
|
962
1261
|
if str(entry.get("class", "")) == class_id:
|
|
@@ -1048,8 +1347,25 @@ func _write_json(path: String, value: Dictionary) -> void:
|
|
|
1048
1347
|
func _success(summary: String, output: Dictionary) -> Dictionary:
|
|
1049
1348
|
return {"ok": true, "summary": summary, "reasons": [], "output": output}
|
|
1050
1349
|
|
|
1051
|
-
func _failure(summary: String, reasons: Array) -> Dictionary:
|
|
1052
|
-
return {"ok": false, "summary": summary, "reasons": reasons, "output": null}
|
|
1350
|
+
func _failure(summary: String, reasons: Array, help := {}) -> Dictionary:
|
|
1351
|
+
return {"ok": false, "summary": summary, "reasons": reasons, "output": null, "help": help}
|
|
1352
|
+
|
|
1353
|
+
func _operation_help(kind: String) -> Dictionary:
|
|
1354
|
+
var examples := {
|
|
1355
|
+
"scene.tree": {"kind": "scene.tree", "scenePath": "res://path/to/scene.tscn", "maxDepth": 3},
|
|
1356
|
+
"node.inspect": {"kind": "node.inspect", "scenePath": "res://path/to/scene.tscn", "nodePath": ".", "includePropertyList": true, "propertyLimit": 40},
|
|
1357
|
+
"resource.read": {"kind": "resource.read", "resourcePath": "res://path/to/resource.tres", "propertyNames": ["name"]},
|
|
1358
|
+
"resource.properties": {"kind": "resource.properties", "resourcePath": "res://path/to/resource.tres"},
|
|
1359
|
+
"class.search": {"kind": "class.search", "query": "Label"},
|
|
1360
|
+
"class.info": {"kind": "class.info", "className": "Label", "propertyQuery": "text"},
|
|
1361
|
+
"editor.state": {"kind": "editor.state"},
|
|
1362
|
+
}
|
|
1363
|
+
var example = examples.get(kind, {"kind": "editor.state"})
|
|
1364
|
+
return {
|
|
1365
|
+
"usage": "Use editor.operation.run with operation.kind, or prefer focused MCP tools: editor.state, editor.scene.tree, editor.node.inspect, editor.resource.read, editor.resource.properties, editor.class.search, editor.class.info.",
|
|
1366
|
+
"helpCommand": "gdh editor operation run --help",
|
|
1367
|
+
"examples": [example],
|
|
1368
|
+
}
|
|
1053
1369
|
`;
|
|
1054
1370
|
}
|
|
1055
1371
|
export function renderEditorOperationCatalogGdscript() {
|