Replace all 32 unchecked type assertions (result.(Type)) with safe ok-pattern checks that return descriptive errors on type mismatch. Complete stub handlers in tools_window.go (restore, title, visibility, fullscreen) and tools_layout.go (save, restore, list, delete, get, tile, snap) using proper IPC message types instead of workarounds. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
158 lines
5.2 KiB
Go
158 lines
5.2 KiB
Go
// pkg/mcp/tools_dialog.go
|
|
package mcp
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"forge.lthn.ai/core/gui/pkg/dialog"
|
|
"github.com/modelcontextprotocol/go-sdk/mcp"
|
|
)
|
|
|
|
// --- dialog_open_file ---
|
|
|
|
type DialogOpenFileInput struct {
|
|
Title string `json:"title,omitempty"`
|
|
Directory string `json:"directory,omitempty"`
|
|
Filters []dialog.FileFilter `json:"filters,omitempty"`
|
|
AllowMultiple bool `json:"allowMultiple,omitempty"`
|
|
}
|
|
type DialogOpenFileOutput struct {
|
|
Paths []string `json:"paths"`
|
|
}
|
|
|
|
func (s *Subsystem) dialogOpenFile(_ context.Context, _ *mcp.CallToolRequest, input DialogOpenFileInput) (*mcp.CallToolResult, DialogOpenFileOutput, error) {
|
|
result, _, err := s.core.PERFORM(dialog.TaskOpenFile{Opts: dialog.OpenFileOptions{
|
|
Title: input.Title,
|
|
Directory: input.Directory,
|
|
Filters: input.Filters,
|
|
AllowMultiple: input.AllowMultiple,
|
|
}})
|
|
if err != nil {
|
|
return nil, DialogOpenFileOutput{}, err
|
|
}
|
|
paths, ok := result.([]string)
|
|
if !ok {
|
|
return nil, DialogOpenFileOutput{}, fmt.Errorf("unexpected result type from open file dialog")
|
|
}
|
|
return nil, DialogOpenFileOutput{Paths: paths}, nil
|
|
}
|
|
|
|
// --- dialog_save_file ---
|
|
|
|
type DialogSaveFileInput struct {
|
|
Title string `json:"title,omitempty"`
|
|
Directory string `json:"directory,omitempty"`
|
|
Filename string `json:"filename,omitempty"`
|
|
Filters []dialog.FileFilter `json:"filters,omitempty"`
|
|
}
|
|
type DialogSaveFileOutput struct {
|
|
Path string `json:"path"`
|
|
}
|
|
|
|
func (s *Subsystem) dialogSaveFile(_ context.Context, _ *mcp.CallToolRequest, input DialogSaveFileInput) (*mcp.CallToolResult, DialogSaveFileOutput, error) {
|
|
result, _, err := s.core.PERFORM(dialog.TaskSaveFile{Opts: dialog.SaveFileOptions{
|
|
Title: input.Title,
|
|
Directory: input.Directory,
|
|
Filename: input.Filename,
|
|
Filters: input.Filters,
|
|
}})
|
|
if err != nil {
|
|
return nil, DialogSaveFileOutput{}, err
|
|
}
|
|
path, ok := result.(string)
|
|
if !ok {
|
|
return nil, DialogSaveFileOutput{}, fmt.Errorf("unexpected result type from save file dialog")
|
|
}
|
|
return nil, DialogSaveFileOutput{Path: path}, nil
|
|
}
|
|
|
|
// --- dialog_open_directory ---
|
|
|
|
type DialogOpenDirectoryInput struct {
|
|
Title string `json:"title,omitempty"`
|
|
Directory string `json:"directory,omitempty"`
|
|
}
|
|
type DialogOpenDirectoryOutput struct {
|
|
Path string `json:"path"`
|
|
}
|
|
|
|
func (s *Subsystem) dialogOpenDirectory(_ context.Context, _ *mcp.CallToolRequest, input DialogOpenDirectoryInput) (*mcp.CallToolResult, DialogOpenDirectoryOutput, error) {
|
|
result, _, err := s.core.PERFORM(dialog.TaskOpenDirectory{Opts: dialog.OpenDirectoryOptions{
|
|
Title: input.Title,
|
|
Directory: input.Directory,
|
|
}})
|
|
if err != nil {
|
|
return nil, DialogOpenDirectoryOutput{}, err
|
|
}
|
|
path, ok := result.(string)
|
|
if !ok {
|
|
return nil, DialogOpenDirectoryOutput{}, fmt.Errorf("unexpected result type from open directory dialog")
|
|
}
|
|
return nil, DialogOpenDirectoryOutput{Path: path}, nil
|
|
}
|
|
|
|
// --- dialog_confirm ---
|
|
|
|
type DialogConfirmInput struct {
|
|
Title string `json:"title"`
|
|
Message string `json:"message"`
|
|
Buttons []string `json:"buttons,omitempty"`
|
|
}
|
|
type DialogConfirmOutput struct {
|
|
Button string `json:"button"`
|
|
}
|
|
|
|
func (s *Subsystem) dialogConfirm(_ context.Context, _ *mcp.CallToolRequest, input DialogConfirmInput) (*mcp.CallToolResult, DialogConfirmOutput, error) {
|
|
result, _, err := s.core.PERFORM(dialog.TaskMessageDialog{Opts: dialog.MessageDialogOptions{
|
|
Type: dialog.DialogQuestion,
|
|
Title: input.Title,
|
|
Message: input.Message,
|
|
Buttons: input.Buttons,
|
|
}})
|
|
if err != nil {
|
|
return nil, DialogConfirmOutput{}, err
|
|
}
|
|
button, ok := result.(string)
|
|
if !ok {
|
|
return nil, DialogConfirmOutput{}, fmt.Errorf("unexpected result type from confirm dialog")
|
|
}
|
|
return nil, DialogConfirmOutput{Button: button}, nil
|
|
}
|
|
|
|
// --- dialog_prompt ---
|
|
|
|
type DialogPromptInput struct {
|
|
Title string `json:"title"`
|
|
Message string `json:"message"`
|
|
}
|
|
type DialogPromptOutput struct {
|
|
Button string `json:"button"`
|
|
}
|
|
|
|
func (s *Subsystem) dialogPrompt(_ context.Context, _ *mcp.CallToolRequest, input DialogPromptInput) (*mcp.CallToolResult, DialogPromptOutput, error) {
|
|
result, _, err := s.core.PERFORM(dialog.TaskMessageDialog{Opts: dialog.MessageDialogOptions{
|
|
Type: dialog.DialogInfo,
|
|
Title: input.Title,
|
|
Message: input.Message,
|
|
Buttons: []string{"OK", "Cancel"},
|
|
}})
|
|
if err != nil {
|
|
return nil, DialogPromptOutput{}, err
|
|
}
|
|
button, ok := result.(string)
|
|
if !ok {
|
|
return nil, DialogPromptOutput{}, fmt.Errorf("unexpected result type from prompt dialog")
|
|
}
|
|
return nil, DialogPromptOutput{Button: button}, nil
|
|
}
|
|
|
|
// --- Registration ---
|
|
|
|
func (s *Subsystem) registerDialogTools(server *mcp.Server) {
|
|
mcp.AddTool(server, &mcp.Tool{Name: "dialog_open_file", Description: "Show an open file dialog"}, s.dialogOpenFile)
|
|
mcp.AddTool(server, &mcp.Tool{Name: "dialog_save_file", Description: "Show a save file dialog"}, s.dialogSaveFile)
|
|
mcp.AddTool(server, &mcp.Tool{Name: "dialog_open_directory", Description: "Show a directory picker dialog"}, s.dialogOpenDirectory)
|
|
mcp.AddTool(server, &mcp.Tool{Name: "dialog_confirm", Description: "Show a confirmation dialog"}, s.dialogConfirm)
|
|
mcp.AddTool(server, &mcp.Tool{Name: "dialog_prompt", Description: "Show a prompt dialog"}, s.dialogPrompt)
|
|
}
|