Randoloot/addons/godot_mcp_toolkit/ui/mcp_json_write_flow.gd
2026-10-09 12:49:07 +02:00

55 lines
2.8 KiB
GDScript

@tool
extends RefCounted
## Shared confirm-then-write flow for the project-root .mcp.json.
##
## The one place the "write .mcp.json" user action lives: checks whether the
## write would overwrite an existing file, shows the overwrite confirmation when
## it would, delegates the file I/O to [code]MCPJsonSync.write_from_template[/code]
## (which stays pure I/O), and reports the outcome through the caller's result
## callback. Built by the composer and injected into every surface that offers
## the write, so no surface owns the flow and none reaches through the dock for
## it — the dock is a UI surface, not a service locator.
##
## Editor-only: the confirmation dialog parents to the editor base control, so
## this script must never enter the runtime autoload's preload closure.
const MCPJsonSync := preload("res://addons/godot_mcp_toolkit/ui/mcp_json_sync.gd")
const DockConfirm := preload("res://addons/godot_mcp_toolkit/ui/dock/dock_confirm.gd")
## Write .mcp.json from the bundled template, confirming first when a file
## already exists (skipped when [param force_overwrite]).
##
## Declining the confirmation opens the existing file in the system editor
## instead of writing — the "don't overwrite, let me look at it" recovery — and
## reports nothing. After a write attempt [param on_result] receives one
## (ok, message, severity, tooltip) report; severity is the editor-toast scale
## (0 info / 1 warning / 2 error). Pass an empty Callable to fire and forget.
func write(force_overwrite: bool = false, on_result: Callable = Callable()) -> void:
# MCPJsonSync calls its on_result unconditionally, so a fire-and-forget
# (empty) caller sink is wrapped in a validity guard rather than passed through.
var report := func(ok: bool, message: String, severity: int, tooltip: String) -> void:
if on_result.is_valid():
on_result.call(ok, message, severity, tooltip)
if not force_overwrite and MCPJsonSync.needs_overwrite_confirm():
var dest := MCPJsonSync.get_mcp_json_path()
# "Cancel" is repurposed as "Open .mcp.json": declining the overwrite opens
# the file so the user can edit it (fix a malformed file, or inspect a valid
# one) rather than lose it. Esc/✕ route through the same path — the intended
# "don't overwrite, let me look at it" recovery. The lambdas capture only
# locals (report, dest) — a bare member reference inside a lambda is not
# use-self-marked on Godot 4.2 and would look up on a Nil self.
DockConfirm.confirm(
".mcp.json already exists",
"Overwrite .mcp.json with a clean template?\n\n" + dest
+ "\n\nThis replaces your current content — choose \"Open .mcp.json\" instead to edit the file yourself.",
"Overwrite",
func() -> void: MCPJsonSync.write_from_template(true, report),
"Open .mcp.json",
func() -> void: OS.shell_open(dest),
)
return
MCPJsonSync.write_from_template(force_overwrite, report)