@skillcap/gdh 4.0.0 → 4.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.
Files changed (72) hide show
  1. package/INSTALL-BUNDLE.json +1 -1
  2. package/RELEASE-SPAN-UPDATE-CONTRACTS.json +138 -0
  3. package/node_modules/@gdh/adapters/dist/skill-rendering.js +3 -3
  4. package/node_modules/@gdh/adapters/dist/skill-rendering.js.map +1 -1
  5. package/node_modules/@gdh/adapters/package.json +7 -7
  6. package/node_modules/@gdh/authoring/dist/index.d.ts +1 -0
  7. package/node_modules/@gdh/authoring/dist/index.d.ts.map +1 -1
  8. package/node_modules/@gdh/authoring/dist/index.js +1 -0
  9. package/node_modules/@gdh/authoring/dist/index.js.map +1 -1
  10. package/node_modules/@gdh/authoring/dist/lsp-client.d.ts +5 -2
  11. package/node_modules/@gdh/authoring/dist/lsp-client.d.ts.map +1 -1
  12. package/node_modules/@gdh/authoring/dist/lsp-client.js +6 -1
  13. package/node_modules/@gdh/authoring/dist/lsp-client.js.map +1 -1
  14. package/node_modules/@gdh/authoring/dist/lsp-test-server.test-utils.d.ts +3 -0
  15. package/node_modules/@gdh/authoring/dist/lsp-test-server.test-utils.d.ts.map +1 -1
  16. package/node_modules/@gdh/authoring/dist/lsp-test-server.test-utils.js +22 -0
  17. package/node_modules/@gdh/authoring/dist/lsp-test-server.test-utils.js.map +1 -1
  18. package/node_modules/@gdh/authoring/dist/lsp.d.ts +12 -0
  19. package/node_modules/@gdh/authoring/dist/lsp.d.ts.map +1 -1
  20. package/node_modules/@gdh/authoring/dist/lsp.js +128 -3
  21. package/node_modules/@gdh/authoring/dist/lsp.js.map +1 -1
  22. package/node_modules/@gdh/authoring/dist/prepare.d.ts.map +1 -1
  23. package/node_modules/@gdh/authoring/dist/prepare.js +104 -12
  24. package/node_modules/@gdh/authoring/dist/prepare.js.map +1 -1
  25. package/node_modules/@gdh/authoring/dist/symbol-navigation.d.ts +23 -0
  26. package/node_modules/@gdh/authoring/dist/symbol-navigation.d.ts.map +1 -0
  27. package/node_modules/@gdh/authoring/dist/symbol-navigation.js +557 -0
  28. package/node_modules/@gdh/authoring/dist/symbol-navigation.js.map +1 -0
  29. package/node_modules/@gdh/authoring/package.json +2 -2
  30. package/node_modules/@gdh/cli/dist/index.d.ts.map +1 -1
  31. package/node_modules/@gdh/cli/dist/index.js +4 -2
  32. package/node_modules/@gdh/cli/dist/index.js.map +1 -1
  33. package/node_modules/@gdh/cli/package.json +11 -11
  34. package/node_modules/@gdh/core/dist/editor-operation-runner.d.ts.map +1 -1
  35. package/node_modules/@gdh/core/dist/editor-operation-runner.js +530 -1
  36. package/node_modules/@gdh/core/dist/editor-operation-runner.js.map +1 -1
  37. package/node_modules/@gdh/core/dist/index.d.ts +90 -9
  38. package/node_modules/@gdh/core/dist/index.d.ts.map +1 -1
  39. package/node_modules/@gdh/core/dist/index.js +17 -6
  40. package/node_modules/@gdh/core/dist/index.js.map +1 -1
  41. package/node_modules/@gdh/core/package.json +1 -1
  42. package/node_modules/@gdh/docs/dist/templates/guidance/authoring-and-validation.md.tpl +2 -0
  43. package/node_modules/@gdh/docs/dist/templates/guidance/editor-bridge.md.tpl +4 -1
  44. package/node_modules/@gdh/docs/package.json +2 -2
  45. package/node_modules/@gdh/editor/dist/index.d.ts +101 -0
  46. package/node_modules/@gdh/editor/dist/index.d.ts.map +1 -1
  47. package/node_modules/@gdh/editor/dist/index.js +166 -5
  48. package/node_modules/@gdh/editor/dist/index.js.map +1 -1
  49. package/node_modules/@gdh/editor/package.json +2 -2
  50. package/node_modules/@gdh/mcp/dist/bridge-tools.d.ts +4 -3
  51. package/node_modules/@gdh/mcp/dist/bridge-tools.d.ts.map +1 -1
  52. package/node_modules/@gdh/mcp/dist/bridge-tools.js +26 -1
  53. package/node_modules/@gdh/mcp/dist/bridge-tools.js.map +1 -1
  54. package/node_modules/@gdh/mcp/dist/index.d.ts.map +1 -1
  55. package/node_modules/@gdh/mcp/dist/index.js +969 -80
  56. package/node_modules/@gdh/mcp/dist/index.js.map +1 -1
  57. package/node_modules/@gdh/mcp/package.json +8 -8
  58. package/node_modules/@gdh/observability/package.json +2 -2
  59. package/node_modules/@gdh/runtime/dist/bridge-broker-client.d.ts +4 -1
  60. package/node_modules/@gdh/runtime/dist/bridge-broker-client.d.ts.map +1 -1
  61. package/node_modules/@gdh/runtime/dist/bridge-broker-client.js +5 -0
  62. package/node_modules/@gdh/runtime/dist/bridge-broker-client.js.map +1 -1
  63. package/node_modules/@gdh/runtime/dist/bridge-broker.d.ts +10 -1
  64. package/node_modules/@gdh/runtime/dist/bridge-broker.d.ts.map +1 -1
  65. package/node_modules/@gdh/runtime/dist/bridge-broker.js +270 -53
  66. package/node_modules/@gdh/runtime/dist/bridge-broker.js.map +1 -1
  67. package/node_modules/@gdh/runtime/dist/bridge-surface.js +11 -3
  68. package/node_modules/@gdh/runtime/dist/bridge-surface.js.map +1 -1
  69. package/node_modules/@gdh/runtime/package.json +2 -2
  70. package/node_modules/@gdh/scan/package.json +3 -3
  71. package/node_modules/@gdh/verify/package.json +6 -6
  72. package/package.json +12 -12
@@ -1,6 +1,6 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
- import { doctorAuthoringDiagnostics, getAuthoringDiagnosticsStatus, getCurrentAuthoringDiagnostics, readProjectConfig, readWorktreeState, refreshAuthoringDiagnostics, resolveAuthoringStatus, resolveEffectiveTargetPath, resolveTargetGodotDocsVersion, runAuthoringCheck, runTargetPrepare, warmupManagedLsp, } from "@gdh/authoring";
3
+ import { doctorAuthoringDiagnostics, getAuthoringDiagnosticsStatus, getCurrentAuthoringDiagnostics, getAuthoringDocumentSymbols, getAuthoringSymbolDeclaration, getAuthoringSymbolDefinition, getAuthoringSymbolHover, getAuthoringSymbolReferences, getAuthoringSymbolStatus, readProjectConfig, readWorktreeState, refreshAuthoringDiagnostics, resolveAuthoringStatus, resolveEffectiveTargetPath, resolveTargetGodotDocsVersion, runAuthoringCheck, runTargetPrepare, warmupManagedLsp, } from "@gdh/authoring";
4
4
  import { definePackageBoundary, GDH_MCP_MANIFEST_VERSION, presentPublicRuntimeTerms, readGdhUpdateMetaOrNull, resolveGdhProductMetadata, } from "@gdh/core";
5
5
  import { fetchOfficialGodotDoc, searchOfficialGodotDocs } from "@gdh/docs";
6
6
  import { inspectEditorBridgeSession, runEditorOperation, } from "@gdh/editor";
@@ -66,6 +66,25 @@ const outputEnvelopeSchema = defineObjectSchema("Common MCP invocation envelope
66
66
  description: "Failure message when the invocation state is failed, or an empty string otherwise.",
67
67
  },
68
68
  }, ["manifestVersion", "toolName", "targetPath", "state", "error"]);
69
+ function positionSymbolProperties() {
70
+ return {
71
+ filePath: {
72
+ type: "string",
73
+ description: "Target-relative, project-relative, or absolute .gd file path.",
74
+ },
75
+ line: {
76
+ type: "number",
77
+ description: "1-based source line.",
78
+ },
79
+ column: {
80
+ type: "number",
81
+ description: "1-based source column.",
82
+ },
83
+ };
84
+ }
85
+ function definePositionSymbolSchema(description) {
86
+ return defineObjectSchema(description, positionSymbolProperties(), ["filePath", "line", "column"]);
87
+ }
69
88
  const TOOL_MANIFEST = [
70
89
  {
71
90
  name: "docs.search",
@@ -112,7 +131,7 @@ const TOOL_MANIFEST = [
112
131
  inputSchema: defineObjectSchema("Target-preparation request.", {
113
132
  sourceTargetPath: {
114
133
  type: "string",
115
- description: "Optional source target path to use when hydrating reusable .godot generated state.",
134
+ description: "Optional source target path to use when hydrating reusable .godot generated state; secondary git worktree checkouts infer the main checkout automatically when available.",
116
135
  },
117
136
  refreshImports: {
118
137
  type: "boolean",
@@ -184,33 +203,612 @@ const TOOL_MANIFEST = [
184
203
  targetPathPolicy: "optional",
185
204
  inputSchema: emptyObjectSchema,
186
205
  outputSchema: outputEnvelopeSchema,
187
- outputContract: "GdhAuthoringLspWarmupResult",
206
+ outputContract: "GdhAuthoringLspWarmupResult",
207
+ },
208
+ {
209
+ name: "authoring.symbols.status",
210
+ summary: "Report managed Godot LSP symbol-navigation health and advertised capabilities. Workspace-wide symbols are reported explicitly as unsupported when Godot does not advertise workspaceSymbolProvider.",
211
+ targetPathPolicy: "optional",
212
+ inputSchema: emptyObjectSchema,
213
+ outputSchema: outputEnvelopeSchema,
214
+ outputContract: "GdhAuthoringSymbolStatusResult",
215
+ },
216
+ {
217
+ name: "authoring.symbols.document",
218
+ summary: "Open the current .gd file text through the managed Godot LSP and return normalized document symbols. Results are on-demand and not persisted.",
219
+ targetPathPolicy: "optional",
220
+ inputSchema: defineObjectSchema("Document-symbol request.", {
221
+ filePath: {
222
+ type: "string",
223
+ description: "Target-relative, project-relative, or absolute .gd file path.",
224
+ },
225
+ }, ["filePath"]),
226
+ outputSchema: outputEnvelopeSchema,
227
+ outputContract: "GdhAuthoringDocumentSymbolsResult",
228
+ },
229
+ {
230
+ name: "authoring.symbols.definition",
231
+ summary: "Open the current .gd file text through the managed Godot LSP and return normalized go-to-definition locations for a 1-based position.",
232
+ targetPathPolicy: "optional",
233
+ inputSchema: definePositionSymbolSchema("Definition request."),
234
+ outputSchema: outputEnvelopeSchema,
235
+ outputContract: "GdhAuthoringSymbolLocationsResult",
236
+ },
237
+ {
238
+ name: "authoring.symbols.declaration",
239
+ summary: "Open the current .gd file text through the managed Godot LSP and return normalized go-to-declaration locations for a 1-based position.",
240
+ targetPathPolicy: "optional",
241
+ inputSchema: definePositionSymbolSchema("Declaration request."),
242
+ outputSchema: outputEnvelopeSchema,
243
+ outputContract: "GdhAuthoringSymbolLocationsResult",
244
+ },
245
+ {
246
+ name: "authoring.symbols.references",
247
+ summary: "Open the current .gd file text through the managed Godot LSP and return normalized references for a 1-based position. Other-file results are Godot workspace/cache-derived.",
248
+ targetPathPolicy: "optional",
249
+ inputSchema: defineObjectSchema("References request.", {
250
+ ...positionSymbolProperties(),
251
+ includeDeclaration: {
252
+ type: "boolean",
253
+ description: "Whether to include the symbol declaration in references. Defaults to true.",
254
+ },
255
+ }, ["filePath", "line", "column"]),
256
+ outputSchema: outputEnvelopeSchema,
257
+ outputContract: "GdhAuthoringSymbolLocationsResult",
258
+ },
259
+ {
260
+ name: "authoring.symbols.hover",
261
+ summary: "Open the current .gd file text through the managed Godot LSP and return hover information for a 1-based position.",
262
+ targetPathPolicy: "optional",
263
+ inputSchema: definePositionSymbolSchema("Hover request."),
264
+ outputSchema: outputEnvelopeSchema,
265
+ outputContract: "GdhAuthoringSymbolHoverResult",
266
+ },
267
+ {
268
+ name: "editor.session.status",
269
+ summary: "Inspect whether GDH can run Godot-native editor operations for the exact bound target/worktree.",
270
+ targetPathPolicy: "optional",
271
+ inputSchema: defineObjectSchema("Editor Bridge session status request.", {
272
+ mode: {
273
+ type: "string",
274
+ description: "Optional session mode: auto, headless_only, adopt_only, or disabled. Defaults to auto.",
275
+ },
276
+ godotEditorBin: {
277
+ type: "string",
278
+ description: "Optional Godot editor executable override for this invocation.",
279
+ },
280
+ }),
281
+ outputSchema: outputEnvelopeSchema,
282
+ outputContract: "GdhEditorSessionSummary",
283
+ },
284
+ {
285
+ name: "editor.state",
286
+ summary: "Read current Godot editor context for the exact target/worktree: project state plus current/open scene and selection when an adopted editor exposes them.",
287
+ targetPathPolicy: "optional",
288
+ inputSchema: defineObjectSchema("Editor state request.", {
289
+ mode: {
290
+ type: "string",
291
+ description: "Optional session mode: auto, headless_only, adopt_only, or disabled. Use adopt_only when the user asks about the already-open editor.",
292
+ },
293
+ timeoutMs: {
294
+ type: "number",
295
+ description: "Optional positive timeout in milliseconds for the editor operation.",
296
+ },
297
+ godotEditorBin: {
298
+ type: "string",
299
+ description: "Optional Godot editor executable override for this invocation.",
300
+ },
301
+ }),
302
+ outputSchema: outputEnvelopeSchema,
303
+ outputContract: "GdhEditorOperationResult",
304
+ },
305
+ {
306
+ name: "editor.scene.tree",
307
+ summary: "Load one saved scene through Godot editor APIs and return a bounded node tree. Requires scenePath; use editor.state first when you need the active editor scene.",
308
+ targetPathPolicy: "optional",
309
+ inputSchema: defineObjectSchema("Editor scene tree request.", {
310
+ scenePath: {
311
+ type: "string",
312
+ description: "Required res:// path for the saved scene to load.",
313
+ },
314
+ maxDepth: {
315
+ type: "number",
316
+ description: "Optional positive depth limit for returned children.",
317
+ },
318
+ mode: {
319
+ type: "string",
320
+ description: "Optional session mode: auto, headless_only, adopt_only, or disabled.",
321
+ },
322
+ timeoutMs: {
323
+ type: "number",
324
+ description: "Optional positive timeout in milliseconds for the editor operation.",
325
+ },
326
+ godotEditorBin: {
327
+ type: "string",
328
+ description: "Optional Godot editor executable override for this invocation.",
329
+ },
330
+ }, ["scenePath"]),
331
+ outputSchema: outputEnvelopeSchema,
332
+ outputContract: "GdhEditorOperationResult",
333
+ },
334
+ {
335
+ name: "editor.node.inspect",
336
+ summary: "Inspect one node from a saved scene: node summary plus requested property values or a bounded inspector-style property list.",
337
+ targetPathPolicy: "optional",
338
+ inputSchema: defineObjectSchema("Editor node inspection request.", {
339
+ scenePath: {
340
+ type: "string",
341
+ description: "Required res:// path for the saved scene to load.",
342
+ },
343
+ nodePath: {
344
+ type: "string",
345
+ description: "Optional node path relative to the scene root. Defaults to root.",
346
+ },
347
+ propertyNames: stringArraySchema("Optional exact property names to read from the node."),
348
+ includePropertyList: {
349
+ type: "boolean",
350
+ description: "When true, return bounded property metadata similar to inspector discovery.",
351
+ },
352
+ propertyQuery: {
353
+ type: "string",
354
+ description: "Optional substring filter for returned property metadata.",
355
+ },
356
+ propertyLimit: {
357
+ type: "number",
358
+ description: "Optional positive limit for returned property metadata.",
359
+ },
360
+ mode: {
361
+ type: "string",
362
+ description: "Optional session mode: auto, headless_only, adopt_only, or disabled.",
363
+ },
364
+ timeoutMs: {
365
+ type: "number",
366
+ description: "Optional positive timeout in milliseconds for the editor operation.",
367
+ },
368
+ godotEditorBin: {
369
+ type: "string",
370
+ description: "Optional Godot editor executable override for this invocation.",
371
+ },
372
+ }, ["scenePath"]),
373
+ outputSchema: outputEnvelopeSchema,
374
+ outputContract: "GdhEditorOperationResult",
375
+ },
376
+ {
377
+ name: "editor.resource.read",
378
+ summary: "Read requested properties from one Godot resource via editor APIs. Nested arrays/dictionaries are encoded recursively with bounded resource handles.",
379
+ targetPathPolicy: "optional",
380
+ inputSchema: defineObjectSchema("Editor resource read request.", {
381
+ resourcePath: {
382
+ type: "string",
383
+ description: "Required res:// resource path, including ::subresource id when needed.",
384
+ },
385
+ propertyNames: stringArraySchema("Optional exact property names to read from the resource."),
386
+ mode: {
387
+ type: "string",
388
+ description: "Optional session mode: auto, headless_only, adopt_only, or disabled.",
389
+ },
390
+ timeoutMs: {
391
+ type: "number",
392
+ description: "Optional positive timeout in milliseconds for the editor operation.",
393
+ },
394
+ godotEditorBin: {
395
+ type: "string",
396
+ description: "Optional Godot editor executable override for this invocation.",
397
+ },
398
+ }, ["resourcePath"]),
399
+ outputSchema: outputEnvelopeSchema,
400
+ outputContract: "GdhEditorOperationResult",
401
+ },
402
+ {
403
+ name: "editor.resource.properties",
404
+ summary: "Discover bounded property metadata for one Godot resource before choosing propertyNames for editor.resource.read.",
405
+ targetPathPolicy: "optional",
406
+ inputSchema: defineObjectSchema("Editor resource property discovery request.", {
407
+ resourcePath: {
408
+ type: "string",
409
+ description: "Required res:// resource path, including ::subresource id when needed.",
410
+ },
411
+ propertyQuery: {
412
+ type: "string",
413
+ description: "Optional substring filter for returned property metadata.",
414
+ },
415
+ propertyLimit: {
416
+ type: "number",
417
+ description: "Optional positive limit for returned property metadata.",
418
+ },
419
+ mode: {
420
+ type: "string",
421
+ description: "Optional session mode: auto, headless_only, adopt_only, or disabled.",
422
+ },
423
+ timeoutMs: {
424
+ type: "number",
425
+ description: "Optional positive timeout in milliseconds for the editor operation.",
426
+ },
427
+ godotEditorBin: {
428
+ type: "string",
429
+ description: "Optional Godot editor executable override for this invocation.",
430
+ },
431
+ }, ["resourcePath"]),
432
+ outputSchema: outputEnvelopeSchema,
433
+ outputContract: "GdhEditorOperationResult",
434
+ },
435
+ {
436
+ name: "editor.class.search",
437
+ summary: "Search Godot ClassDB and registered script classes with bounded query controls.",
438
+ targetPathPolicy: "optional",
439
+ inputSchema: defineObjectSchema("Editor class search request.", {
440
+ query: {
441
+ type: "string",
442
+ description: "Optional substring query for class names.",
443
+ },
444
+ baseClass: {
445
+ type: "string",
446
+ description: "Optional base class filter.",
447
+ },
448
+ instantiableOnly: {
449
+ type: "boolean",
450
+ description: "When false, include non-instantiable classes. Defaults to true.",
451
+ },
452
+ limit: {
453
+ type: "number",
454
+ description: "Optional positive result limit.",
455
+ },
456
+ mode: {
457
+ type: "string",
458
+ description: "Optional session mode: auto, headless_only, adopt_only, or disabled.",
459
+ },
460
+ timeoutMs: {
461
+ type: "number",
462
+ description: "Optional positive timeout in milliseconds for the editor operation.",
463
+ },
464
+ godotEditorBin: {
465
+ type: "string",
466
+ description: "Optional Godot editor executable override for this invocation.",
467
+ },
468
+ }),
469
+ outputSchema: outputEnvelopeSchema,
470
+ outputContract: "GdhEditorOperationResult",
471
+ },
472
+ {
473
+ name: "editor.class.info",
474
+ summary: "Return bounded property metadata for one Godot or registered script class.",
475
+ targetPathPolicy: "optional",
476
+ inputSchema: defineObjectSchema("Editor class info request.", {
477
+ className: {
478
+ type: "string",
479
+ description: "Required Godot or registered script class name.",
480
+ },
481
+ includeInherited: {
482
+ type: "boolean",
483
+ description: "When true, include inherited properties. Defaults to true.",
484
+ },
485
+ propertyQuery: {
486
+ type: "string",
487
+ description: "Optional substring filter for returned property metadata.",
488
+ },
489
+ propertyLimit: {
490
+ type: "number",
491
+ description: "Optional positive property metadata limit.",
492
+ },
493
+ mode: {
494
+ type: "string",
495
+ description: "Optional session mode: auto, headless_only, adopt_only, or disabled.",
496
+ },
497
+ timeoutMs: {
498
+ type: "number",
499
+ description: "Optional positive timeout in milliseconds for the editor operation.",
500
+ },
501
+ godotEditorBin: {
502
+ type: "string",
503
+ description: "Optional Godot editor executable override for this invocation.",
504
+ },
505
+ }, ["className"]),
506
+ outputSchema: outputEnvelopeSchema,
507
+ outputContract: "GdhEditorOperationResult",
508
+ },
509
+ {
510
+ name: "editor.animation.player.inspect",
511
+ summary: "Inspect an AnimationPlayer or AnimationMixer node in a saved scene, including libraries, clips, autoplay, and blend metadata.",
512
+ targetPathPolicy: "optional",
513
+ inputSchema: defineObjectSchema("Editor animation player inspection request.", {
514
+ scenePath: {
515
+ type: "string",
516
+ description: "Required res:// path for the saved scene to load.",
517
+ },
518
+ animationPlayerPath: {
519
+ type: "string",
520
+ description: "Required node path to the AnimationPlayer or AnimationMixer.",
521
+ },
522
+ mode: {
523
+ type: "string",
524
+ description: "Optional session mode: auto, headless_only, adopt_only, or disabled.",
525
+ },
526
+ timeoutMs: {
527
+ type: "number",
528
+ description: "Optional positive timeout in milliseconds for the editor operation.",
529
+ },
530
+ godotEditorBin: {
531
+ type: "string",
532
+ description: "Optional Godot editor executable override for this invocation.",
533
+ },
534
+ }, ["scenePath", "animationPlayerPath"]),
535
+ outputSchema: outputEnvelopeSchema,
536
+ outputContract: "GdhEditorOperationResult",
537
+ },
538
+ {
539
+ name: "editor.animation.clip.read",
540
+ summary: "Read one AnimationPlayer clip through Godot APIs, including tracks and optionally bounded keyframe data.",
541
+ targetPathPolicy: "optional",
542
+ inputSchema: defineObjectSchema("Editor animation clip read request.", {
543
+ scenePath: {
544
+ type: "string",
545
+ description: "Required res:// path for the saved scene to load.",
546
+ },
547
+ animationPlayerPath: {
548
+ type: "string",
549
+ description: "Required node path to the AnimationPlayer or AnimationMixer.",
550
+ },
551
+ libraryName: {
552
+ type: "string",
553
+ description: "Optional AnimationLibrary name. Defaults to the global empty-name library.",
554
+ },
555
+ animationName: {
556
+ type: "string",
557
+ description: "Required animation key inside the selected library.",
558
+ },
559
+ includeKeys: {
560
+ type: "boolean",
561
+ description: "When true, include bounded keyframe data for each returned track.",
562
+ },
563
+ keyLimit: {
564
+ type: "number",
565
+ description: "Optional positive keyframe limit across each track.",
566
+ },
567
+ mode: {
568
+ type: "string",
569
+ description: "Optional session mode: auto, headless_only, adopt_only, or disabled.",
570
+ },
571
+ timeoutMs: {
572
+ type: "number",
573
+ description: "Optional positive timeout in milliseconds for the editor operation.",
574
+ },
575
+ godotEditorBin: {
576
+ type: "string",
577
+ description: "Optional Godot editor executable override for this invocation.",
578
+ },
579
+ }, ["scenePath", "animationPlayerPath", "animationName"]),
580
+ outputSchema: outputEnvelopeSchema,
581
+ outputContract: "GdhEditorOperationResult",
582
+ },
583
+ {
584
+ name: "editor.animation.clip.create",
585
+ summary: "Create or overwrite one AnimationPlayer clip in an AnimationLibrary through Godot editor APIs.",
586
+ targetPathPolicy: "optional",
587
+ inputSchema: defineObjectSchema("Editor animation clip create request.", {
588
+ scenePath: {
589
+ type: "string",
590
+ description: "Required res:// path for the saved scene to load.",
591
+ },
592
+ animationPlayerPath: {
593
+ type: "string",
594
+ description: "Required node path to the AnimationPlayer or AnimationMixer.",
595
+ },
596
+ libraryName: {
597
+ type: "string",
598
+ description: "Optional AnimationLibrary name. Defaults to the global empty-name library.",
599
+ },
600
+ animationName: {
601
+ type: "string",
602
+ description: "Required animation key inside the selected library.",
603
+ },
604
+ length: {
605
+ type: "number",
606
+ description: "Optional animation length in seconds. Defaults to 1.0.",
607
+ },
608
+ step: {
609
+ type: "number",
610
+ description: "Optional animation step in seconds.",
611
+ },
612
+ loopMode: {
613
+ type: ["string", "number"],
614
+ description: "Optional loop mode: none, linear, pingpong, or a Godot numeric value.",
615
+ },
616
+ overwrite: {
617
+ type: "boolean",
618
+ description: "When true, replace an existing clip with the same name.",
619
+ },
620
+ mode: {
621
+ type: "string",
622
+ description: "Optional session mode: auto, headless_only, adopt_only, or disabled.",
623
+ },
624
+ timeoutMs: {
625
+ type: "number",
626
+ description: "Optional positive timeout in milliseconds for the editor operation.",
627
+ },
628
+ godotEditorBin: {
629
+ type: "string",
630
+ description: "Optional Godot editor executable override for this invocation.",
631
+ },
632
+ }, ["scenePath", "animationPlayerPath", "animationName"]),
633
+ outputSchema: outputEnvelopeSchema,
634
+ outputContract: "GdhEditorOperationResult",
635
+ },
636
+ {
637
+ name: "editor.animation.clip.delete",
638
+ summary: "Delete one AnimationPlayer clip from an AnimationLibrary through Godot editor APIs.",
639
+ targetPathPolicy: "optional",
640
+ inputSchema: defineObjectSchema("Editor animation clip delete request.", {
641
+ scenePath: {
642
+ type: "string",
643
+ description: "Required res:// path for the saved scene to load.",
644
+ },
645
+ animationPlayerPath: {
646
+ type: "string",
647
+ description: "Required node path to the AnimationPlayer or AnimationMixer.",
648
+ },
649
+ libraryName: {
650
+ type: "string",
651
+ description: "Optional AnimationLibrary name. Defaults to the global empty-name library.",
652
+ },
653
+ animationName: {
654
+ type: "string",
655
+ description: "Required animation key inside the selected library.",
656
+ },
657
+ mode: {
658
+ type: "string",
659
+ description: "Optional session mode: auto, headless_only, adopt_only, or disabled.",
660
+ },
661
+ timeoutMs: {
662
+ type: "number",
663
+ description: "Optional positive timeout in milliseconds for the editor operation.",
664
+ },
665
+ godotEditorBin: {
666
+ type: "string",
667
+ description: "Optional Godot editor executable override for this invocation.",
668
+ },
669
+ }, ["scenePath", "animationPlayerPath", "animationName"]),
670
+ outputSchema: outputEnvelopeSchema,
671
+ outputContract: "GdhEditorOperationResult",
672
+ },
673
+ {
674
+ name: "editor.animation.track.add",
675
+ summary: "Add a typed Animation track to one clip, using Godot track types and a NodePath such as Sprite2D:modulate:a.",
676
+ targetPathPolicy: "optional",
677
+ inputSchema: defineObjectSchema("Editor animation track add request.", {
678
+ scenePath: {
679
+ type: "string",
680
+ description: "Required res:// path for the saved scene to load.",
681
+ },
682
+ animationPlayerPath: {
683
+ type: "string",
684
+ description: "Required node path to the AnimationPlayer or AnimationMixer.",
685
+ },
686
+ libraryName: {
687
+ type: "string",
688
+ description: "Optional AnimationLibrary name. Defaults to the global empty-name library.",
689
+ },
690
+ animationName: {
691
+ type: "string",
692
+ description: "Required animation key inside the selected library.",
693
+ },
694
+ trackType: {
695
+ type: ["string", "number"],
696
+ description: "Optional Godot Animation track type. Use value, position_3d, rotation_3d, scale_3d, blend_shape, method, bezier, audio, or animation. Defaults to value.",
697
+ },
698
+ trackPath: {
699
+ type: "string",
700
+ description: "Required Animation track NodePath, relative to the AnimationPlayer root.",
701
+ },
702
+ atPosition: {
703
+ type: "number",
704
+ description: "Optional zero-based insertion position. Defaults to appending the track.",
705
+ },
706
+ interpolation: {
707
+ type: ["string", "number"],
708
+ description: "Optional interpolation: nearest, linear, cubic, linear_angle, cubic_angle, or a Godot numeric value.",
709
+ },
710
+ updateMode: {
711
+ type: ["string", "number"],
712
+ description: "Optional value-track update mode: continuous, discrete, capture, or a Godot numeric value.",
713
+ },
714
+ mode: {
715
+ type: "string",
716
+ description: "Optional session mode: auto, headless_only, adopt_only, or disabled.",
717
+ },
718
+ timeoutMs: {
719
+ type: "number",
720
+ description: "Optional positive timeout in milliseconds for the editor operation.",
721
+ },
722
+ godotEditorBin: {
723
+ type: "string",
724
+ description: "Optional Godot editor executable override for this invocation.",
725
+ },
726
+ }, ["scenePath", "animationPlayerPath", "animationName", "trackPath"]),
727
+ outputSchema: outputEnvelopeSchema,
728
+ outputContract: "GdhEditorOperationResult",
188
729
  },
189
730
  {
190
- name: "editor.session.status",
191
- summary: "Inspect whether GDH can run Godot-native editor operations for the exact bound target/worktree.",
731
+ name: "editor.animation.track.remove",
732
+ summary: "Remove one track from an AnimationPlayer clip by zero-based track index.",
192
733
  targetPathPolicy: "optional",
193
- inputSchema: defineObjectSchema("Editor Bridge session status request.", {
734
+ inputSchema: defineObjectSchema("Editor animation track remove request.", {
735
+ scenePath: {
736
+ type: "string",
737
+ description: "Required res:// path for the saved scene to load.",
738
+ },
739
+ animationPlayerPath: {
740
+ type: "string",
741
+ description: "Required node path to the AnimationPlayer or AnimationMixer.",
742
+ },
743
+ libraryName: {
744
+ type: "string",
745
+ description: "Optional AnimationLibrary name. Defaults to the global empty-name library.",
746
+ },
747
+ animationName: {
748
+ type: "string",
749
+ description: "Required animation key inside the selected library.",
750
+ },
751
+ trackIndex: {
752
+ type: "number",
753
+ description: "Required zero-based track index.",
754
+ },
194
755
  mode: {
195
756
  type: "string",
196
- description: "Optional session mode: auto, headless_only, adopt_only, or disabled. Defaults to auto.",
757
+ description: "Optional session mode: auto, headless_only, adopt_only, or disabled.",
758
+ },
759
+ timeoutMs: {
760
+ type: "number",
761
+ description: "Optional positive timeout in milliseconds for the editor operation.",
197
762
  },
198
763
  godotEditorBin: {
199
764
  type: "string",
200
765
  description: "Optional Godot editor executable override for this invocation.",
201
766
  },
202
- }),
767
+ }, ["scenePath", "animationPlayerPath", "animationName", "trackIndex"]),
203
768
  outputSchema: outputEnvelopeSchema,
204
- outputContract: "GdhEditorSessionSummary",
769
+ outputContract: "GdhEditorOperationResult",
205
770
  },
206
771
  {
207
- name: "editor.state",
208
- summary: "Read current Godot editor context for the exact target/worktree: project state plus current/open scene and selection when an adopted editor exposes them.",
772
+ name: "editor.animation.keyframe.upsert",
773
+ summary: "Insert or replace one keyframe on an Animation track. Values use GDH's encoded Variant shape for vectors, colors, resources, and scalars.",
209
774
  targetPathPolicy: "optional",
210
- inputSchema: defineObjectSchema("Editor state request.", {
775
+ inputSchema: defineObjectSchema("Editor animation keyframe upsert request.", {
776
+ scenePath: {
777
+ type: "string",
778
+ description: "Required res:// path for the saved scene to load.",
779
+ },
780
+ animationPlayerPath: {
781
+ type: "string",
782
+ description: "Required node path to the AnimationPlayer or AnimationMixer.",
783
+ },
784
+ libraryName: {
785
+ type: "string",
786
+ description: "Optional AnimationLibrary name. Defaults to the global empty-name library.",
787
+ },
788
+ animationName: {
789
+ type: "string",
790
+ description: "Required animation key inside the selected library.",
791
+ },
792
+ trackIndex: {
793
+ type: "number",
794
+ description: "Required zero-based track index.",
795
+ },
796
+ time: {
797
+ type: "number",
798
+ description: "Required key time in seconds.",
799
+ },
800
+ value: {
801
+ type: ["string", "number", "boolean", "object", "array"],
802
+ description: "Required key value as a JSON-serializable Godot Variant encoding.",
803
+ additionalProperties: true,
804
+ },
805
+ transition: {
806
+ type: "number",
807
+ description: "Optional key transition value. Defaults to 1.0.",
808
+ },
211
809
  mode: {
212
810
  type: "string",
213
- description: "Optional session mode: auto, headless_only, adopt_only, or disabled. Use adopt_only when the user asks about the already-open editor.",
811
+ description: "Optional session mode: auto, headless_only, adopt_only, or disabled.",
214
812
  },
215
813
  timeoutMs: {
216
814
  type: "number",
@@ -220,22 +818,42 @@ const TOOL_MANIFEST = [
220
818
  type: "string",
221
819
  description: "Optional Godot editor executable override for this invocation.",
222
820
  },
223
- }),
821
+ }, ["scenePath", "animationPlayerPath", "animationName", "trackIndex", "time", "value"]),
224
822
  outputSchema: outputEnvelopeSchema,
225
823
  outputContract: "GdhEditorOperationResult",
226
824
  },
227
825
  {
228
- name: "editor.scene.tree",
229
- summary: "Load one saved scene through Godot editor APIs and return a bounded node tree. Requires scenePath; use editor.state first when you need the active editor scene.",
826
+ name: "editor.animation.keyframe.delete",
827
+ summary: "Delete one keyframe from an Animation track by key index or key time.",
230
828
  targetPathPolicy: "optional",
231
- inputSchema: defineObjectSchema("Editor scene tree request.", {
829
+ inputSchema: defineObjectSchema("Editor animation keyframe delete request.", {
232
830
  scenePath: {
233
831
  type: "string",
234
832
  description: "Required res:// path for the saved scene to load.",
235
833
  },
236
- maxDepth: {
834
+ animationPlayerPath: {
835
+ type: "string",
836
+ description: "Required node path to the AnimationPlayer or AnimationMixer.",
837
+ },
838
+ libraryName: {
839
+ type: "string",
840
+ description: "Optional AnimationLibrary name. Defaults to the global empty-name library.",
841
+ },
842
+ animationName: {
843
+ type: "string",
844
+ description: "Required animation key inside the selected library.",
845
+ },
846
+ trackIndex: {
237
847
  type: "number",
238
- description: "Optional positive depth limit for returned children.",
848
+ description: "Required zero-based track index.",
849
+ },
850
+ keyIndex: {
851
+ type: "number",
852
+ description: "Optional zero-based key index. Provide keyIndex or time.",
853
+ },
854
+ time: {
855
+ type: "number",
856
+ description: "Optional key time in seconds. Provide keyIndex or time.",
239
857
  },
240
858
  mode: {
241
859
  type: "string",
@@ -249,35 +867,60 @@ const TOOL_MANIFEST = [
249
867
  type: "string",
250
868
  description: "Optional Godot editor executable override for this invocation.",
251
869
  },
252
- }, ["scenePath"]),
870
+ }, ["scenePath", "animationPlayerPath", "animationName", "trackIndex"]),
253
871
  outputSchema: outputEnvelopeSchema,
254
872
  outputContract: "GdhEditorOperationResult",
255
873
  },
256
874
  {
257
- name: "editor.node.inspect",
258
- summary: "Inspect one node from a saved scene: node summary plus requested property values or a bounded inspector-style property list.",
875
+ name: "editor.animation.state_machine.create",
876
+ summary: "Create an AnimationNodeStateMachine tree_root on an AnimationTree node through Godot editor APIs.",
259
877
  targetPathPolicy: "optional",
260
- inputSchema: defineObjectSchema("Editor node inspection request.", {
878
+ inputSchema: defineObjectSchema("Editor animation state-machine create request.", {
261
879
  scenePath: {
262
880
  type: "string",
263
881
  description: "Required res:// path for the saved scene to load.",
264
882
  },
265
- nodePath: {
883
+ animationTreePath: {
266
884
  type: "string",
267
- description: "Optional node path relative to the scene root. Defaults to root.",
885
+ description: "Required node path to the AnimationTree.",
268
886
  },
269
- propertyNames: stringArraySchema("Optional exact property names to read from the node."),
270
- includePropertyList: {
887
+ overwrite: {
271
888
  type: "boolean",
272
- description: "When true, return bounded property metadata similar to inspector discovery.",
889
+ description: "When true, replace an existing AnimationNodeStateMachine tree_root.",
273
890
  },
274
- propertyQuery: {
891
+ properties: {
892
+ type: "object",
893
+ description: "Optional properties to set on the AnimationNodeStateMachine resource.",
894
+ additionalProperties: true,
895
+ },
896
+ mode: {
275
897
  type: "string",
276
- description: "Optional substring filter for returned property metadata.",
898
+ description: "Optional session mode: auto, headless_only, adopt_only, or disabled.",
277
899
  },
278
- propertyLimit: {
900
+ timeoutMs: {
279
901
  type: "number",
280
- description: "Optional positive limit for returned property metadata.",
902
+ description: "Optional positive timeout in milliseconds for the editor operation.",
903
+ },
904
+ godotEditorBin: {
905
+ type: "string",
906
+ description: "Optional Godot editor executable override for this invocation.",
907
+ },
908
+ }, ["scenePath", "animationTreePath"]),
909
+ outputSchema: outputEnvelopeSchema,
910
+ outputContract: "GdhEditorOperationResult",
911
+ },
912
+ {
913
+ name: "editor.animation.state_machine.read",
914
+ summary: "Read an AnimationTree state-machine graph as compact nodes and transitions without automating the editor UI.",
915
+ targetPathPolicy: "optional",
916
+ inputSchema: defineObjectSchema("Editor animation state-machine graph read request.", {
917
+ scenePath: {
918
+ type: "string",
919
+ description: "Required res:// path for the saved scene to load.",
920
+ },
921
+ animationTreePath: {
922
+ type: "string",
923
+ description: "Required node path to the AnimationTree with an AnimationNodeStateMachine tree_root.",
281
924
  },
282
925
  mode: {
283
926
  type: "string",
@@ -291,20 +934,41 @@ const TOOL_MANIFEST = [
291
934
  type: "string",
292
935
  description: "Optional Godot editor executable override for this invocation.",
293
936
  },
294
- }, ["scenePath"]),
937
+ }, ["scenePath", "animationTreePath"]),
295
938
  outputSchema: outputEnvelopeSchema,
296
939
  outputContract: "GdhEditorOperationResult",
297
940
  },
298
941
  {
299
- name: "editor.resource.read",
300
- summary: "Read requested properties from one Godot resource via editor APIs. Nested arrays/dictionaries are encoded recursively with bounded resource handles.",
942
+ name: "editor.animation.state_machine.node.upsert",
943
+ summary: "Create or update one node in an AnimationTree state-machine graph without automating the editor UI.",
301
944
  targetPathPolicy: "optional",
302
- inputSchema: defineObjectSchema("Editor resource read request.", {
303
- resourcePath: {
945
+ inputSchema: defineObjectSchema("Editor animation state-machine node upsert request.", {
946
+ scenePath: {
304
947
  type: "string",
305
- description: "Required res:// resource path, including ::subresource id when needed.",
948
+ description: "Required res:// path for the saved scene to load.",
949
+ },
950
+ animationTreePath: {
951
+ type: "string",
952
+ description: "Required node path to the AnimationTree.",
953
+ },
954
+ stateName: {
955
+ type: "string",
956
+ description: "Required state-machine node name.",
957
+ },
958
+ nodeType: {
959
+ type: "string",
960
+ description: "Optional AnimationNode type. Defaults to AnimationNodeAnimation.",
961
+ },
962
+ position: {
963
+ type: "object",
964
+ description: 'Optional graph position encoded as {"$vector2":{"x":0,"y":0}}.',
965
+ additionalProperties: true,
966
+ },
967
+ properties: {
968
+ type: "object",
969
+ description: 'Optional properties to set on the AnimationNode, for example {"animation":"idle"}.',
970
+ additionalProperties: true,
306
971
  },
307
- propertyNames: stringArraySchema("Optional exact property names to read from the resource."),
308
972
  mode: {
309
973
  type: "string",
310
974
  description: "Optional session mode: auto, headless_only, adopt_only, or disabled.",
@@ -317,26 +981,26 @@ const TOOL_MANIFEST = [
317
981
  type: "string",
318
982
  description: "Optional Godot editor executable override for this invocation.",
319
983
  },
320
- }, ["resourcePath"]),
984
+ }, ["scenePath", "animationTreePath", "stateName"]),
321
985
  outputSchema: outputEnvelopeSchema,
322
986
  outputContract: "GdhEditorOperationResult",
323
987
  },
324
988
  {
325
- name: "editor.resource.properties",
326
- summary: "Discover bounded property metadata for one Godot resource before choosing propertyNames for editor.resource.read.",
989
+ name: "editor.animation.state_machine.node.delete",
990
+ summary: "Delete one node from an AnimationTree state-machine graph.",
327
991
  targetPathPolicy: "optional",
328
- inputSchema: defineObjectSchema("Editor resource property discovery request.", {
329
- resourcePath: {
992
+ inputSchema: defineObjectSchema("Editor animation state-machine node delete request.", {
993
+ scenePath: {
330
994
  type: "string",
331
- description: "Required res:// resource path, including ::subresource id when needed.",
995
+ description: "Required res:// path for the saved scene to load.",
332
996
  },
333
- propertyQuery: {
997
+ animationTreePath: {
334
998
  type: "string",
335
- description: "Optional substring filter for returned property metadata.",
999
+ description: "Required node path to the AnimationTree.",
336
1000
  },
337
- propertyLimit: {
338
- type: "number",
339
- description: "Optional positive limit for returned property metadata.",
1001
+ stateName: {
1002
+ type: "string",
1003
+ description: "Required state-machine node name.",
340
1004
  },
341
1005
  mode: {
342
1006
  type: "string",
@@ -350,30 +1014,35 @@ const TOOL_MANIFEST = [
350
1014
  type: "string",
351
1015
  description: "Optional Godot editor executable override for this invocation.",
352
1016
  },
353
- }, ["resourcePath"]),
1017
+ }, ["scenePath", "animationTreePath", "stateName"]),
354
1018
  outputSchema: outputEnvelopeSchema,
355
1019
  outputContract: "GdhEditorOperationResult",
356
1020
  },
357
1021
  {
358
- name: "editor.class.search",
359
- summary: "Search Godot ClassDB and registered script classes with bounded query controls.",
1022
+ name: "editor.animation.state_machine.transition.upsert",
1023
+ summary: "Create or replace one transition in an AnimationTree state-machine graph without automating the editor UI.",
360
1024
  targetPathPolicy: "optional",
361
- inputSchema: defineObjectSchema("Editor class search request.", {
362
- query: {
1025
+ inputSchema: defineObjectSchema("Editor animation state-machine transition upsert request.", {
1026
+ scenePath: {
363
1027
  type: "string",
364
- description: "Optional substring query for class names.",
1028
+ description: "Required res:// path for the saved scene to load.",
365
1029
  },
366
- baseClass: {
1030
+ animationTreePath: {
367
1031
  type: "string",
368
- description: "Optional base class filter.",
1032
+ description: "Required node path to the AnimationTree.",
369
1033
  },
370
- instantiableOnly: {
371
- type: "boolean",
372
- description: "When false, include non-instantiable classes. Defaults to true.",
1034
+ fromState: {
1035
+ type: "string",
1036
+ description: "Required source state name.",
373
1037
  },
374
- limit: {
375
- type: "number",
376
- description: "Optional positive result limit.",
1038
+ toState: {
1039
+ type: "string",
1040
+ description: "Required target state name.",
1041
+ },
1042
+ properties: {
1043
+ type: "object",
1044
+ description: "Optional properties to set on the transition resource.",
1045
+ additionalProperties: true,
377
1046
  },
378
1047
  mode: {
379
1048
  type: "string",
@@ -387,30 +1056,30 @@ const TOOL_MANIFEST = [
387
1056
  type: "string",
388
1057
  description: "Optional Godot editor executable override for this invocation.",
389
1058
  },
390
- }),
1059
+ }, ["scenePath", "animationTreePath", "fromState", "toState"]),
391
1060
  outputSchema: outputEnvelopeSchema,
392
1061
  outputContract: "GdhEditorOperationResult",
393
1062
  },
394
1063
  {
395
- name: "editor.class.info",
396
- summary: "Return bounded property metadata for one Godot or registered script class.",
1064
+ name: "editor.animation.state_machine.transition.delete",
1065
+ summary: "Delete one transition from an AnimationTree state-machine graph.",
397
1066
  targetPathPolicy: "optional",
398
- inputSchema: defineObjectSchema("Editor class info request.", {
399
- className: {
1067
+ inputSchema: defineObjectSchema("Editor animation state-machine transition delete request.", {
1068
+ scenePath: {
400
1069
  type: "string",
401
- description: "Required Godot or registered script class name.",
1070
+ description: "Required res:// path for the saved scene to load.",
402
1071
  },
403
- includeInherited: {
404
- type: "boolean",
405
- description: "When true, include inherited properties. Defaults to true.",
1072
+ animationTreePath: {
1073
+ type: "string",
1074
+ description: "Required node path to the AnimationTree.",
406
1075
  },
407
- propertyQuery: {
1076
+ fromState: {
408
1077
  type: "string",
409
- description: "Optional substring filter for returned property metadata.",
1078
+ description: "Required source state name.",
410
1079
  },
411
- propertyLimit: {
412
- type: "number",
413
- description: "Optional positive property metadata limit.",
1080
+ toState: {
1081
+ type: "string",
1082
+ description: "Required target state name.",
414
1083
  },
415
1084
  mode: {
416
1085
  type: "string",
@@ -424,13 +1093,13 @@ const TOOL_MANIFEST = [
424
1093
  type: "string",
425
1094
  description: "Optional Godot editor executable override for this invocation.",
426
1095
  },
427
- }, ["className"]),
1096
+ }, ["scenePath", "animationTreePath", "fromState", "toState"]),
428
1097
  outputSchema: outputEnvelopeSchema,
429
1098
  outputContract: "GdhEditorOperationResult",
430
1099
  },
431
1100
  {
432
1101
  name: "editor.operation.run",
433
- summary: "Advanced escape hatch for one targeted Godot-native editor operation. Prefer focused editor.* tools for normal reads. Payloads dispatch on operation.kind, not type.",
1102
+ summary: "Advanced escape hatch for one targeted Godot-native editor operation. Prefer focused editor.* tools for normal reads and common writes. Payloads dispatch on operation.kind, not type.",
434
1103
  targetPathPolicy: "optional",
435
1104
  inputSchema: defineObjectSchema("Editor Bridge operation request.", {
436
1105
  operation: {
@@ -651,6 +1320,18 @@ async function invokeMcpToolWithContext(request, context) {
651
1320
  return succeeded(request.toolName, targetPath, await invokeAuthoringDiagnosticsDoctorTool(targetPath));
652
1321
  case "authoring.warmup":
653
1322
  return succeeded(request.toolName, targetPath, await invokeAuthoringWarmupTool(targetPath, request.input));
1323
+ case "authoring.symbols.status":
1324
+ return succeeded(request.toolName, targetPath, await invokeAuthoringSymbolStatusTool(targetPath));
1325
+ case "authoring.symbols.document":
1326
+ return succeeded(request.toolName, targetPath, await invokeAuthoringDocumentSymbolsTool(targetPath, request.input));
1327
+ case "authoring.symbols.definition":
1328
+ return succeeded(request.toolName, targetPath, await invokeAuthoringPositionSymbolTool("definition", targetPath, request.input));
1329
+ case "authoring.symbols.declaration":
1330
+ return succeeded(request.toolName, targetPath, await invokeAuthoringPositionSymbolTool("declaration", targetPath, request.input));
1331
+ case "authoring.symbols.references":
1332
+ return succeeded(request.toolName, targetPath, await invokeAuthoringReferencesTool(targetPath, request.input));
1333
+ case "authoring.symbols.hover":
1334
+ return succeeded(request.toolName, targetPath, await invokeAuthoringPositionSymbolTool("hover", targetPath, request.input));
654
1335
  case "editor.session.status":
655
1336
  return succeeded(request.toolName, targetPath, await invokeEditorSessionStatusTool(targetPath, request.input));
656
1337
  case "editor.state":
@@ -697,6 +1378,129 @@ async function invokeMcpToolWithContext(request, context) {
697
1378
  propertyQuery: readOptionalString(request.input["propertyQuery"], "propertyQuery"),
698
1379
  propertyLimit: readOptionalPositiveInteger(request.input["propertyLimit"], "propertyLimit"),
699
1380
  })));
1381
+ case "editor.animation.player.inspect":
1382
+ return succeeded(request.toolName, targetPath, await invokeFocusedEditorOperationTool(targetPath, request.input, createEditorOperation("animation.player.inspect", {
1383
+ scenePath: requireString(request.input["scenePath"], "scenePath"),
1384
+ animationPlayerPath: requireString(request.input["animationPlayerPath"], "animationPlayerPath"),
1385
+ })));
1386
+ case "editor.animation.clip.read":
1387
+ return succeeded(request.toolName, targetPath, await invokeFocusedEditorOperationTool(targetPath, request.input, createEditorOperation("animation.clip.read", {
1388
+ scenePath: requireString(request.input["scenePath"], "scenePath"),
1389
+ animationPlayerPath: requireString(request.input["animationPlayerPath"], "animationPlayerPath"),
1390
+ libraryName: readOptionalString(request.input["libraryName"], "libraryName"),
1391
+ animationName: requireString(request.input["animationName"], "animationName"),
1392
+ includeKeys: readOptionalBoolean(request.input["includeKeys"], "includeKeys"),
1393
+ keyLimit: readOptionalPositiveInteger(request.input["keyLimit"], "keyLimit"),
1394
+ })));
1395
+ case "editor.animation.clip.create":
1396
+ return succeeded(request.toolName, targetPath, await invokeFocusedEditorOperationTool(targetPath, request.input, createEditorOperation("animation.clip.create", {
1397
+ scenePath: requireString(request.input["scenePath"], "scenePath"),
1398
+ animationPlayerPath: requireString(request.input["animationPlayerPath"], "animationPlayerPath"),
1399
+ libraryName: readOptionalString(request.input["libraryName"], "libraryName"),
1400
+ animationName: requireString(request.input["animationName"], "animationName"),
1401
+ length: readOptionalNumber(request.input["length"], "length"),
1402
+ step: readOptionalNumber(request.input["step"], "step"),
1403
+ loopMode: readOptionalStringOrNumber(request.input["loopMode"], "loopMode"),
1404
+ overwrite: readOptionalBoolean(request.input["overwrite"], "overwrite"),
1405
+ })));
1406
+ case "editor.animation.clip.delete":
1407
+ return succeeded(request.toolName, targetPath, await invokeFocusedEditorOperationTool(targetPath, request.input, createEditorOperation("animation.clip.delete", {
1408
+ scenePath: requireString(request.input["scenePath"], "scenePath"),
1409
+ animationPlayerPath: requireString(request.input["animationPlayerPath"], "animationPlayerPath"),
1410
+ libraryName: readOptionalString(request.input["libraryName"], "libraryName"),
1411
+ animationName: requireString(request.input["animationName"], "animationName"),
1412
+ })));
1413
+ case "editor.animation.track.add":
1414
+ return succeeded(request.toolName, targetPath, await invokeFocusedEditorOperationTool(targetPath, request.input, createEditorOperation("animation.track.add", {
1415
+ scenePath: requireString(request.input["scenePath"], "scenePath"),
1416
+ animationPlayerPath: requireString(request.input["animationPlayerPath"], "animationPlayerPath"),
1417
+ libraryName: readOptionalString(request.input["libraryName"], "libraryName"),
1418
+ animationName: requireString(request.input["animationName"], "animationName"),
1419
+ trackType: readOptionalStringOrNumber(request.input["trackType"], "trackType") ?? "value",
1420
+ trackPath: requireString(request.input["trackPath"], "trackPath"),
1421
+ atPosition: readOptionalNumber(request.input["atPosition"], "atPosition"),
1422
+ interpolation: readOptionalStringOrNumber(request.input["interpolation"], "interpolation"),
1423
+ updateMode: readOptionalStringOrNumber(request.input["updateMode"], "updateMode"),
1424
+ })));
1425
+ case "editor.animation.track.remove":
1426
+ return succeeded(request.toolName, targetPath, await invokeFocusedEditorOperationTool(targetPath, request.input, createEditorOperation("animation.track.remove", {
1427
+ scenePath: requireString(request.input["scenePath"], "scenePath"),
1428
+ animationPlayerPath: requireString(request.input["animationPlayerPath"], "animationPlayerPath"),
1429
+ libraryName: readOptionalString(request.input["libraryName"], "libraryName"),
1430
+ animationName: requireString(request.input["animationName"], "animationName"),
1431
+ trackIndex: requireNumber(request.input["trackIndex"], "trackIndex"),
1432
+ })));
1433
+ case "editor.animation.keyframe.upsert":
1434
+ return succeeded(request.toolName, targetPath, await invokeFocusedEditorOperationTool(targetPath, request.input, createEditorOperation("animation.keyframe.upsert", {
1435
+ scenePath: requireString(request.input["scenePath"], "scenePath"),
1436
+ animationPlayerPath: requireString(request.input["animationPlayerPath"], "animationPlayerPath"),
1437
+ libraryName: readOptionalString(request.input["libraryName"], "libraryName"),
1438
+ animationName: requireString(request.input["animationName"], "animationName"),
1439
+ trackIndex: requireNumber(request.input["trackIndex"], "trackIndex"),
1440
+ time: requireNumber(request.input["time"], "time"),
1441
+ value: requireJsonValue(request.input["value"], "value"),
1442
+ transition: readOptionalNumber(request.input["transition"], "transition"),
1443
+ })));
1444
+ case "editor.animation.keyframe.delete":
1445
+ return succeeded(request.toolName, targetPath, await invokeFocusedEditorOperationTool(targetPath, request.input, createEditorOperation("animation.keyframe.delete", {
1446
+ scenePath: requireString(request.input["scenePath"], "scenePath"),
1447
+ animationPlayerPath: requireString(request.input["animationPlayerPath"], "animationPlayerPath"),
1448
+ libraryName: readOptionalString(request.input["libraryName"], "libraryName"),
1449
+ animationName: requireString(request.input["animationName"], "animationName"),
1450
+ trackIndex: requireNumber(request.input["trackIndex"], "trackIndex"),
1451
+ keyIndex: readOptionalNumber(request.input["keyIndex"], "keyIndex"),
1452
+ time: readOptionalNumber(request.input["time"], "time"),
1453
+ })));
1454
+ case "editor.animation.state_machine.create":
1455
+ return succeeded(request.toolName, targetPath, await invokeFocusedEditorOperationTool(targetPath, request.input, createEditorOperation("animation.state_machine.create", {
1456
+ scenePath: requireString(request.input["scenePath"], "scenePath"),
1457
+ animationTreePath: requireString(request.input["animationTreePath"], "animationTreePath"),
1458
+ overwrite: readOptionalBoolean(request.input["overwrite"], "overwrite"),
1459
+ properties: request.input["properties"] === undefined
1460
+ ? undefined
1461
+ : requireObject(request.input["properties"], "properties"),
1462
+ })));
1463
+ case "editor.animation.state_machine.read":
1464
+ return succeeded(request.toolName, targetPath, await invokeFocusedEditorOperationTool(targetPath, request.input, createEditorOperation("animation.state_machine.read", {
1465
+ scenePath: requireString(request.input["scenePath"], "scenePath"),
1466
+ animationTreePath: requireString(request.input["animationTreePath"], "animationTreePath"),
1467
+ })));
1468
+ case "editor.animation.state_machine.node.upsert":
1469
+ return succeeded(request.toolName, targetPath, await invokeFocusedEditorOperationTool(targetPath, request.input, createEditorOperation("animation.state_machine.node.upsert", {
1470
+ scenePath: requireString(request.input["scenePath"], "scenePath"),
1471
+ animationTreePath: requireString(request.input["animationTreePath"], "animationTreePath"),
1472
+ stateName: requireString(request.input["stateName"], "stateName"),
1473
+ nodeType: readOptionalString(request.input["nodeType"], "nodeType"),
1474
+ position: request.input["position"] === undefined
1475
+ ? undefined
1476
+ : requireJsonValue(request.input["position"], "position"),
1477
+ properties: request.input["properties"] === undefined
1478
+ ? undefined
1479
+ : requireObject(request.input["properties"], "properties"),
1480
+ })));
1481
+ case "editor.animation.state_machine.node.delete":
1482
+ return succeeded(request.toolName, targetPath, await invokeFocusedEditorOperationTool(targetPath, request.input, createEditorOperation("animation.state_machine.node.delete", {
1483
+ scenePath: requireString(request.input["scenePath"], "scenePath"),
1484
+ animationTreePath: requireString(request.input["animationTreePath"], "animationTreePath"),
1485
+ stateName: requireString(request.input["stateName"], "stateName"),
1486
+ })));
1487
+ case "editor.animation.state_machine.transition.upsert":
1488
+ return succeeded(request.toolName, targetPath, await invokeFocusedEditorOperationTool(targetPath, request.input, createEditorOperation("animation.state_machine.transition.upsert", {
1489
+ scenePath: requireString(request.input["scenePath"], "scenePath"),
1490
+ animationTreePath: requireString(request.input["animationTreePath"], "animationTreePath"),
1491
+ fromState: requireString(request.input["fromState"], "fromState"),
1492
+ toState: requireString(request.input["toState"], "toState"),
1493
+ properties: request.input["properties"] === undefined
1494
+ ? undefined
1495
+ : requireObject(request.input["properties"], "properties"),
1496
+ })));
1497
+ case "editor.animation.state_machine.transition.delete":
1498
+ return succeeded(request.toolName, targetPath, await invokeFocusedEditorOperationTool(targetPath, request.input, createEditorOperation("animation.state_machine.transition.delete", {
1499
+ scenePath: requireString(request.input["scenePath"], "scenePath"),
1500
+ animationTreePath: requireString(request.input["animationTreePath"], "animationTreePath"),
1501
+ fromState: requireString(request.input["fromState"], "fromState"),
1502
+ toState: requireString(request.input["toState"], "toState"),
1503
+ })));
700
1504
  case "editor.operation.run":
701
1505
  return succeeded(request.toolName, targetPath, await invokeEditorOperationRunTool(targetPath, request.input));
702
1506
  case "bridge.entry.list":
@@ -920,6 +1724,53 @@ async function invokeAuthoringWarmupTool(targetPath, _input) {
920
1724
  });
921
1725
  return result;
922
1726
  }
1727
+ async function invokeAuthoringSymbolStatusTool(targetPath) {
1728
+ const context = await buildAuthoringContext(targetPath);
1729
+ return getAuthoringSymbolStatus({
1730
+ targetPath: context.targetPath,
1731
+ status: context.status,
1732
+ projectConfig: context.projectConfig,
1733
+ });
1734
+ }
1735
+ async function invokeAuthoringDocumentSymbolsTool(targetPath, input) {
1736
+ const context = await buildAuthoringContext(targetPath);
1737
+ return getAuthoringDocumentSymbols({
1738
+ targetPath: context.targetPath,
1739
+ status: context.status,
1740
+ projectConfig: context.projectConfig,
1741
+ filePath: requireString(input["filePath"], "filePath"),
1742
+ });
1743
+ }
1744
+ async function invokeAuthoringPositionSymbolTool(operation, targetPath, input) {
1745
+ const context = await buildAuthoringContext(targetPath);
1746
+ const symbolInput = {
1747
+ targetPath: context.targetPath,
1748
+ status: context.status,
1749
+ projectConfig: context.projectConfig,
1750
+ filePath: requireString(input["filePath"], "filePath"),
1751
+ line: requirePositiveInteger(input["line"], "line"),
1752
+ column: requirePositiveInteger(input["column"], "column"),
1753
+ };
1754
+ if (operation === "definition") {
1755
+ return getAuthoringSymbolDefinition(symbolInput);
1756
+ }
1757
+ if (operation === "declaration") {
1758
+ return getAuthoringSymbolDeclaration(symbolInput);
1759
+ }
1760
+ return getAuthoringSymbolHover(symbolInput);
1761
+ }
1762
+ async function invokeAuthoringReferencesTool(targetPath, input) {
1763
+ const context = await buildAuthoringContext(targetPath);
1764
+ return getAuthoringSymbolReferences({
1765
+ targetPath: context.targetPath,
1766
+ status: context.status,
1767
+ projectConfig: context.projectConfig,
1768
+ filePath: requireString(input["filePath"], "filePath"),
1769
+ line: requirePositiveInteger(input["line"], "line"),
1770
+ column: requirePositiveInteger(input["column"], "column"),
1771
+ includeDeclaration: readOptionalBoolean(input["includeDeclaration"], "includeDeclaration") ?? true,
1772
+ });
1773
+ }
923
1774
  async function invokeRunConfigCheckTool(targetPath, input) {
924
1775
  const projectConfig = await readProjectConfig(targetPath);
925
1776
  const runtimeInput = normalizeRuntimeActionInput(input, {
@@ -1083,6 +1934,15 @@ function readOptionalString(value, fieldName) {
1083
1934
  }
1084
1935
  return value;
1085
1936
  }
1937
+ function readOptionalStringOrNumber(value, fieldName) {
1938
+ if (value === undefined || value === null) {
1939
+ return undefined;
1940
+ }
1941
+ if (typeof value !== "string" && typeof value !== "number") {
1942
+ throw new Error(`MCP input field "${fieldName}" must be a string or number.`);
1943
+ }
1944
+ return value;
1945
+ }
1086
1946
  function readOptionalEditorSessionMode(value, fieldName) {
1087
1947
  const mode = readOptionalString(value, fieldName);
1088
1948
  if (mode === null || mode === "auto")
@@ -1102,6 +1962,28 @@ function requireString(value, fieldName) {
1102
1962
  }
1103
1963
  return stringValue;
1104
1964
  }
1965
+ function readOptionalNumber(value, fieldName) {
1966
+ if (value === undefined) {
1967
+ return undefined;
1968
+ }
1969
+ if (typeof value !== "number") {
1970
+ throw new Error(`MCP input field "${fieldName}" must be a number.`);
1971
+ }
1972
+ return value;
1973
+ }
1974
+ function requireNumber(value, fieldName) {
1975
+ const numberValue = readOptionalNumber(value, fieldName);
1976
+ if (numberValue === undefined) {
1977
+ throw new Error(`MCP input field "${fieldName}" is required.`);
1978
+ }
1979
+ return numberValue;
1980
+ }
1981
+ function requireJsonValue(value, fieldName) {
1982
+ if (value === undefined) {
1983
+ throw new Error(`MCP input field "${fieldName}" is required.`);
1984
+ }
1985
+ return value;
1986
+ }
1105
1987
  function requireObject(value, fieldName) {
1106
1988
  if (value === undefined) {
1107
1989
  throw new Error(`MCP input field "${fieldName}" is required.`);
@@ -1120,6 +2002,13 @@ function readOptionalPositiveInteger(value, fieldName) {
1120
2002
  }
1121
2003
  return value;
1122
2004
  }
2005
+ function requirePositiveInteger(value, fieldName) {
2006
+ const numberValue = readOptionalPositiveInteger(value, fieldName);
2007
+ if (numberValue === undefined) {
2008
+ throw new Error(`MCP input field "${fieldName}" is required.`);
2009
+ }
2010
+ return numberValue;
2011
+ }
1123
2012
  function readOptionalStringArray(value, fieldName) {
1124
2013
  if (value === undefined) {
1125
2014
  return [];