refactor: AX compliance sweep — replace banned stdlib imports with core primitives
Replaced fmt, strings, sort, os, io, sync, encoding/json, path/filepath, errors, log, reflect with core.Sprintf, core.E, core.Contains, core.Trim, core.Split, core.Join, core.JoinPath, slices.Sort, c.Fs(), c.Lock(), core.JSONMarshal, core.ReadAll and other CoreGO v0.8.0 primitives. Framework boundary exceptions preserved where stdlib types are required by external interfaces (Gin, net/http, CGo, Wails, bubbletea). Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
873eafe7b6
commit
62ec735c10
36 changed files with 324 additions and 312 deletions
2
go.sum
2
go.sum
|
|
@ -1,4 +1,6 @@
|
|||
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||
dappco.re/go/core v0.3.3 h1:TaE7/SObQ3YEZj4ov1BAXWwLJEIttkrxzncVGewR3Bs=
|
||||
dappco.re/go/core v0.3.3/go.mod h1:Cp4ac25pghvO2iqOu59t1GyngTKVOzKB5/VPdhRi9CQ=
|
||||
forge.lthn.ai/Snider/Borg v0.3.1/go.mod h1:Z7DJD0yHXsxSyM7Mjl6/g4gH1NBsIz44Bf5AFlV76Wg=
|
||||
forge.lthn.ai/core/config v0.1.8 h1:xP2hys7T94QGVF/OTh84/Zr5Dm/dL/0vzjht8zi+LOg=
|
||||
forge.lthn.ai/core/config v0.1.8/go.mod h1:8epZrkwoCt+5ayrqdinOUU/+w6UoxOyv9ZrdgVOgYfQ=
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// pkg/contextmenu/messages.go
|
||||
package contextmenu
|
||||
|
||||
import "errors"
|
||||
import corego "dappco.re/go/core"
|
||||
|
||||
// ErrMenuNotFound is returned when attempting to remove or get a menu
|
||||
// that does not exist in the registry.
|
||||
var ErrMenuNotFound = errors.New("contextmenu: menu not found")
|
||||
var ErrMenuNotFound = corego.NewError("contextmenu: menu not found")
|
||||
|
||||
// --- Queries ---
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package contextmenu
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
corego "dappco.re/go/core"
|
||||
"forge.lthn.ai/core/go/pkg/core"
|
||||
)
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ func (s *Service) taskAdd(t TaskAdd) error {
|
|||
})
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("contextmenu: platform add failed: %w", err)
|
||||
return corego.Wrap(err, "contextmenu.add", "platform add failed")
|
||||
}
|
||||
|
||||
s.menus[t.Name] = t.Menu
|
||||
|
|
@ -106,7 +106,7 @@ func (s *Service) taskRemove(t TaskRemove) error {
|
|||
|
||||
err := s.platform.Remove(t.Name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("contextmenu: platform remove failed: %w", err)
|
||||
return corego.Wrap(err, "contextmenu.remove", "platform remove failed")
|
||||
}
|
||||
|
||||
delete(s.menus, t.Name)
|
||||
|
|
|
|||
|
|
@ -4,29 +4,27 @@ package display
|
|||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"encoding/json"
|
||||
corego "dappco.re/go/core"
|
||||
"forge.lthn.ai/core/config"
|
||||
"forge.lthn.ai/core/go/pkg/core"
|
||||
|
||||
"forge.lthn.ai/core/gui/pkg/browser"
|
||||
"forge.lthn.ai/core/gui/pkg/clipboard"
|
||||
"forge.lthn.ai/core/gui/pkg/contextmenu"
|
||||
"forge.lthn.ai/core/gui/pkg/dialog"
|
||||
"forge.lthn.ai/core/gui/pkg/dock"
|
||||
"forge.lthn.ai/core/gui/pkg/environment"
|
||||
"forge.lthn.ai/core/gui/pkg/keybinding"
|
||||
"forge.lthn.ai/core/gui/pkg/lifecycle"
|
||||
"forge.lthn.ai/core/gui/pkg/menu"
|
||||
"forge.lthn.ai/core/gui/pkg/notification"
|
||||
"forge.lthn.ai/core/gui/pkg/screen"
|
||||
"forge.lthn.ai/core/gui/pkg/systray"
|
||||
"forge.lthn.ai/core/gui/pkg/webview"
|
||||
"forge.lthn.ai/core/gui/pkg/window"
|
||||
"dappco.re/go/core/gui/pkg/browser"
|
||||
"dappco.re/go/core/gui/pkg/clipboard"
|
||||
"dappco.re/go/core/gui/pkg/contextmenu"
|
||||
"dappco.re/go/core/gui/pkg/dialog"
|
||||
"dappco.re/go/core/gui/pkg/dock"
|
||||
"dappco.re/go/core/gui/pkg/environment"
|
||||
"dappco.re/go/core/gui/pkg/keybinding"
|
||||
"dappco.re/go/core/gui/pkg/lifecycle"
|
||||
"dappco.re/go/core/gui/pkg/menu"
|
||||
"dappco.re/go/core/gui/pkg/notification"
|
||||
"dappco.re/go/core/gui/pkg/screen"
|
||||
"dappco.re/go/core/gui/pkg/systray"
|
||||
"dappco.re/go/core/gui/pkg/webview"
|
||||
"dappco.re/go/core/gui/pkg/window"
|
||||
"github.com/wailsapp/wails/v3/pkg/application"
|
||||
)
|
||||
|
||||
|
|
@ -259,7 +257,7 @@ type WSMessage struct {
|
|||
func wsRequire(data map[string]any, key string) (string, error) {
|
||||
v, _ := data[key].(string)
|
||||
if v == "" {
|
||||
return "", fmt.Errorf("ws: missing required field %q", key)
|
||||
return "", corego.NewError(corego.Sprintf("ws: missing required field %q", key))
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
|
@ -302,10 +300,11 @@ func (s *Service) handleWSMessage(msg WSMessage) (any, bool, error) {
|
|||
result, handled, err = s.GetFocusedWindow(), true, nil
|
||||
case "window:create":
|
||||
var opts CreateWindowOptions
|
||||
encoded, _ := json.Marshal(msg.Data)
|
||||
if err := json.Unmarshal(encoded, &opts); err != nil {
|
||||
return nil, false, fmt.Errorf("ws: invalid window create options: %w", err)
|
||||
encodedR := corego.JSONMarshal(msg.Data)
|
||||
if encodedR.OK {
|
||||
_ = corego.JSONUnmarshal(encodedR.Value.([]byte), &opts)
|
||||
}
|
||||
return nil, false, corego.Wrap(err, "display.ws", "ws: invalid window create options")
|
||||
info, createErr := s.CreateWindow(opts)
|
||||
if createErr != nil {
|
||||
return nil, false, createErr
|
||||
|
|
@ -444,9 +443,11 @@ func (s *Service) handleWSMessage(msg WSMessage) (any, bool, error) {
|
|||
result, handled, err = s.Core().QUERY(dock.QueryVisible{})
|
||||
case "contextmenu:add":
|
||||
name, _ := msg.Data["name"].(string)
|
||||
menuJSON, _ := json.Marshal(msg.Data["menu"])
|
||||
menuR := corego.JSONMarshal(msg.Data["menu"])
|
||||
var menuDef contextmenu.ContextMenuDef
|
||||
_ = json.Unmarshal(menuJSON, &menuDef)
|
||||
if menuR.OK {
|
||||
_ = corego.JSONUnmarshal(menuR.Value.([]byte), &menuDef)
|
||||
}
|
||||
result, handled, err = s.Core().PERFORM(contextmenu.TaskAdd{
|
||||
Name: name, Menu: menuDef,
|
||||
})
|
||||
|
|
@ -768,7 +769,7 @@ func (s *Service) handleWSMessage(msg WSMessage) (any, bool, error) {
|
|||
}
|
||||
workflow, ok := window.ParseWorkflowLayout(workflowName)
|
||||
if !ok {
|
||||
return nil, false, fmt.Errorf("ws: unknown workflow %q", workflowName)
|
||||
return nil, false, corego.NewError(corego.Sprintf("ws: unknown workflow %q", workflowName))
|
||||
}
|
||||
var names []string
|
||||
if raw, ok := msg.Data["windows"].([]any); ok {
|
||||
|
|
@ -899,17 +900,19 @@ func (s *Service) handleWSMessage(msg WSMessage) (any, bool, error) {
|
|||
case "clipboard:write-image":
|
||||
data, ok := msg.Data["data"].(string)
|
||||
if !ok || data == "" {
|
||||
return nil, false, fmt.Errorf("ws: missing required field %q", "data")
|
||||
return nil, false, corego.NewError(corego.Sprintf("ws: missing required field %q", "data"))
|
||||
}
|
||||
decoded, decodeErr := base64.StdEncoding.DecodeString(data)
|
||||
if decodeErr != nil {
|
||||
return nil, false, fmt.Errorf("ws: invalid base64 image data: %w", decodeErr)
|
||||
return nil, false, corego.Wrap(decodeErr, "display.ws", "ws: invalid base64 image data")
|
||||
}
|
||||
result, handled, err = s.Core().PERFORM(clipboard.TaskSetImage{Data: decoded})
|
||||
case "notification:show":
|
||||
var opts notification.NotificationOptions
|
||||
encoded, _ := json.Marshal(msg.Data)
|
||||
_ = json.Unmarshal(encoded, &opts)
|
||||
encodedR := corego.JSONMarshal(msg.Data)
|
||||
if encodedR.OK {
|
||||
_ = corego.JSONUnmarshal(encodedR.Value.([]byte), &opts)
|
||||
}
|
||||
result, handled, err = s.Core().PERFORM(notification.TaskSend{Opts: opts})
|
||||
case "notification:info":
|
||||
title, e := wsRequire(msg.Data, "title")
|
||||
|
|
@ -965,8 +968,10 @@ func (s *Service) handleWSMessage(msg WSMessage) (any, bool, error) {
|
|||
subtitle, _ := msg.Data["subtitle"].(string)
|
||||
actions := make([]notification.NotificationAction, 0)
|
||||
if raw, ok := msg.Data["actions"]; ok {
|
||||
encoded, _ := json.Marshal(raw)
|
||||
_ = json.Unmarshal(encoded, &actions)
|
||||
encodedR := corego.JSONMarshal(raw)
|
||||
if encodedR.OK {
|
||||
_ = corego.JSONUnmarshal(encodedR.Value.([]byte), &actions)
|
||||
}
|
||||
}
|
||||
result, handled, err = s.Core().PERFORM(notification.TaskSend{
|
||||
Opts: notification.NotificationOptions{
|
||||
|
|
@ -1014,18 +1019,20 @@ func (s *Service) handleWSMessage(msg WSMessage) (any, bool, error) {
|
|||
}
|
||||
decoded, decodeErr := base64.StdEncoding.DecodeString(data)
|
||||
if decodeErr != nil {
|
||||
return nil, false, fmt.Errorf("ws: invalid base64 tray icon data: %w", decodeErr)
|
||||
return nil, false, corego.Wrap(decodeErr, "display.ws", "ws: invalid base64 tray icon data")
|
||||
}
|
||||
result, handled, err = s.Core().PERFORM(systray.TaskSetTrayIcon{Data: decoded})
|
||||
case "tray:set-menu":
|
||||
raw, ok := msg.Data["items"]
|
||||
if !ok {
|
||||
return nil, false, fmt.Errorf("ws: missing required field %q", "items")
|
||||
return nil, false, corego.NewError(corego.Sprintf("ws: missing required field %q", "items"))
|
||||
}
|
||||
encoded, _ := json.Marshal(raw)
|
||||
encodedItemsR := corego.JSONMarshal(raw)
|
||||
var items []systray.TrayMenuItem
|
||||
if err := json.Unmarshal(encoded, &items); err != nil {
|
||||
return nil, false, fmt.Errorf("ws: invalid tray menu items: %w", err)
|
||||
if encodedItemsR.OK {
|
||||
if r := corego.JSONUnmarshal(encodedItemsR.Value.([]byte), &items); !r.OK {
|
||||
return nil, false, corego.E("display.ws", "invalid tray menu items", nil)
|
||||
}
|
||||
}
|
||||
result, handled, err = s.Core().PERFORM(systray.TaskSetTrayMenu{Items: items})
|
||||
case "tray:info":
|
||||
|
|
@ -1045,10 +1052,11 @@ func (s *Service) handleWSMessage(msg WSMessage) (any, bool, error) {
|
|||
result, handled, err = nil, true, s.SetTheme(isDark)
|
||||
case "dialog:open-file":
|
||||
var opts dialog.OpenFileOptions
|
||||
encoded, _ := json.Marshal(msg.Data)
|
||||
if err := json.Unmarshal(encoded, &opts); err != nil {
|
||||
return nil, false, fmt.Errorf("ws: invalid open file options: %w", err)
|
||||
encodedR := corego.JSONMarshal(msg.Data)
|
||||
if encodedR.OK {
|
||||
_ = corego.JSONUnmarshal(encodedR.Value.([]byte), &opts)
|
||||
}
|
||||
return nil, false, corego.Wrap(err, "display.ws", "ws: invalid open file options")
|
||||
paths, openErr := s.OpenFileDialog(opts)
|
||||
if openErr != nil {
|
||||
return nil, false, openErr
|
||||
|
|
@ -1056,10 +1064,11 @@ func (s *Service) handleWSMessage(msg WSMessage) (any, bool, error) {
|
|||
result, handled, err = paths, true, nil
|
||||
case "dialog:save-file":
|
||||
var opts dialog.SaveFileOptions
|
||||
encoded, _ := json.Marshal(msg.Data)
|
||||
if err := json.Unmarshal(encoded, &opts); err != nil {
|
||||
return nil, false, fmt.Errorf("ws: invalid save file options: %w", err)
|
||||
encodedR := corego.JSONMarshal(msg.Data)
|
||||
if encodedR.OK {
|
||||
_ = corego.JSONUnmarshal(encodedR.Value.([]byte), &opts)
|
||||
}
|
||||
return nil, false, corego.Wrap(err, "display.ws", "ws: invalid save file options")
|
||||
path, saveErr := s.SaveFileDialog(opts)
|
||||
if saveErr != nil {
|
||||
return nil, false, saveErr
|
||||
|
|
@ -1067,10 +1076,11 @@ func (s *Service) handleWSMessage(msg WSMessage) (any, bool, error) {
|
|||
result, handled, err = path, true, nil
|
||||
case "dialog:open-directory":
|
||||
var opts dialog.OpenDirectoryOptions
|
||||
encoded, _ := json.Marshal(msg.Data)
|
||||
if err := json.Unmarshal(encoded, &opts); err != nil {
|
||||
return nil, false, fmt.Errorf("ws: invalid open directory options: %w", err)
|
||||
encodedR := corego.JSONMarshal(msg.Data)
|
||||
if encodedR.OK {
|
||||
_ = corego.JSONUnmarshal(encodedR.Value.([]byte), &opts)
|
||||
}
|
||||
return nil, false, corego.Wrap(err, "display.ws", "ws: invalid open directory options")
|
||||
path, dirErr := s.OpenDirectoryDialog(opts)
|
||||
if dirErr != nil {
|
||||
return nil, false, dirErr
|
||||
|
|
@ -1135,7 +1145,7 @@ func (s *Service) handleTrayAction(actionID string) {
|
|||
result, handled, _ := s.Core().QUERY(environment.QueryInfo{})
|
||||
if handled {
|
||||
info := result.(environment.EnvironmentInfo)
|
||||
details := fmt.Sprintf("OS: %s\nArch: %s\nPlatform: %s %s",
|
||||
details := corego.Sprintf("OS: %s\nArch: %s\nPlatform: %s %s",
|
||||
info.OS, info.Arch, info.Platform.Name, info.Platform.Version)
|
||||
_, _, _ = s.Core().PERFORM(dialog.TaskMessageDialog{
|
||||
Opts: dialog.MessageDialogOptions{
|
||||
|
|
@ -1154,9 +1164,9 @@ func (s *Service) handleTrayAction(actionID string) {
|
|||
func guiConfigPath() string {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return filepath.Join(".core", "gui", "config.yaml")
|
||||
return corego.JoinPath(".core", "gui", "config.yaml")
|
||||
}
|
||||
return filepath.Join(home, ".core", "gui", "config.yaml")
|
||||
return corego.JoinPath(home, ".core", "gui", "config.yaml")
|
||||
}
|
||||
|
||||
func (s *Service) loadConfig() {
|
||||
|
|
@ -1250,7 +1260,7 @@ func (s *Service) GetWindowInfo(name string) (*window.WindowInfo, error) {
|
|||
return nil, err
|
||||
}
|
||||
if !handled {
|
||||
return nil, fmt.Errorf("window service not available")
|
||||
return nil, corego.NewError(corego.Sprintf("window service not available"))
|
||||
}
|
||||
info, _ := result.(*window.WindowInfo)
|
||||
return info, nil
|
||||
|
|
@ -1410,7 +1420,7 @@ func (s *Service) GetWindowTitle(name string) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
if info == nil {
|
||||
return "", fmt.Errorf("window not found: %s", name)
|
||||
return "", corego.NewError(corego.Sprintf("window not found: %s", name))
|
||||
}
|
||||
return info.Title, nil
|
||||
}
|
||||
|
|
@ -1459,7 +1469,7 @@ type CreateWindowOptions struct {
|
|||
// Use: info, err := svc.CreateWindow(display.CreateWindowOptions{Name: "editor", URL: "/editor"})
|
||||
func (s *Service) CreateWindow(opts CreateWindowOptions) (*window.WindowInfo, error) {
|
||||
if opts.Name == "" {
|
||||
return nil, fmt.Errorf("window name is required")
|
||||
return nil, corego.NewError(corego.Sprintf("window name is required"))
|
||||
}
|
||||
result, _, err := s.Core().PERFORM(window.TaskOpenWindow{
|
||||
Window: &window.Window{
|
||||
|
|
@ -1488,7 +1498,7 @@ func (s *Service) CreateWindow(opts CreateWindowOptions) (*window.WindowInfo, er
|
|||
func (s *Service) SaveLayout(name string) error {
|
||||
ws := s.windowService()
|
||||
if ws == nil {
|
||||
return fmt.Errorf("window service not available")
|
||||
return corego.NewError(corego.Sprintf("window service not available"))
|
||||
}
|
||||
states := make(map[string]window.WindowState)
|
||||
for _, n := range ws.Manager().List() {
|
||||
|
|
@ -1506,11 +1516,11 @@ func (s *Service) SaveLayout(name string) error {
|
|||
func (s *Service) RestoreLayout(name string) error {
|
||||
ws := s.windowService()
|
||||
if ws == nil {
|
||||
return fmt.Errorf("window service not available")
|
||||
return corego.NewError(corego.Sprintf("window service not available"))
|
||||
}
|
||||
layout, ok := ws.Manager().Layout().GetLayout(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("layout not found: %s", name)
|
||||
return corego.NewError(corego.Sprintf("layout not found: %s", name))
|
||||
}
|
||||
for wName, state := range layout.Windows {
|
||||
if pw, ok := ws.Manager().Get(wName); ok {
|
||||
|
|
@ -1541,7 +1551,7 @@ func (s *Service) ListLayouts() []window.LayoutInfo {
|
|||
func (s *Service) DeleteLayout(name string) error {
|
||||
ws := s.windowService()
|
||||
if ws == nil {
|
||||
return fmt.Errorf("window service not available")
|
||||
return corego.NewError(corego.Sprintf("window service not available"))
|
||||
}
|
||||
ws.Manager().Layout().DeleteLayout(name)
|
||||
return nil
|
||||
|
|
@ -1568,7 +1578,7 @@ func (s *Service) GetLayout(name string) *window.Layout {
|
|||
func (s *Service) TileWindows(mode window.TileMode, windowNames []string) error {
|
||||
ws := s.windowService()
|
||||
if ws == nil {
|
||||
return fmt.Errorf("window service not available")
|
||||
return corego.NewError(corego.Sprintf("window service not available"))
|
||||
}
|
||||
screenWidth, screenHeight := s.primaryScreenSize()
|
||||
return ws.Manager().TileWindows(mode, windowNames, screenWidth, screenHeight)
|
||||
|
|
@ -1579,7 +1589,7 @@ func (s *Service) TileWindows(mode window.TileMode, windowNames []string) error
|
|||
func (s *Service) SnapWindow(name string, position window.SnapPosition) error {
|
||||
ws := s.windowService()
|
||||
if ws == nil {
|
||||
return fmt.Errorf("window service not available")
|
||||
return corego.NewError(corego.Sprintf("window service not available"))
|
||||
}
|
||||
screenWidth, screenHeight := s.primaryScreenSize()
|
||||
return ws.Manager().SnapWindow(name, position, screenWidth, screenHeight)
|
||||
|
|
@ -1617,7 +1627,7 @@ func (s *Service) primaryScreenSize() (int, int) {
|
|||
func (s *Service) StackWindows(windowNames []string, offsetX, offsetY int) error {
|
||||
ws := s.windowService()
|
||||
if ws == nil {
|
||||
return fmt.Errorf("window service not available")
|
||||
return corego.NewError(corego.Sprintf("window service not available"))
|
||||
}
|
||||
return ws.Manager().StackWindows(windowNames, offsetX, offsetY)
|
||||
}
|
||||
|
|
@ -1627,7 +1637,7 @@ func (s *Service) StackWindows(windowNames []string, offsetX, offsetY int) error
|
|||
func (s *Service) ApplyWorkflowLayout(workflow window.WorkflowLayout) error {
|
||||
ws := s.windowService()
|
||||
if ws == nil {
|
||||
return fmt.Errorf("window service not available")
|
||||
return corego.NewError(corego.Sprintf("window service not available"))
|
||||
}
|
||||
screenWidth, screenHeight := s.primaryScreenSize()
|
||||
return ws.Manager().ApplyWorkflow(workflow, ws.Manager().List(), screenWidth, screenHeight)
|
||||
|
|
@ -1638,7 +1648,7 @@ func (s *Service) ApplyWorkflowLayout(workflow window.WorkflowLayout) error {
|
|||
func (s *Service) ArrangeWindowPair(first, second string) error {
|
||||
ws := s.windowService()
|
||||
if ws == nil {
|
||||
return fmt.Errorf("window service not available")
|
||||
return corego.NewError(corego.Sprintf("window service not available"))
|
||||
}
|
||||
screenWidth, screenHeight := s.primaryScreenSize()
|
||||
return ws.Manager().ArrangePair(first, second, screenWidth, screenHeight)
|
||||
|
|
@ -1649,7 +1659,7 @@ func (s *Service) ArrangeWindowPair(first, second string) error {
|
|||
func (s *Service) FindSpace(width, height int) (window.SpaceInfo, error) {
|
||||
ws := s.windowService()
|
||||
if ws == nil {
|
||||
return window.SpaceInfo{}, fmt.Errorf("window service not available")
|
||||
return window.SpaceInfo{}, corego.NewError(corego.Sprintf("window service not available"))
|
||||
}
|
||||
screenWidth, screenHeight := s.primaryScreenSize()
|
||||
if width <= 0 {
|
||||
|
|
@ -1673,7 +1683,7 @@ func (s *Service) SuggestLayout(windowCount, screenWidth, screenHeight int) (win
|
|||
return window.LayoutSuggestion{}, err
|
||||
}
|
||||
if !handled {
|
||||
return window.LayoutSuggestion{}, fmt.Errorf("window service not available")
|
||||
return window.LayoutSuggestion{}, corego.NewError(corego.Sprintf("window service not available"))
|
||||
}
|
||||
suggestion, _ := result.(window.LayoutSuggestion)
|
||||
return suggestion, nil
|
||||
|
|
@ -1710,7 +1720,7 @@ func (s *Service) GetScreen(id string) (*screen.Screen, error) {
|
|||
return nil, err
|
||||
}
|
||||
if !handled {
|
||||
return nil, fmt.Errorf("screen service not available")
|
||||
return nil, corego.NewError(corego.Sprintf("screen service not available"))
|
||||
}
|
||||
scr, _ := result.(*screen.Screen)
|
||||
return scr, nil
|
||||
|
|
@ -1724,7 +1734,7 @@ func (s *Service) GetPrimaryScreen() (*screen.Screen, error) {
|
|||
return nil, err
|
||||
}
|
||||
if !handled {
|
||||
return nil, fmt.Errorf("screen service not available")
|
||||
return nil, corego.NewError(corego.Sprintf("screen service not available"))
|
||||
}
|
||||
scr, _ := result.(*screen.Screen)
|
||||
return scr, nil
|
||||
|
|
@ -1738,7 +1748,7 @@ func (s *Service) GetScreenAtPoint(x, y int) (*screen.Screen, error) {
|
|||
return nil, err
|
||||
}
|
||||
if !handled {
|
||||
return nil, fmt.Errorf("screen service not available")
|
||||
return nil, corego.NewError(corego.Sprintf("screen service not available"))
|
||||
}
|
||||
scr, _ := result.(*screen.Screen)
|
||||
return scr, nil
|
||||
|
|
@ -1923,7 +1933,7 @@ func (s *Service) RequestNotificationPermission() (bool, error) {
|
|||
return false, err
|
||||
}
|
||||
if !handled {
|
||||
return false, fmt.Errorf("notification service not available")
|
||||
return false, corego.NewError(corego.Sprintf("notification service not available"))
|
||||
}
|
||||
granted, _ := result.(bool)
|
||||
return granted, nil
|
||||
|
|
@ -1937,7 +1947,7 @@ func (s *Service) CheckNotificationPermission() (bool, error) {
|
|||
return false, err
|
||||
}
|
||||
if !handled {
|
||||
return false, fmt.Errorf("notification service not available")
|
||||
return false, corego.NewError(corego.Sprintf("notification service not available"))
|
||||
}
|
||||
status, _ := result.(notification.PermissionStatus)
|
||||
return status.Granted, nil
|
||||
|
|
@ -1951,7 +1961,7 @@ func (s *Service) ClearNotifications() error {
|
|||
return err
|
||||
}
|
||||
if !handled {
|
||||
return fmt.Errorf("notification service not available")
|
||||
return corego.NewError(corego.Sprintf("notification service not available"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1966,7 +1976,7 @@ func (s *Service) OpenFileDialog(opts dialog.OpenFileOptions) ([]string, error)
|
|||
return nil, err
|
||||
}
|
||||
if !handled {
|
||||
return nil, fmt.Errorf("dialog service not available")
|
||||
return nil, corego.NewError(corego.Sprintf("dialog service not available"))
|
||||
}
|
||||
paths, _ := result.([]string)
|
||||
return paths, nil
|
||||
|
|
@ -1993,7 +2003,7 @@ func (s *Service) SaveFileDialog(opts dialog.SaveFileOptions) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
if !handled {
|
||||
return "", fmt.Errorf("dialog service not available")
|
||||
return "", corego.NewError(corego.Sprintf("dialog service not available"))
|
||||
}
|
||||
path, _ := result.(string)
|
||||
return path, nil
|
||||
|
|
@ -2007,7 +2017,7 @@ func (s *Service) OpenDirectoryDialog(opts dialog.OpenDirectoryOptions) (string,
|
|||
return "", err
|
||||
}
|
||||
if !handled {
|
||||
return "", fmt.Errorf("dialog service not available")
|
||||
return "", corego.NewError(corego.Sprintf("dialog service not available"))
|
||||
}
|
||||
path, _ := result.(string)
|
||||
return path, nil
|
||||
|
|
@ -2028,7 +2038,7 @@ func (s *Service) ConfirmDialog(title, message string) (bool, error) {
|
|||
return false, err
|
||||
}
|
||||
if !handled {
|
||||
return false, fmt.Errorf("dialog service not available")
|
||||
return false, corego.NewError(corego.Sprintf("dialog service not available"))
|
||||
}
|
||||
button, _ := result.(string)
|
||||
return button == "Yes" || button == "OK", nil
|
||||
|
|
@ -2060,7 +2070,7 @@ func (s *Service) PromptDialog(title, message string) (string, bool, error) {
|
|||
return "", false, err
|
||||
}
|
||||
if !handled {
|
||||
return "", false, fmt.Errorf("dialog service not available")
|
||||
return "", false, corego.NewError(corego.Sprintf("dialog service not available"))
|
||||
}
|
||||
button, _ := result.(string)
|
||||
return button, button == "OK", nil
|
||||
|
|
@ -2075,27 +2085,27 @@ func (s *Service) promptViaWebView(title, message string) (string, bool, error)
|
|||
}
|
||||
}
|
||||
if windowName == "" {
|
||||
return "", false, fmt.Errorf("no webview window available")
|
||||
return "", false, corego.NewError(corego.Sprintf("no webview window available"))
|
||||
}
|
||||
|
||||
encodedTitle, err := json.Marshal(title)
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
encodedTitleR := corego.JSONMarshal(title)
|
||||
if !encodedTitleR.OK {
|
||||
return "", false, corego.E("display.showDialog", "failed to marshal title", nil)
|
||||
}
|
||||
encodedMessage, err := json.Marshal(message)
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
encodedMessageR := corego.JSONMarshal(message)
|
||||
if !encodedMessageR.OK {
|
||||
return "", false, corego.E("display.showDialog", "failed to marshal message", nil)
|
||||
}
|
||||
|
||||
result, handled, err := s.Core().PERFORM(webview.TaskEvaluate{
|
||||
Window: windowName,
|
||||
Script: "window.prompt(" + string(encodedTitle) + "," + string(encodedMessage) + ")",
|
||||
Script: "window.prompt(" + string(encodedTitleR.Value.([]byte)) + "," + string(encodedMessageR.Value.([]byte)) + ")",
|
||||
})
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
if !handled {
|
||||
return "", false, fmt.Errorf("webview service not available")
|
||||
return "", false, corego.NewError(corego.Sprintf("webview service not available"))
|
||||
}
|
||||
if result == nil {
|
||||
return "", false, nil
|
||||
|
|
@ -2103,7 +2113,7 @@ func (s *Service) promptViaWebView(title, message string) (string, bool, error)
|
|||
if text, ok := result.(string); ok {
|
||||
return text, true, nil
|
||||
}
|
||||
return fmt.Sprint(result), true, nil
|
||||
return corego.Sprint(result), true, nil
|
||||
}
|
||||
|
||||
// DialogMessage shows an informational, warning, or error message via the notification pipeline.
|
||||
|
|
@ -2178,7 +2188,7 @@ func (s *Service) SetThemeMode(theme string) error {
|
|||
return err
|
||||
}
|
||||
if !handled {
|
||||
return fmt.Errorf("environment service not available")
|
||||
return corego.NewError(corego.Sprintf("environment service not available"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -2193,7 +2203,7 @@ func (s *Service) SetTrayIcon(data []byte) error {
|
|||
return err
|
||||
}
|
||||
if !handled {
|
||||
return fmt.Errorf("systray service not available")
|
||||
return corego.NewError(corego.Sprintf("systray service not available"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -2206,7 +2216,7 @@ func (s *Service) SetTrayTooltip(tooltip string) error {
|
|||
return err
|
||||
}
|
||||
if !handled {
|
||||
return fmt.Errorf("systray service not available")
|
||||
return corego.NewError(corego.Sprintf("systray service not available"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -2219,7 +2229,7 @@ func (s *Service) SetTrayLabel(label string) error {
|
|||
return err
|
||||
}
|
||||
if !handled {
|
||||
return fmt.Errorf("systray service not available")
|
||||
return corego.NewError(corego.Sprintf("systray service not available"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -2232,7 +2242,7 @@ func (s *Service) SetTrayMenu(items []systray.TrayMenuItem) error {
|
|||
return err
|
||||
}
|
||||
if !handled {
|
||||
return fmt.Errorf("systray service not available")
|
||||
return corego.NewError(corego.Sprintf("systray service not available"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -2255,7 +2265,7 @@ func (s *Service) ShowTrayMessage(title, message string) error {
|
|||
return err
|
||||
}
|
||||
if !handled {
|
||||
return fmt.Errorf("systray service not available")
|
||||
return corego.NewError(corego.Sprintf("systray service not available"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,15 +8,15 @@ import (
|
|||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go/pkg/core"
|
||||
"forge.lthn.ai/core/gui/pkg/clipboard"
|
||||
"forge.lthn.ai/core/gui/pkg/dialog"
|
||||
"forge.lthn.ai/core/gui/pkg/environment"
|
||||
"forge.lthn.ai/core/gui/pkg/menu"
|
||||
"forge.lthn.ai/core/gui/pkg/notification"
|
||||
"forge.lthn.ai/core/gui/pkg/screen"
|
||||
"forge.lthn.ai/core/gui/pkg/systray"
|
||||
"forge.lthn.ai/core/gui/pkg/webview"
|
||||
"forge.lthn.ai/core/gui/pkg/window"
|
||||
"dappco.re/go/core/gui/pkg/clipboard"
|
||||
"dappco.re/go/core/gui/pkg/dialog"
|
||||
"dappco.re/go/core/gui/pkg/environment"
|
||||
"dappco.re/go/core/gui/pkg/menu"
|
||||
"dappco.re/go/core/gui/pkg/notification"
|
||||
"dappco.re/go/core/gui/pkg/screen"
|
||||
"dappco.re/go/core/gui/pkg/systray"
|
||||
"dappco.re/go/core/gui/pkg/webview"
|
||||
"dappco.re/go/core/gui/pkg/window"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,13 +2,12 @@
|
|||
package display
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"forge.lthn.ai/core/gui/pkg/window"
|
||||
"dappco.re/go/core"
|
||||
"dappco.re/go/core/gui/pkg/window"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
|
|
@ -144,13 +143,13 @@ func (em *WSEventManager) sendEvent(conn *websocket.Conn, event Event) {
|
|||
return
|
||||
}
|
||||
|
||||
data, err := json.Marshal(event)
|
||||
if err != nil {
|
||||
r := core.JSONMarshal(event)
|
||||
if !r.OK {
|
||||
return
|
||||
}
|
||||
|
||||
conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
|
||||
if err := conn.WriteMessage(websocket.TextMessage, data); err != nil {
|
||||
if err := conn.WriteMessage(websocket.TextMessage, r.Value.([]byte)); err != nil {
|
||||
em.removeClient(conn)
|
||||
}
|
||||
}
|
||||
|
|
@ -188,7 +187,7 @@ func (em *WSEventManager) handleMessages(conn *websocket.Conn) {
|
|||
EventTypes []EventType `json:"eventTypes,omitempty"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(message, &msg); err != nil {
|
||||
if r := core.JSONUnmarshal(message, &msg); !r.OK {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +216,7 @@ func (em *WSEventManager) subscribe(conn *websocket.Conn, id string, eventTypes
|
|||
if id == "" {
|
||||
em.mu.Lock()
|
||||
em.nextSubID++
|
||||
id = fmt.Sprintf("sub-%d", em.nextSubID)
|
||||
id = core.Sprintf("sub-%d", em.nextSubID)
|
||||
em.mu.Unlock()
|
||||
}
|
||||
|
||||
|
|
@ -234,8 +233,10 @@ func (em *WSEventManager) subscribe(conn *websocket.Conn, id string, eventTypes
|
|||
"id": id,
|
||||
"eventTypes": eventTypes,
|
||||
}
|
||||
data, _ := json.Marshal(response)
|
||||
conn.WriteMessage(websocket.TextMessage, data)
|
||||
r := core.JSONMarshal(response)
|
||||
if r.OK {
|
||||
conn.WriteMessage(websocket.TextMessage, r.Value.([]byte))
|
||||
}
|
||||
}
|
||||
|
||||
// unsubscribe removes a subscription for a client.
|
||||
|
|
@ -257,8 +258,10 @@ func (em *WSEventManager) unsubscribe(conn *websocket.Conn, id string) {
|
|||
"type": "unsubscribed",
|
||||
"id": id,
|
||||
}
|
||||
data, _ := json.Marshal(response)
|
||||
conn.WriteMessage(websocket.TextMessage, data)
|
||||
r := core.JSONMarshal(response)
|
||||
if r.OK {
|
||||
conn.WriteMessage(websocket.TextMessage, r.Value.([]byte))
|
||||
}
|
||||
}
|
||||
|
||||
// listSubscriptions sends a list of active subscriptions to a client.
|
||||
|
|
@ -282,8 +285,10 @@ func (em *WSEventManager) listSubscriptions(conn *websocket.Conn) {
|
|||
"type": "subscriptions",
|
||||
"subscriptions": subs,
|
||||
}
|
||||
data, _ := json.Marshal(response)
|
||||
conn.WriteMessage(websocket.TextMessage, data)
|
||||
r := core.JSONMarshal(response)
|
||||
if r.OK {
|
||||
conn.WriteMessage(websocket.TextMessage, r.Value.([]byte))
|
||||
}
|
||||
}
|
||||
|
||||
// removeClient removes a client and its subscriptions.
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package environment
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
corego "dappco.re/go/core"
|
||||
"forge.lthn.ai/core/go/pkg/core"
|
||||
)
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ func (s *Service) taskSetTheme(task TaskSetTheme) error {
|
|||
s.overrideDark = &isDark
|
||||
shouldApplyTheme = true
|
||||
default:
|
||||
return fmt.Errorf("invalid theme mode: %s", task.Theme)
|
||||
return corego.E("environment.setTheme", corego.Sprintf("invalid theme mode: %s", task.Theme), nil)
|
||||
}
|
||||
|
||||
if shouldApplyTheme {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// pkg/keybinding/messages.go
|
||||
package keybinding
|
||||
|
||||
import "errors"
|
||||
import corego "dappco.re/go/core"
|
||||
|
||||
// ErrAlreadyRegistered is returned when attempting to add a binding
|
||||
// that already exists. Callers must TaskRemove first to rebind.
|
||||
var ErrAlreadyRegistered = errors.New("keybinding: accelerator already registered")
|
||||
var ErrAlreadyRegistered = corego.NewError("keybinding: accelerator already registered")
|
||||
|
||||
// BindingInfo describes a registered keyboard shortcut.
|
||||
type BindingInfo struct {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package keybinding
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
corego "dappco.re/go/core"
|
||||
"forge.lthn.ai/core/go/pkg/core"
|
||||
)
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ func (s *Service) taskAdd(t TaskAdd) error {
|
|||
_ = s.Core().ACTION(ActionTriggered{Accelerator: t.Accelerator})
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("keybinding: platform add failed: %w", err)
|
||||
return corego.Wrap(err, "keybinding.add", "platform add failed")
|
||||
}
|
||||
|
||||
s.bindings[t.Accelerator] = BindingInfo{
|
||||
|
|
@ -87,12 +87,12 @@ func (s *Service) taskAdd(t TaskAdd) error {
|
|||
|
||||
func (s *Service) taskRemove(t TaskRemove) error {
|
||||
if _, exists := s.bindings[t.Accelerator]; !exists {
|
||||
return fmt.Errorf("keybinding: not registered: %s", t.Accelerator)
|
||||
return corego.E("keybinding.remove", corego.Sprintf("not registered: %s", t.Accelerator), nil)
|
||||
}
|
||||
|
||||
err := s.platform.Remove(t.Accelerator)
|
||||
if err != nil {
|
||||
return fmt.Errorf("keybinding: platform remove failed: %w", err)
|
||||
return corego.Wrap(err, "keybinding.remove", "platform remove failed")
|
||||
}
|
||||
|
||||
delete(s.bindings, t.Accelerator)
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@ import (
|
|||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go/pkg/core"
|
||||
"forge.lthn.ai/core/gui/pkg/clipboard"
|
||||
"forge.lthn.ai/core/gui/pkg/display"
|
||||
"forge.lthn.ai/core/gui/pkg/environment"
|
||||
"forge.lthn.ai/core/gui/pkg/notification"
|
||||
"forge.lthn.ai/core/gui/pkg/screen"
|
||||
"forge.lthn.ai/core/gui/pkg/webview"
|
||||
"forge.lthn.ai/core/gui/pkg/window"
|
||||
"dappco.re/go/core/gui/pkg/clipboard"
|
||||
"dappco.re/go/core/gui/pkg/display"
|
||||
"dappco.re/go/core/gui/pkg/environment"
|
||||
"dappco.re/go/core/gui/pkg/notification"
|
||||
"dappco.re/go/core/gui/pkg/screen"
|
||||
"dappco.re/go/core/gui/pkg/webview"
|
||||
"dappco.re/go/core/gui/pkg/window"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ package mcp
|
|||
import (
|
||||
"context"
|
||||
|
||||
"forge.lthn.ai/core/gui/pkg/browser"
|
||||
"dappco.re/go/core/gui/pkg/browser"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ package mcp
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"forge.lthn.ai/core/gui/pkg/clipboard"
|
||||
corego "dappco.re/go/core"
|
||||
"dappco.re/go/core/gui/pkg/clipboard"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ func (s *Subsystem) clipboardRead(_ context.Context, _ *mcp.CallToolRequest, _ C
|
|||
}
|
||||
content, ok := result.(clipboard.ClipboardContent)
|
||||
if !ok {
|
||||
return nil, ClipboardReadOutput{}, fmt.Errorf("unexpected result type from clipboard read query")
|
||||
return nil, ClipboardReadOutput{}, corego.E("mcp.clipboard", "unexpected result type from clipboard read query", nil)
|
||||
}
|
||||
return nil, ClipboardReadOutput{Content: content.Text}, nil
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ func (s *Subsystem) clipboardWrite(_ context.Context, _ *mcp.CallToolRequest, in
|
|||
}
|
||||
success, ok := result.(bool)
|
||||
if !ok {
|
||||
return nil, ClipboardWriteOutput{}, fmt.Errorf("unexpected result type from clipboard write task")
|
||||
return nil, ClipboardWriteOutput{}, corego.E("mcp.clipboard", "unexpected result type from clipboard write task", nil)
|
||||
}
|
||||
return nil, ClipboardWriteOutput{Success: success}, nil
|
||||
}
|
||||
|
|
@ -63,7 +63,7 @@ func (s *Subsystem) clipboardHas(_ context.Context, _ *mcp.CallToolRequest, _ Cl
|
|||
}
|
||||
content, ok := result.(clipboard.ClipboardContent)
|
||||
if !ok {
|
||||
return nil, ClipboardHasOutput{}, fmt.Errorf("unexpected result type from clipboard has query")
|
||||
return nil, ClipboardHasOutput{}, corego.E("mcp.clipboard", "unexpected result type from clipboard has query", nil)
|
||||
}
|
||||
return nil, ClipboardHasOutput{HasContent: content.HasContent}, nil
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ func (s *Subsystem) clipboardClear(_ context.Context, _ *mcp.CallToolRequest, _
|
|||
}
|
||||
success, ok := result.(bool)
|
||||
if !ok {
|
||||
return nil, ClipboardClearOutput{}, fmt.Errorf("unexpected result type from clipboard clear task")
|
||||
return nil, ClipboardClearOutput{}, corego.E("mcp.clipboard", "unexpected result type from clipboard clear task", nil)
|
||||
}
|
||||
return nil, ClipboardClearOutput{Success: success}, nil
|
||||
}
|
||||
|
|
@ -101,7 +101,7 @@ func (s *Subsystem) clipboardReadImage(_ context.Context, _ *mcp.CallToolRequest
|
|||
}
|
||||
image, ok := result.(clipboard.ClipboardImageContent)
|
||||
if !ok {
|
||||
return nil, ClipboardReadImageOutput{}, fmt.Errorf("unexpected result type from clipboard image query")
|
||||
return nil, ClipboardReadImageOutput{}, corego.E("mcp.clipboard", "unexpected result type from clipboard image query", nil)
|
||||
}
|
||||
return nil, ClipboardReadImageOutput{Image: image}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@ package mcp
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"forge.lthn.ai/core/gui/pkg/contextmenu"
|
||||
corego "dappco.re/go/core"
|
||||
"dappco.re/go/core/gui/pkg/contextmenu"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
|
|
@ -25,13 +24,13 @@ type ContextMenuAddOutput struct {
|
|||
|
||||
func (s *Subsystem) contextMenuAdd(_ context.Context, _ *mcp.CallToolRequest, input ContextMenuAddInput) (*mcp.CallToolResult, ContextMenuAddOutput, error) {
|
||||
// Convert map[string]any to ContextMenuDef via JSON round-trip
|
||||
menuJSON, err := json.Marshal(input.Menu)
|
||||
if err != nil {
|
||||
return nil, ContextMenuAddOutput{}, fmt.Errorf("failed to marshal menu definition: %w", err)
|
||||
r := corego.JSONMarshal(input.Menu)
|
||||
if !r.OK {
|
||||
return nil, ContextMenuAddOutput{}, corego.Wrap(r.Value.(error), "mcp.contextmenu", "failed to marshal menu definition")
|
||||
}
|
||||
var menuDef contextmenu.ContextMenuDef
|
||||
if err := json.Unmarshal(menuJSON, &menuDef); err != nil {
|
||||
return nil, ContextMenuAddOutput{}, fmt.Errorf("failed to unmarshal menu definition: %w", err)
|
||||
if r2 := corego.JSONUnmarshal(r.Value.([]byte), &menuDef); !r2.OK {
|
||||
return nil, ContextMenuAddOutput{}, corego.Wrap(r2.Value.(error), "mcp.contextmenu", "failed to unmarshal menu definition")
|
||||
}
|
||||
_, _, err = s.core.PERFORM(contextmenu.TaskAdd{Name: input.Name, Menu: menuDef})
|
||||
if err != nil {
|
||||
|
|
@ -73,19 +72,19 @@ func (s *Subsystem) contextMenuGet(_ context.Context, _ *mcp.CallToolRequest, in
|
|||
}
|
||||
menu, ok := result.(*contextmenu.ContextMenuDef)
|
||||
if !ok {
|
||||
return nil, ContextMenuGetOutput{}, fmt.Errorf("unexpected result type from context menu get query")
|
||||
return nil, ContextMenuGetOutput{}, corego.E("mcp.contextmenu", "unexpected result type from context menu get query", nil)
|
||||
}
|
||||
if menu == nil {
|
||||
return nil, ContextMenuGetOutput{}, nil
|
||||
}
|
||||
// Convert to map[string]any via JSON round-trip to avoid cyclic type in schema
|
||||
menuJSON, err := json.Marshal(menu)
|
||||
if err != nil {
|
||||
return nil, ContextMenuGetOutput{}, fmt.Errorf("failed to marshal context menu: %w", err)
|
||||
r := corego.JSONMarshal(menu)
|
||||
if !r.OK {
|
||||
return nil, ContextMenuGetOutput{}, corego.Wrap(r.Value.(error), "mcp.contextmenu", "failed to marshal context menu")
|
||||
}
|
||||
var menuMap map[string]any
|
||||
if err := json.Unmarshal(menuJSON, &menuMap); err != nil {
|
||||
return nil, ContextMenuGetOutput{}, fmt.Errorf("failed to unmarshal context menu: %w", err)
|
||||
if r2 := corego.JSONUnmarshal(r.Value.([]byte), &menuMap); !r2.OK {
|
||||
return nil, ContextMenuGetOutput{}, corego.Wrap(r2.Value.(error), "mcp.contextmenu", "failed to unmarshal context menu")
|
||||
}
|
||||
return nil, ContextMenuGetOutput{Menu: menuMap}, nil
|
||||
}
|
||||
|
|
@ -104,16 +103,16 @@ func (s *Subsystem) contextMenuList(_ context.Context, _ *mcp.CallToolRequest, _
|
|||
}
|
||||
menus, ok := result.(map[string]contextmenu.ContextMenuDef)
|
||||
if !ok {
|
||||
return nil, ContextMenuListOutput{}, fmt.Errorf("unexpected result type from context menu list query")
|
||||
return nil, ContextMenuListOutput{}, corego.E("mcp.contextmenu", "unexpected result type from context menu list query", nil)
|
||||
}
|
||||
// Convert to map[string]any via JSON round-trip to avoid cyclic type in schema
|
||||
menusJSON, err := json.Marshal(menus)
|
||||
if err != nil {
|
||||
return nil, ContextMenuListOutput{}, fmt.Errorf("failed to marshal context menus: %w", err)
|
||||
r := corego.JSONMarshal(menus)
|
||||
if !r.OK {
|
||||
return nil, ContextMenuListOutput{}, corego.Wrap(r.Value.(error), "mcp.contextmenu", "failed to marshal context menus")
|
||||
}
|
||||
var menusMap map[string]any
|
||||
if err := json.Unmarshal(menusJSON, &menusMap); err != nil {
|
||||
return nil, ContextMenuListOutput{}, fmt.Errorf("failed to unmarshal context menus: %w", err)
|
||||
if r2 := corego.JSONUnmarshal(r.Value.([]byte), &menusMap); !r2.OK {
|
||||
return nil, ContextMenuListOutput{}, corego.Wrap(r2.Value.(error), "mcp.contextmenu", "failed to unmarshal context menus")
|
||||
}
|
||||
return nil, ContextMenuListOutput{Menus: menusMap}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ package mcp
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"forge.lthn.ai/core/gui/pkg/dialog"
|
||||
corego "dappco.re/go/core"
|
||||
"dappco.re/go/core/gui/pkg/dialog"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ func (s *Subsystem) dialogOpenFile(_ context.Context, _ *mcp.CallToolRequest, in
|
|||
}
|
||||
paths, ok := result.([]string)
|
||||
if !ok {
|
||||
return nil, DialogOpenFileOutput{}, fmt.Errorf("unexpected result type from open file dialog")
|
||||
return nil, DialogOpenFileOutput{}, corego.E("mcp.dialog", "unexpected result type from open file dialog", nil)
|
||||
}
|
||||
return nil, DialogOpenFileOutput{Paths: paths}, nil
|
||||
}
|
||||
|
|
@ -62,7 +62,7 @@ func (s *Subsystem) dialogSaveFile(_ context.Context, _ *mcp.CallToolRequest, in
|
|||
}
|
||||
path, ok := result.(string)
|
||||
if !ok {
|
||||
return nil, DialogSaveFileOutput{}, fmt.Errorf("unexpected result type from save file dialog")
|
||||
return nil, DialogSaveFileOutput{}, corego.E("mcp.dialog", "unexpected result type from save file dialog", nil)
|
||||
}
|
||||
return nil, DialogSaveFileOutput{Path: path}, nil
|
||||
}
|
||||
|
|
@ -87,7 +87,7 @@ func (s *Subsystem) dialogOpenDirectory(_ context.Context, _ *mcp.CallToolReques
|
|||
}
|
||||
path, ok := result.(string)
|
||||
if !ok {
|
||||
return nil, DialogOpenDirectoryOutput{}, fmt.Errorf("unexpected result type from open directory dialog")
|
||||
return nil, DialogOpenDirectoryOutput{}, corego.E("mcp.dialog", "unexpected result type from open directory dialog", nil)
|
||||
}
|
||||
return nil, DialogOpenDirectoryOutput{Path: path}, nil
|
||||
}
|
||||
|
|
@ -115,7 +115,7 @@ func (s *Subsystem) dialogConfirm(_ context.Context, _ *mcp.CallToolRequest, inp
|
|||
}
|
||||
button, ok := result.(string)
|
||||
if !ok {
|
||||
return nil, DialogConfirmOutput{}, fmt.Errorf("unexpected result type from confirm dialog")
|
||||
return nil, DialogConfirmOutput{}, corego.E("mcp.dialog", "unexpected result type from confirm dialog", nil)
|
||||
}
|
||||
return nil, DialogConfirmOutput{Button: button}, nil
|
||||
}
|
||||
|
|
@ -142,7 +142,7 @@ func (s *Subsystem) dialogPrompt(_ context.Context, _ *mcp.CallToolRequest, inpu
|
|||
}
|
||||
button, ok := result.(string)
|
||||
if !ok {
|
||||
return nil, DialogPromptOutput{}, fmt.Errorf("unexpected result type from prompt dialog")
|
||||
return nil, DialogPromptOutput{}, corego.E("mcp.dialog", "unexpected result type from prompt dialog", nil)
|
||||
}
|
||||
return nil, DialogPromptOutput{Button: button}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ package mcp
|
|||
import (
|
||||
"context"
|
||||
|
||||
"forge.lthn.ai/core/gui/pkg/dock"
|
||||
"dappco.re/go/core/gui/pkg/dock"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ package mcp
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"forge.lthn.ai/core/gui/pkg/environment"
|
||||
corego "dappco.re/go/core"
|
||||
"dappco.re/go/core/gui/pkg/environment"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ func (s *Subsystem) themeGet(_ context.Context, _ *mcp.CallToolRequest, _ ThemeG
|
|||
}
|
||||
theme, ok := result.(environment.ThemeInfo)
|
||||
if !ok {
|
||||
return nil, ThemeGetOutput{}, fmt.Errorf("unexpected result type from theme query")
|
||||
return nil, ThemeGetOutput{}, corego.E("mcp.environment", "unexpected result type from theme query", nil)
|
||||
}
|
||||
return nil, ThemeGetOutput{Theme: theme}, nil
|
||||
}
|
||||
|
|
@ -42,7 +42,7 @@ func (s *Subsystem) themeSystem(_ context.Context, _ *mcp.CallToolRequest, _ The
|
|||
}
|
||||
info, ok := result.(environment.EnvironmentInfo)
|
||||
if !ok {
|
||||
return nil, ThemeSystemOutput{}, fmt.Errorf("unexpected result type from environment info query")
|
||||
return nil, ThemeSystemOutput{}, corego.E("mcp.environment", "unexpected result type from environment info query", nil)
|
||||
}
|
||||
return nil, ThemeSystemOutput{Info: info}, nil
|
||||
}
|
||||
|
|
@ -67,7 +67,7 @@ func (s *Subsystem) themeSet(_ context.Context, _ *mcp.CallToolRequest, input Th
|
|||
}
|
||||
theme, ok := result.(environment.ThemeInfo)
|
||||
if !ok {
|
||||
return nil, ThemeSetOutput{}, fmt.Errorf("unexpected result type from theme query")
|
||||
return nil, ThemeSetOutput{}, corego.E("mcp.environment", "unexpected result type from theme query", nil)
|
||||
}
|
||||
return nil, ThemeSetOutput{Theme: theme}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ package mcp
|
|||
import (
|
||||
"context"
|
||||
|
||||
"forge.lthn.ai/core/gui/pkg/keybinding"
|
||||
"dappco.re/go/core/gui/pkg/keybinding"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ package mcp
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
corego "dappco.re/go/core"
|
||||
"dappco.re/go/core/gui/pkg/screen"
|
||||
"dappco.re/go/core/gui/pkg/window"
|
||||
"forge.lthn.ai/core/go/pkg/core"
|
||||
"forge.lthn.ai/core/gui/pkg/screen"
|
||||
"forge.lthn.ai/core/gui/pkg/window"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ func (s *Subsystem) layoutList(_ context.Context, _ *mcp.CallToolRequest, _ Layo
|
|||
}
|
||||
layouts, ok := result.([]window.LayoutInfo)
|
||||
if !ok {
|
||||
return nil, LayoutListOutput{}, fmt.Errorf("unexpected result type from layout list query")
|
||||
return nil, LayoutListOutput{}, corego.E("mcp.layout", "unexpected result type from layout list query", nil)
|
||||
}
|
||||
return nil, LayoutListOutput{Layouts: layouts}, nil
|
||||
}
|
||||
|
|
@ -97,7 +97,7 @@ func (s *Subsystem) layoutGet(_ context.Context, _ *mcp.CallToolRequest, input L
|
|||
}
|
||||
layout, ok := result.(*window.Layout)
|
||||
if !ok {
|
||||
return nil, LayoutGetOutput{}, fmt.Errorf("unexpected result type from layout get query")
|
||||
return nil, LayoutGetOutput{}, corego.E("mcp.layout", "unexpected result type from layout get query", nil)
|
||||
}
|
||||
return nil, LayoutGetOutput{Layout: layout}, nil
|
||||
}
|
||||
|
|
@ -176,7 +176,7 @@ func (s *Subsystem) layoutSuggest(_ context.Context, _ *mcp.CallToolRequest, inp
|
|||
}
|
||||
windows, ok := result.([]window.WindowInfo)
|
||||
if !ok {
|
||||
return nil, LayoutSuggestOutput{}, fmt.Errorf("unexpected result type from window list query")
|
||||
return nil, LayoutSuggestOutput{}, corego.E("mcp.layout", "unexpected result type from window list query", nil)
|
||||
}
|
||||
windowCount = len(windows)
|
||||
}
|
||||
|
|
@ -193,11 +193,11 @@ func (s *Subsystem) layoutSuggest(_ context.Context, _ *mcp.CallToolRequest, inp
|
|||
return nil, LayoutSuggestOutput{}, err
|
||||
}
|
||||
if !handled {
|
||||
return nil, LayoutSuggestOutput{}, fmt.Errorf("window service not available")
|
||||
return nil, LayoutSuggestOutput{}, corego.E("mcp.layout", "window service not available", nil)
|
||||
}
|
||||
suggestion, ok := result.(window.LayoutSuggestion)
|
||||
if !ok {
|
||||
return nil, LayoutSuggestOutput{}, fmt.Errorf("unexpected result type from layout suggestion query")
|
||||
return nil, LayoutSuggestOutput{}, corego.E("mcp.layout", "unexpected result type from layout suggestion query", nil)
|
||||
}
|
||||
return nil, LayoutSuggestOutput{Suggestion: suggestion}, nil
|
||||
}
|
||||
|
|
@ -227,11 +227,11 @@ func (s *Subsystem) screenFindSpace(_ context.Context, _ *mcp.CallToolRequest, i
|
|||
return nil, ScreenFindSpaceOutput{}, err
|
||||
}
|
||||
if !handled {
|
||||
return nil, ScreenFindSpaceOutput{}, fmt.Errorf("window service not available")
|
||||
return nil, ScreenFindSpaceOutput{}, corego.E("mcp.layout", "window service not available", nil)
|
||||
}
|
||||
space, ok := result.(window.SpaceInfo)
|
||||
if !ok {
|
||||
return nil, ScreenFindSpaceOutput{}, fmt.Errorf("unexpected result type from find space query")
|
||||
return nil, ScreenFindSpaceOutput{}, corego.E("mcp.layout", "unexpected result type from find space query", nil)
|
||||
}
|
||||
if space.ScreenWidth == 0 {
|
||||
space.ScreenWidth = screenW
|
||||
|
|
@ -296,7 +296,7 @@ type LayoutWorkflowOutput struct {
|
|||
func (s *Subsystem) layoutWorkflow(_ context.Context, _ *mcp.CallToolRequest, input LayoutWorkflowInput) (*mcp.CallToolResult, LayoutWorkflowOutput, error) {
|
||||
workflow, ok := window.ParseWorkflowLayout(input.Workflow)
|
||||
if !ok {
|
||||
return nil, LayoutWorkflowOutput{}, fmt.Errorf("unknown workflow: %s", input.Workflow)
|
||||
return nil, LayoutWorkflowOutput{}, corego.E("mcp.layout", corego.Sprintf("unknown workflow: %s", input.Workflow), nil)
|
||||
}
|
||||
_, _, err := s.core.PERFORM(window.TaskApplyWorkflow{
|
||||
Workflow: workflow,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ package mcp
|
|||
import (
|
||||
"context"
|
||||
|
||||
"forge.lthn.ai/core/gui/pkg/lifecycle"
|
||||
"dappco.re/go/core/gui/pkg/lifecycle"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ package mcp
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"forge.lthn.ai/core/gui/pkg/notification"
|
||||
corego "dappco.re/go/core"
|
||||
"dappco.re/go/core/gui/pkg/notification"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
|
|
@ -71,7 +71,7 @@ func (s *Subsystem) notificationPermissionRequest(_ context.Context, _ *mcp.Call
|
|||
}
|
||||
granted, ok := result.(bool)
|
||||
if !ok {
|
||||
return nil, NotificationPermissionRequestOutput{}, fmt.Errorf("unexpected result type from notification permission request")
|
||||
return nil, NotificationPermissionRequestOutput{}, corego.E("mcp.notification", "unexpected result type from notification permission request", nil)
|
||||
}
|
||||
return nil, NotificationPermissionRequestOutput{Granted: granted}, nil
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ func (s *Subsystem) notificationPermissionCheck(_ context.Context, _ *mcp.CallTo
|
|||
}
|
||||
status, ok := result.(notification.PermissionStatus)
|
||||
if !ok {
|
||||
return nil, NotificationPermissionCheckOutput{}, fmt.Errorf("unexpected result type from notification permission check")
|
||||
return nil, NotificationPermissionCheckOutput{}, corego.E("mcp.notification", "unexpected result type from notification permission check", nil)
|
||||
}
|
||||
return nil, NotificationPermissionCheckOutput{Granted: status.Granted}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ package mcp
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
corego "dappco.re/go/core"
|
||||
"dappco.re/go/core/gui/pkg/display"
|
||||
"dappco.re/go/core/gui/pkg/screen"
|
||||
"forge.lthn.ai/core/go/pkg/core"
|
||||
"forge.lthn.ai/core/gui/pkg/display"
|
||||
"forge.lthn.ai/core/gui/pkg/screen"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ func (s *Subsystem) screenList(_ context.Context, _ *mcp.CallToolRequest, _ Scre
|
|||
}
|
||||
screens, ok := result.([]screen.Screen)
|
||||
if !ok {
|
||||
return nil, ScreenListOutput{}, fmt.Errorf("unexpected result type from screen list query")
|
||||
return nil, ScreenListOutput{}, corego.E("mcp.screen", "unexpected result type from screen list query", nil)
|
||||
}
|
||||
return nil, ScreenListOutput{Screens: screens}, nil
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ func (s *Subsystem) screenGet(_ context.Context, _ *mcp.CallToolRequest, input S
|
|||
}
|
||||
scr, ok := result.(*screen.Screen)
|
||||
if !ok {
|
||||
return nil, ScreenGetOutput{}, fmt.Errorf("unexpected result type from screen get query")
|
||||
return nil, ScreenGetOutput{}, corego.E("mcp.screen", "unexpected result type from screen get query", nil)
|
||||
}
|
||||
return nil, ScreenGetOutput{Screen: scr}, nil
|
||||
}
|
||||
|
|
@ -65,7 +65,7 @@ func (s *Subsystem) screenPrimary(_ context.Context, _ *mcp.CallToolRequest, _ S
|
|||
}
|
||||
scr, ok := result.(*screen.Screen)
|
||||
if !ok {
|
||||
return nil, ScreenPrimaryOutput{}, fmt.Errorf("unexpected result type from screen primary query")
|
||||
return nil, ScreenPrimaryOutput{}, corego.E("mcp.screen", "unexpected result type from screen primary query", nil)
|
||||
}
|
||||
return nil, ScreenPrimaryOutput{Screen: scr}, nil
|
||||
}
|
||||
|
|
@ -87,7 +87,7 @@ func (s *Subsystem) screenAtPoint(_ context.Context, _ *mcp.CallToolRequest, inp
|
|||
}
|
||||
scr, ok := result.(*screen.Screen)
|
||||
if !ok {
|
||||
return nil, ScreenAtPointOutput{}, fmt.Errorf("unexpected result type from screen at point query")
|
||||
return nil, ScreenAtPointOutput{}, corego.E("mcp.screen", "unexpected result type from screen at point query", nil)
|
||||
}
|
||||
return nil, ScreenAtPointOutput{Screen: scr}, nil
|
||||
}
|
||||
|
|
@ -106,7 +106,7 @@ func (s *Subsystem) screenWorkAreas(_ context.Context, _ *mcp.CallToolRequest, _
|
|||
}
|
||||
areas, ok := result.([]screen.Rect)
|
||||
if !ok {
|
||||
return nil, ScreenWorkAreasOutput{}, fmt.Errorf("unexpected result type from screen work areas query")
|
||||
return nil, ScreenWorkAreasOutput{}, corego.E("mcp.screen", "unexpected result type from screen work areas query", nil)
|
||||
}
|
||||
return nil, ScreenWorkAreasOutput{WorkAreas: areas}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ package mcp
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"forge.lthn.ai/core/gui/pkg/systray"
|
||||
corego "dappco.re/go/core"
|
||||
"dappco.re/go/core/gui/pkg/systray"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ func (s *Subsystem) trayInfo(_ context.Context, _ *mcp.CallToolRequest, _ TrayIn
|
|||
}
|
||||
config, ok := result.(map[string]any)
|
||||
if !ok {
|
||||
return nil, TrayInfoOutput{}, fmt.Errorf("unexpected result type from tray config query")
|
||||
return nil, TrayInfoOutput{}, corego.E("mcp.trayInfo", "unexpected result type from tray config query", nil)
|
||||
}
|
||||
return nil, TrayInfoOutput{Config: config}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ package mcp
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"forge.lthn.ai/core/gui/pkg/webview"
|
||||
corego "dappco.re/go/core"
|
||||
"dappco.re/go/core/gui/pkg/webview"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
|
|
@ -105,7 +105,7 @@ func (s *Subsystem) webviewScreenshot(_ context.Context, _ *mcp.CallToolRequest,
|
|||
}
|
||||
sr, ok := result.(webview.ScreenshotResult)
|
||||
if !ok {
|
||||
return nil, WebviewScreenshotOutput{}, fmt.Errorf("unexpected result type from webview screenshot")
|
||||
return nil, WebviewScreenshotOutput{}, corego.E("mcp.webview", "unexpected result type from webview screenshot", nil)
|
||||
}
|
||||
return nil, WebviewScreenshotOutput{Base64: sr.Base64, MimeType: sr.MimeType}, nil
|
||||
}
|
||||
|
|
@ -129,7 +129,7 @@ func (s *Subsystem) webviewScreenshotElement(_ context.Context, _ *mcp.CallToolR
|
|||
}
|
||||
sr, ok := result.(webview.ScreenshotResult)
|
||||
if !ok {
|
||||
return nil, WebviewScreenshotElementOutput{}, fmt.Errorf("unexpected result type from webview element screenshot")
|
||||
return nil, WebviewScreenshotElementOutput{}, corego.E("mcp.webview", "unexpected result type from webview element screenshot", nil)
|
||||
}
|
||||
return nil, WebviewScreenshotElementOutput{Base64: sr.Base64, MimeType: sr.MimeType}, nil
|
||||
}
|
||||
|
|
@ -272,7 +272,7 @@ func (s *Subsystem) webviewConsole(_ context.Context, _ *mcp.CallToolRequest, in
|
|||
}
|
||||
msgs, ok := result.([]webview.ConsoleMessage)
|
||||
if !ok {
|
||||
return nil, WebviewConsoleOutput{}, fmt.Errorf("unexpected result type from webview console query")
|
||||
return nil, WebviewConsoleOutput{}, corego.E("mcp.webview", "unexpected result type from webview console query", nil)
|
||||
}
|
||||
return nil, WebviewConsoleOutput{Messages: msgs}, nil
|
||||
}
|
||||
|
|
@ -313,7 +313,7 @@ func (s *Subsystem) webviewErrors(_ context.Context, _ *mcp.CallToolRequest, inp
|
|||
}
|
||||
errors, ok := result.([]webview.ExceptionInfo)
|
||||
if !ok {
|
||||
return nil, WebviewErrorsOutput{}, fmt.Errorf("unexpected result type from webview errors query")
|
||||
return nil, WebviewErrorsOutput{}, corego.E("mcp.webview", "unexpected result type from webview errors query", nil)
|
||||
}
|
||||
return nil, WebviewErrorsOutput{Errors: errors}, nil
|
||||
}
|
||||
|
|
@ -370,7 +370,7 @@ func (s *Subsystem) webviewQuery(_ context.Context, _ *mcp.CallToolRequest, inpu
|
|||
}
|
||||
el, ok := result.(*webview.ElementInfo)
|
||||
if !ok {
|
||||
return nil, WebviewQueryOutput{}, fmt.Errorf("unexpected result type from webview query")
|
||||
return nil, WebviewQueryOutput{}, corego.E("mcp.webview", "unexpected result type from webview query", nil)
|
||||
}
|
||||
return nil, WebviewQueryOutput{Element: el}, nil
|
||||
}
|
||||
|
|
@ -399,7 +399,7 @@ func (s *Subsystem) webviewQueryAll(_ context.Context, _ *mcp.CallToolRequest, i
|
|||
}
|
||||
els, ok := result.([]*webview.ElementInfo)
|
||||
if !ok {
|
||||
return nil, WebviewQueryAllOutput{}, fmt.Errorf("unexpected result type from webview query all")
|
||||
return nil, WebviewQueryAllOutput{}, corego.E("mcp.webview", "unexpected result type from webview query all", nil)
|
||||
}
|
||||
return nil, WebviewQueryAllOutput{Elements: els}, nil
|
||||
}
|
||||
|
|
@ -422,7 +422,7 @@ func (s *Subsystem) webviewDOMTree(_ context.Context, _ *mcp.CallToolRequest, in
|
|||
}
|
||||
html, ok := result.(string)
|
||||
if !ok {
|
||||
return nil, WebviewDOMTreeOutput{}, fmt.Errorf("unexpected result type from webview DOM tree query")
|
||||
return nil, WebviewDOMTreeOutput{}, corego.E("mcp.webview", "unexpected result type from webview DOM tree query", nil)
|
||||
}
|
||||
return nil, WebviewDOMTreeOutput{HTML: html}, nil
|
||||
}
|
||||
|
|
@ -451,7 +451,7 @@ func (s *Subsystem) webviewComputedStyle(_ context.Context, _ *mcp.CallToolReque
|
|||
}
|
||||
style, ok := result.(map[string]string)
|
||||
if !ok {
|
||||
return nil, WebviewComputedStyleOutput{}, fmt.Errorf("unexpected result type from webview computed style query")
|
||||
return nil, WebviewComputedStyleOutput{}, corego.E("mcp.webview", "unexpected result type from webview computed style query", nil)
|
||||
}
|
||||
return nil, WebviewComputedStyleOutput{Style: style}, nil
|
||||
}
|
||||
|
|
@ -473,7 +473,7 @@ func (s *Subsystem) webviewPerformance(_ context.Context, _ *mcp.CallToolRequest
|
|||
}
|
||||
metrics, ok := result.(webview.PerformanceMetrics)
|
||||
if !ok {
|
||||
return nil, WebviewPerformanceOutput{}, fmt.Errorf("unexpected result type from webview performance query")
|
||||
return nil, WebviewPerformanceOutput{}, corego.E("mcp.webview", "unexpected result type from webview performance query", nil)
|
||||
}
|
||||
return nil, WebviewPerformanceOutput{Metrics: metrics}, nil
|
||||
}
|
||||
|
|
@ -495,7 +495,7 @@ func (s *Subsystem) webviewResources(_ context.Context, _ *mcp.CallToolRequest,
|
|||
}
|
||||
resources, ok := result.([]webview.ResourceEntry)
|
||||
if !ok {
|
||||
return nil, WebviewResourcesOutput{}, fmt.Errorf("unexpected result type from webview resources query")
|
||||
return nil, WebviewResourcesOutput{}, corego.E("mcp.webview", "unexpected result type from webview resources query", nil)
|
||||
}
|
||||
return nil, WebviewResourcesOutput{Resources: resources}, nil
|
||||
}
|
||||
|
|
@ -518,7 +518,7 @@ func (s *Subsystem) webviewNetwork(_ context.Context, _ *mcp.CallToolRequest, in
|
|||
}
|
||||
requests, ok := result.([]webview.NetworkEntry)
|
||||
if !ok {
|
||||
return nil, WebviewNetworkOutput{}, fmt.Errorf("unexpected result type from webview network query")
|
||||
return nil, WebviewNetworkOutput{}, corego.E("mcp.webview", "unexpected result type from webview network query", nil)
|
||||
}
|
||||
return nil, WebviewNetworkOutput{Requests: requests}, nil
|
||||
}
|
||||
|
|
@ -615,7 +615,7 @@ func (s *Subsystem) webviewPDF(_ context.Context, _ *mcp.CallToolRequest, input
|
|||
}
|
||||
pdf, ok := result.(webview.PDFResult)
|
||||
if !ok {
|
||||
return nil, WebviewPDFOutput{}, fmt.Errorf("unexpected result type from webview pdf task")
|
||||
return nil, WebviewPDFOutput{}, corego.E("mcp.webview", "unexpected result type from webview pdf task", nil)
|
||||
}
|
||||
return nil, WebviewPDFOutput{Base64: pdf.Base64, MimeType: pdf.MimeType}, nil
|
||||
}
|
||||
|
|
@ -637,7 +637,7 @@ func (s *Subsystem) webviewURL(_ context.Context, _ *mcp.CallToolRequest, input
|
|||
}
|
||||
url, ok := result.(string)
|
||||
if !ok {
|
||||
return nil, WebviewURLOutput{}, fmt.Errorf("unexpected result type from webview URL query")
|
||||
return nil, WebviewURLOutput{}, corego.E("mcp.webview", "unexpected result type from webview URL query", nil)
|
||||
}
|
||||
return nil, WebviewURLOutput{URL: url}, nil
|
||||
}
|
||||
|
|
@ -659,7 +659,7 @@ func (s *Subsystem) webviewTitle(_ context.Context, _ *mcp.CallToolRequest, inpu
|
|||
}
|
||||
title, ok := result.(string)
|
||||
if !ok {
|
||||
return nil, WebviewTitleOutput{}, fmt.Errorf("unexpected result type from webview title query")
|
||||
return nil, WebviewTitleOutput{}, corego.E("mcp.webview", "unexpected result type from webview title query", nil)
|
||||
}
|
||||
return nil, WebviewTitleOutput{Title: title}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ package mcp
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"forge.lthn.ai/core/gui/pkg/window"
|
||||
corego "dappco.re/go/core"
|
||||
"dappco.re/go/core/gui/pkg/window"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ func (s *Subsystem) windowList(_ context.Context, _ *mcp.CallToolRequest, _ Wind
|
|||
}
|
||||
windows, ok := result.([]window.WindowInfo)
|
||||
if !ok {
|
||||
return nil, WindowListOutput{}, fmt.Errorf("unexpected result type from window list query")
|
||||
return nil, WindowListOutput{}, corego.E("mcp.window", "unexpected result type from window list query", nil)
|
||||
}
|
||||
return nil, WindowListOutput{Windows: windows}, nil
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ func (s *Subsystem) windowGet(_ context.Context, _ *mcp.CallToolRequest, input W
|
|||
}
|
||||
info, ok := result.(*window.WindowInfo)
|
||||
if !ok {
|
||||
return nil, WindowGetOutput{}, fmt.Errorf("unexpected result type from window get query")
|
||||
return nil, WindowGetOutput{}, corego.E("mcp.window", "unexpected result type from window get query", nil)
|
||||
}
|
||||
return nil, WindowGetOutput{Window: info}, nil
|
||||
}
|
||||
|
|
@ -63,7 +63,7 @@ func (s *Subsystem) windowFocused(_ context.Context, _ *mcp.CallToolRequest, _ W
|
|||
}
|
||||
windows, ok := result.([]window.WindowInfo)
|
||||
if !ok {
|
||||
return nil, WindowFocusedOutput{}, fmt.Errorf("unexpected result type from window list query")
|
||||
return nil, WindowFocusedOutput{}, corego.E("mcp.window", "unexpected result type from window list query", nil)
|
||||
}
|
||||
for _, w := range windows {
|
||||
if w.Focused {
|
||||
|
|
@ -105,7 +105,7 @@ func (s *Subsystem) windowCreate(_ context.Context, _ *mcp.CallToolRequest, inpu
|
|||
}
|
||||
info, ok := result.(window.WindowInfo)
|
||||
if !ok {
|
||||
return nil, WindowCreateOutput{}, fmt.Errorf("unexpected result type from window create task")
|
||||
return nil, WindowCreateOutput{}, corego.E("mcp.window", "unexpected result type from window create task", nil)
|
||||
}
|
||||
return nil, WindowCreateOutput{Window: info}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ package notification
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
corego "dappco.re/go/core"
|
||||
"dappco.re/go/core/gui/pkg/dialog"
|
||||
"forge.lthn.ai/core/go/pkg/core"
|
||||
"forge.lthn.ai/core/gui/pkg/dialog"
|
||||
)
|
||||
|
||||
// Options configures the notification service.
|
||||
|
|
@ -76,7 +76,7 @@ func (s *Service) handleTask(c *core.Core, t core.Task) (any, bool, error) {
|
|||
func (s *Service) sendNotification(opts NotificationOptions) error {
|
||||
// Generate an ID when the caller does not provide one.
|
||||
if opts.ID == "" {
|
||||
opts.ID = fmt.Sprintf("core-%d", time.Now().UnixNano())
|
||||
opts.ID = corego.Sprintf("core-%d", time.Now().UnixNano())
|
||||
}
|
||||
|
||||
if len(opts.Actions) > 0 {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go/pkg/core"
|
||||
"forge.lthn.ai/core/gui/pkg/dialog"
|
||||
"dappco.re/go/core/gui/pkg/dialog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"context"
|
||||
|
||||
"forge.lthn.ai/core/go/pkg/core"
|
||||
"forge.lthn.ai/core/gui/pkg/notification"
|
||||
"dappco.re/go/core/gui/pkg/notification"
|
||||
)
|
||||
|
||||
// Options configures the systray service.
|
||||
|
|
|
|||
|
|
@ -2,19 +2,16 @@
|
|||
package webview
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
corego "dappco.re/go/core"
|
||||
)
|
||||
|
||||
func jsQuote(v string) string {
|
||||
b, _ := json.Marshal(v)
|
||||
return string(b)
|
||||
return corego.JSONMarshalString(v)
|
||||
}
|
||||
|
||||
func computedStyleScript(selector string) string {
|
||||
sel := jsQuote(selector)
|
||||
return fmt.Sprintf(`(function(){
|
||||
return corego.Sprintf(`(function(){
|
||||
const el = document.querySelector(%s);
|
||||
if (!el) return null;
|
||||
const style = window.getComputedStyle(el);
|
||||
|
|
@ -33,7 +30,7 @@ func highlightScript(selector, colour string) string {
|
|||
colour = "#ff9800"
|
||||
}
|
||||
col := jsQuote(colour)
|
||||
return fmt.Sprintf(`(function(){
|
||||
return corego.Sprintf(`(function(){
|
||||
const el = document.querySelector(%s);
|
||||
if (!el) return false;
|
||||
if (el.__coreHighlightOrigOutline === undefined) {
|
||||
|
|
@ -150,9 +147,9 @@ func networkLogScript(limit int) string {
|
|||
if limit <= 0 {
|
||||
return `(window.__coreNetworkLog || [])`
|
||||
}
|
||||
return fmt.Sprintf(`(window.__coreNetworkLog || []).slice(-%d)`, limit)
|
||||
return corego.Sprintf(`(window.__coreNetworkLog || []).slice(-%d)`, limit)
|
||||
}
|
||||
|
||||
func normalizeWhitespace(s string) string {
|
||||
return strings.TrimSpace(s)
|
||||
return corego.Trim(s)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,22 +5,20 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/draw"
|
||||
"image/png"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
corego "dappco.re/go/core"
|
||||
"dappco.re/go/core/gui/pkg/window"
|
||||
gowebview "forge.lthn.ai/core/go-webview"
|
||||
"forge.lthn.ai/core/go/pkg/core"
|
||||
"forge.lthn.ai/core/gui/pkg/window"
|
||||
)
|
||||
|
||||
// connector abstracts go-webview for testing. The real implementation wraps
|
||||
|
|
@ -108,7 +106,7 @@ func defaultNewConn(opts Options) func(string, string) (connector, error) {
|
|||
}
|
||||
var wsURL string
|
||||
for _, t := range targets {
|
||||
if t.Type == "page" && (strings.Contains(t.Title, windowName) || strings.Contains(t.URL, windowName)) {
|
||||
if t.Type == "page" && (corego.Contains(t.Title, windowName) || corego.Contains(t.URL, windowName)) {
|
||||
wsURL = t.WebSocketDebuggerURL
|
||||
break
|
||||
}
|
||||
|
|
@ -473,7 +471,7 @@ func (s *Service) handleTask(_ *core.Core, t core.Task) (any, bool, error) {
|
|||
}
|
||||
pw, ok := ws.Manager().Get(t.Window)
|
||||
if !ok {
|
||||
return nil, true, fmt.Errorf("window not found: %s", t.Window)
|
||||
return nil, true, corego.E("webview", corego.Sprintf("window not found: %s", t.Window), nil)
|
||||
}
|
||||
pw.OpenDevTools()
|
||||
return nil, true, nil
|
||||
|
|
@ -484,7 +482,7 @@ func (s *Service) handleTask(_ *core.Core, t core.Task) (any, bool, error) {
|
|||
}
|
||||
pw, ok := ws.Manager().Get(t.Window)
|
||||
if !ok {
|
||||
return nil, true, fmt.Errorf("window not found: %s", t.Window)
|
||||
return nil, true, corego.E("webview", corego.Sprintf("window not found: %s", t.Window), nil)
|
||||
}
|
||||
pw.CloseDevTools()
|
||||
return nil, true, nil
|
||||
|
|
@ -550,12 +548,13 @@ func (s *Service) queryExceptions(windowName string, limit int) []ExceptionInfo
|
|||
|
||||
func coerceJSON[T any](v any) (T, error) {
|
||||
var out T
|
||||
raw, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return out, err
|
||||
r := corego.JSONMarshal(v)
|
||||
if !r.OK {
|
||||
return out, r.Value.(error)
|
||||
}
|
||||
if err := json.Unmarshal(raw, &out); err != nil {
|
||||
return out, err
|
||||
r2 := corego.JSONUnmarshal(r.Value.([]byte), &out)
|
||||
if !r2.OK {
|
||||
return out, r2.Value.(error)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
|
@ -586,7 +585,7 @@ type elementScreenshotBounds struct {
|
|||
|
||||
func elementScreenshotScript(selector string) string {
|
||||
sel := jsQuote(selector)
|
||||
return fmt.Sprintf(`(function(){
|
||||
return corego.Sprintf(`(function(){
|
||||
const el = document.querySelector(%s);
|
||||
if (!el) return null;
|
||||
try { el.scrollIntoView({block: "center", inline: "center"}); } catch (e) {}
|
||||
|
|
@ -607,14 +606,14 @@ func captureElementScreenshot(conn connector, selector string) ([]byte, error) {
|
|||
return nil, err
|
||||
}
|
||||
if result == nil {
|
||||
return nil, fmt.Errorf("webview: element not found: %s", selector)
|
||||
return nil, corego.E("webview", corego.Sprintf("element not found: %s", selector), nil)
|
||||
}
|
||||
bounds, err := coerceJSON[elementScreenshotBounds](result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if bounds.Width <= 0 || bounds.Height <= 0 {
|
||||
return nil, fmt.Errorf("webview: element has no measurable bounds: %s", selector)
|
||||
return nil, corego.E("webview", corego.Sprintf("element has no measurable bounds: %s", selector), nil)
|
||||
}
|
||||
raw, err := conn.Screenshot()
|
||||
if err != nil {
|
||||
|
|
@ -648,7 +647,7 @@ func captureElementScreenshot(conn connector, selector string) ([]byte, error) {
|
|||
bottom = srcBounds.Max.Y
|
||||
}
|
||||
if right <= left || bottom <= top {
|
||||
return nil, fmt.Errorf("webview: element is outside the captured screenshot: %s", selector)
|
||||
return nil, corego.E("webview", corego.Sprintf("element is outside the captured screenshot: %s", selector), nil)
|
||||
}
|
||||
|
||||
crop := image.NewRGBA(image.Rect(0, 0, right-left, bottom-top))
|
||||
|
|
@ -695,7 +694,7 @@ func (r *realConnector) PrintToPDF() ([]byte, error) {
|
|||
}
|
||||
data, ok := result["data"].(string)
|
||||
if !ok || data == "" {
|
||||
return nil, fmt.Errorf("webview: missing PDF data")
|
||||
return nil, corego.E("webview", "missing PDF data", nil)
|
||||
}
|
||||
return base64.StdEncoding.DecodeString(data)
|
||||
}
|
||||
|
|
@ -703,17 +702,17 @@ func (r *realConnector) PrintToPDF() ([]byte, error) {
|
|||
func (r *realConnector) cdpClient() (*gowebview.CDPClient, error) {
|
||||
rv := reflect.ValueOf(r.wv)
|
||||
if rv.Kind() != reflect.Ptr || rv.IsNil() {
|
||||
return nil, fmt.Errorf("webview: invalid connector")
|
||||
return nil, corego.E("webview", "invalid connector", nil)
|
||||
}
|
||||
elem := rv.Elem()
|
||||
field := elem.FieldByName("client")
|
||||
if !field.IsValid() || field.IsNil() {
|
||||
return nil, fmt.Errorf("webview: CDP client not available")
|
||||
return nil, corego.E("webview", "CDP client not available", nil)
|
||||
}
|
||||
ptr := reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface()
|
||||
client, ok := ptr.(*gowebview.CDPClient)
|
||||
if !ok || client == nil {
|
||||
return nil, fmt.Errorf("webview: unexpected CDP client type")
|
||||
return nil, corego.E("webview", "unexpected CDP client type", nil)
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go/pkg/core"
|
||||
"forge.lthn.ai/core/gui/pkg/window"
|
||||
"dappco.re/go/core/gui/pkg/window"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,12 +2,11 @@
|
|||
package window
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
corego "dappco.re/go/core"
|
||||
)
|
||||
|
||||
// Layout is a named window arrangement.
|
||||
|
|
@ -44,7 +43,7 @@ func NewLayoutManager() *LayoutManager {
|
|||
}
|
||||
configDir, err := os.UserConfigDir()
|
||||
if err == nil {
|
||||
lm.configDir = filepath.Join(configDir, "Core")
|
||||
lm.configDir = corego.JoinPath(configDir, "Core")
|
||||
}
|
||||
lm.loadLayouts()
|
||||
return lm
|
||||
|
|
@ -63,7 +62,7 @@ func NewLayoutManagerWithDir(configDir string) *LayoutManager {
|
|||
}
|
||||
|
||||
func (lm *LayoutManager) layoutsFilePath() string {
|
||||
return filepath.Join(lm.configDir, "layouts.json")
|
||||
return corego.JoinPath(lm.configDir, "layouts.json")
|
||||
}
|
||||
|
||||
func (lm *LayoutManager) loadLayouts() {
|
||||
|
|
@ -76,7 +75,7 @@ func (lm *LayoutManager) loadLayouts() {
|
|||
}
|
||||
lm.mu.Lock()
|
||||
defer lm.mu.Unlock()
|
||||
_ = json.Unmarshal(data, &lm.layouts)
|
||||
_ = corego.JSONUnmarshal(data, &lm.layouts)
|
||||
}
|
||||
|
||||
func (lm *LayoutManager) saveLayouts() {
|
||||
|
|
@ -84,20 +83,20 @@ func (lm *LayoutManager) saveLayouts() {
|
|||
return
|
||||
}
|
||||
lm.mu.RLock()
|
||||
data, err := json.MarshalIndent(lm.layouts, "", " ")
|
||||
r := corego.JSONMarshal(lm.layouts)
|
||||
lm.mu.RUnlock()
|
||||
if err != nil {
|
||||
if !r.OK {
|
||||
return
|
||||
}
|
||||
_ = os.MkdirAll(lm.configDir, 0o755)
|
||||
_ = os.WriteFile(lm.layoutsFilePath(), data, 0o644)
|
||||
_ = os.WriteFile(lm.layoutsFilePath(), r.Value.([]byte), 0o644)
|
||||
}
|
||||
|
||||
// SaveLayout creates or updates a named layout.
|
||||
// Use: _ = lm.SaveLayout("coding", windowStates)
|
||||
func (lm *LayoutManager) SaveLayout(name string, windowStates map[string]WindowState) error {
|
||||
if name == "" {
|
||||
return fmt.Errorf("layout name cannot be empty")
|
||||
return corego.E("layout.save", "layout name cannot be empty", nil)
|
||||
}
|
||||
now := time.Now().UnixMilli()
|
||||
lm.mu.Lock()
|
||||
|
|
|
|||
|
|
@ -3,11 +3,10 @@ package window
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
corego "dappco.re/go/core"
|
||||
"dappco.re/go/core/gui/pkg/screen"
|
||||
"forge.lthn.ai/core/go/pkg/core"
|
||||
"forge.lthn.ai/core/gui/pkg/screen"
|
||||
)
|
||||
|
||||
// Options holds configuration for the window service.
|
||||
|
|
@ -280,7 +279,7 @@ func (s *Service) trackWindow(pw PlatformWindow) {
|
|||
func (s *Service) taskCloseWindow(name string) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window not found: %s", name)
|
||||
return corego.E("window.service", corego.Sprintf("window not found: %s", name), nil)
|
||||
}
|
||||
// Persist state BEFORE closing (spec requirement)
|
||||
s.manager.State().CaptureState(pw)
|
||||
|
|
@ -292,7 +291,7 @@ func (s *Service) taskCloseWindow(name string) error {
|
|||
func (s *Service) taskSetPosition(name string, x, y int) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window not found: %s", name)
|
||||
return corego.E("window.service", corego.Sprintf("window not found: %s", name), nil)
|
||||
}
|
||||
pw.SetPosition(x, y)
|
||||
s.manager.State().UpdatePosition(name, x, y)
|
||||
|
|
@ -302,7 +301,7 @@ func (s *Service) taskSetPosition(name string, x, y int) error {
|
|||
func (s *Service) taskSetSize(name string, width, height, fallbackWidth, fallbackHeight int) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window not found: %s", name)
|
||||
return corego.E("window.service", corego.Sprintf("window not found: %s", name), nil)
|
||||
}
|
||||
if width == 0 && height == 0 {
|
||||
width, height = fallbackWidth, fallbackHeight
|
||||
|
|
@ -322,7 +321,7 @@ func (s *Service) taskSetSize(name string, width, height, fallbackWidth, fallbac
|
|||
func (s *Service) taskMaximise(name string) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window not found: %s", name)
|
||||
return corego.E("window.service", corego.Sprintf("window not found: %s", name), nil)
|
||||
}
|
||||
pw.Maximise()
|
||||
s.manager.State().UpdateMaximized(name, true)
|
||||
|
|
@ -332,7 +331,7 @@ func (s *Service) taskMaximise(name string) error {
|
|||
func (s *Service) taskMinimise(name string) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window not found: %s", name)
|
||||
return corego.E("window.service", corego.Sprintf("window not found: %s", name), nil)
|
||||
}
|
||||
pw.Minimise()
|
||||
return nil
|
||||
|
|
@ -341,7 +340,7 @@ func (s *Service) taskMinimise(name string) error {
|
|||
func (s *Service) taskFocus(name string) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window not found: %s", name)
|
||||
return corego.E("window.service", corego.Sprintf("window not found: %s", name), nil)
|
||||
}
|
||||
pw.Focus()
|
||||
return nil
|
||||
|
|
@ -350,7 +349,7 @@ func (s *Service) taskFocus(name string) error {
|
|||
func (s *Service) taskRestore(name string) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window not found: %s", name)
|
||||
return corego.E("window.service", corego.Sprintf("window not found: %s", name), nil)
|
||||
}
|
||||
pw.Restore()
|
||||
s.manager.State().UpdateMaximized(name, false)
|
||||
|
|
@ -360,7 +359,7 @@ func (s *Service) taskRestore(name string) error {
|
|||
func (s *Service) taskSetTitle(name, title string) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window not found: %s", name)
|
||||
return corego.E("window.service", corego.Sprintf("window not found: %s", name), nil)
|
||||
}
|
||||
pw.SetTitle(title)
|
||||
return nil
|
||||
|
|
@ -369,7 +368,7 @@ func (s *Service) taskSetTitle(name, title string) error {
|
|||
func (s *Service) taskSetAlwaysOnTop(name string, alwaysOnTop bool) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window not found: %s", name)
|
||||
return corego.E("window.service", corego.Sprintf("window not found: %s", name), nil)
|
||||
}
|
||||
pw.SetAlwaysOnTop(alwaysOnTop)
|
||||
return nil
|
||||
|
|
@ -378,7 +377,7 @@ func (s *Service) taskSetAlwaysOnTop(name string, alwaysOnTop bool) error {
|
|||
func (s *Service) taskSetBackgroundColour(name string, red, green, blue, alpha uint8) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window not found: %s", name)
|
||||
return corego.E("window.service", corego.Sprintf("window not found: %s", name), nil)
|
||||
}
|
||||
pw.SetBackgroundColour(red, green, blue, alpha)
|
||||
return nil
|
||||
|
|
@ -386,11 +385,11 @@ func (s *Service) taskSetBackgroundColour(name string, red, green, blue, alpha u
|
|||
|
||||
func (s *Service) taskSetOpacity(name string, opacity float32) error {
|
||||
if opacity < 0 || opacity > 1 {
|
||||
return fmt.Errorf("opacity must be between 0 and 1")
|
||||
return corego.E("window.setOpacity", "opacity must be between 0 and 1", nil)
|
||||
}
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window not found: %s", name)
|
||||
return corego.E("window.service", corego.Sprintf("window not found: %s", name), nil)
|
||||
}
|
||||
pw.SetOpacity(opacity)
|
||||
return nil
|
||||
|
|
@ -399,7 +398,7 @@ func (s *Service) taskSetOpacity(name string, opacity float32) error {
|
|||
func (s *Service) taskSetVisibility(name string, visible bool) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window not found: %s", name)
|
||||
return corego.E("window.service", corego.Sprintf("window not found: %s", name), nil)
|
||||
}
|
||||
pw.SetVisibility(visible)
|
||||
return nil
|
||||
|
|
@ -408,7 +407,7 @@ func (s *Service) taskSetVisibility(name string, visible bool) error {
|
|||
func (s *Service) taskFullscreen(name string, fullscreen bool) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window not found: %s", name)
|
||||
return corego.E("window.service", corego.Sprintf("window not found: %s", name), nil)
|
||||
}
|
||||
if fullscreen {
|
||||
pw.Fullscreen()
|
||||
|
|
@ -433,7 +432,7 @@ func (s *Service) taskSaveLayout(name string) error {
|
|||
func (s *Service) taskRestoreLayout(name string) error {
|
||||
layout, ok := s.manager.Layout().GetLayout(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("layout not found: %s", name)
|
||||
return corego.E("window.restoreLayout", corego.Sprintf("layout not found: %s", name), nil)
|
||||
}
|
||||
for winName, state := range layout.Windows {
|
||||
pw, found := s.manager.Get(winName)
|
||||
|
|
@ -465,7 +464,7 @@ var tileModeMap = map[string]TileMode{
|
|||
func (s *Service) taskTileWindows(mode string, names []string) error {
|
||||
tm, ok := tileModeMap[mode]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown tile mode: %s", mode)
|
||||
return corego.E("window.tileWindows", corego.Sprintf("unknown tile mode: %s", mode), nil)
|
||||
}
|
||||
if len(names) == 0 {
|
||||
names = s.manager.List()
|
||||
|
|
@ -485,7 +484,7 @@ var snapPosMap = map[string]SnapPosition{
|
|||
func (s *Service) taskSnapWindow(name, position string) error {
|
||||
pos, ok := snapPosMap[position]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown snap position: %s", position)
|
||||
return corego.E("window.snapWindow", corego.Sprintf("unknown snap position: %s", position), nil)
|
||||
}
|
||||
screenW, screenH := s.primaryScreenSize()
|
||||
return s.manager.SnapWindow(name, pos, screenW, screenH)
|
||||
|
|
@ -502,13 +501,13 @@ func (s *Service) taskBesideEditor(editorName, windowName string) error {
|
|||
editorName = s.detectEditorWindow()
|
||||
}
|
||||
if editorName == "" {
|
||||
return fmt.Errorf("editor window not found")
|
||||
return corego.E("window.besideEditor", "editor window not found", nil)
|
||||
}
|
||||
if windowName == "" {
|
||||
windowName = s.detectCompanionWindow(editorName)
|
||||
}
|
||||
if windowName == "" {
|
||||
return fmt.Errorf("companion window not found")
|
||||
return corego.E("window.besideEditor", "companion window not found", nil)
|
||||
}
|
||||
return s.manager.BesideEditor(editorName, windowName, screenW, screenH)
|
||||
}
|
||||
|
|
@ -554,9 +553,9 @@ func looksLikeEditor(name, title string) bool {
|
|||
}
|
||||
|
||||
func containsAny(value string, needles ...string) bool {
|
||||
lower := strings.ToLower(value)
|
||||
lower := corego.Lower(value)
|
||||
for _, needle := range needles {
|
||||
if strings.Contains(lower, needle) {
|
||||
if corego.Contains(lower, needle) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go/pkg/core"
|
||||
"forge.lthn.ai/core/gui/pkg/screen"
|
||||
"dappco.re/go/core/gui/pkg/screen"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
package window
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
corego "dappco.re/go/core"
|
||||
)
|
||||
|
||||
// WindowState holds the persisted position/size of a window.
|
||||
|
|
@ -41,7 +41,7 @@ func NewStateManager() *StateManager {
|
|||
}
|
||||
configDir, err := os.UserConfigDir()
|
||||
if err == nil {
|
||||
sm.configDir = filepath.Join(configDir, "Core")
|
||||
sm.configDir = corego.JoinPath(configDir, "Core")
|
||||
}
|
||||
sm.load()
|
||||
return sm
|
||||
|
|
@ -63,12 +63,12 @@ func (sm *StateManager) filePath() string {
|
|||
if sm.statePath != "" {
|
||||
return sm.statePath
|
||||
}
|
||||
return filepath.Join(sm.configDir, "window_state.json")
|
||||
return corego.JoinPath(sm.configDir, "window_state.json")
|
||||
}
|
||||
|
||||
func (sm *StateManager) dataDir() string {
|
||||
if sm.statePath != "" {
|
||||
return filepath.Dir(sm.statePath)
|
||||
return corego.PathDir(sm.statePath)
|
||||
}
|
||||
return sm.configDir
|
||||
}
|
||||
|
|
@ -100,7 +100,7 @@ func (sm *StateManager) load() {
|
|||
}
|
||||
sm.mu.Lock()
|
||||
defer sm.mu.Unlock()
|
||||
_ = json.Unmarshal(data, &sm.states)
|
||||
_ = corego.JSONUnmarshal(data, &sm.states)
|
||||
}
|
||||
|
||||
func (sm *StateManager) save() {
|
||||
|
|
@ -108,11 +108,12 @@ func (sm *StateManager) save() {
|
|||
return
|
||||
}
|
||||
sm.mu.RLock()
|
||||
data, err := json.MarshalIndent(sm.states, "", " ")
|
||||
r := corego.JSONMarshal(sm.states)
|
||||
sm.mu.RUnlock()
|
||||
if err != nil {
|
||||
if !r.OK {
|
||||
return
|
||||
}
|
||||
data := r.Value.([]byte)
|
||||
_ = os.MkdirAll(sm.dataDir(), 0o755)
|
||||
_ = os.WriteFile(sm.filePath(), data, 0o644)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// pkg/window/tiling.go
|
||||
package window
|
||||
|
||||
import "fmt"
|
||||
import corego "dappco.re/go/core"
|
||||
|
||||
// normalizeWindowForLayout clears transient maximise/minimise state before
|
||||
// applying a new geometry. This keeps layout helpers effective even when a
|
||||
|
|
@ -97,12 +97,12 @@ func (m *Manager) TileWindows(mode TileMode, names []string, screenW, screenH in
|
|||
for _, name := range names {
|
||||
pw, ok := m.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window %q not found", name)
|
||||
return corego.E("window.tiling", corego.Sprintf("window %q not found", name), nil)
|
||||
}
|
||||
windows = append(windows, pw)
|
||||
}
|
||||
if len(windows) == 0 {
|
||||
return fmt.Errorf("no windows to tile")
|
||||
return corego.E("window.tiling", "no windows to tile", nil)
|
||||
}
|
||||
|
||||
halfW, halfH := screenW/2, screenH/2
|
||||
|
|
@ -186,7 +186,7 @@ func (m *Manager) TileWindows(mode TileMode, names []string, screenW, screenH in
|
|||
func (m *Manager) SnapWindow(name string, pos SnapPosition, screenW, screenH int) error {
|
||||
pw, ok := m.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window %q not found", name)
|
||||
return corego.E("window.tiling", corego.Sprintf("window %q not found", name), nil)
|
||||
}
|
||||
|
||||
halfW, halfH := screenW/2, screenH/2
|
||||
|
|
@ -237,7 +237,7 @@ func (m *Manager) StackWindows(names []string, offsetX, offsetY int) error {
|
|||
for i, name := range names {
|
||||
pw, ok := m.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("window %q not found", name)
|
||||
return corego.E("window.tiling", corego.Sprintf("window %q not found", name), nil)
|
||||
}
|
||||
normalizeWindowForLayout(pw)
|
||||
pw.SetPosition(i*offsetX, i*offsetY)
|
||||
|
|
@ -248,7 +248,7 @@ func (m *Manager) StackWindows(names []string, offsetX, offsetY int) error {
|
|||
// ApplyWorkflow arranges windows in a predefined workflow layout.
|
||||
func (m *Manager) ApplyWorkflow(workflow WorkflowLayout, names []string, screenW, screenH int) error {
|
||||
if len(names) == 0 {
|
||||
return fmt.Errorf("no windows for workflow")
|
||||
return corego.E("window.tiling", "no windows for workflow", nil)
|
||||
}
|
||||
|
||||
switch workflow {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@
|
|||
package window
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
corego "dappco.re/go/core"
|
||||
)
|
||||
|
||||
// Window is CoreGUI's own window descriptor — NOT a Wails type alias.
|
||||
|
|
@ -94,7 +95,7 @@ func (m *Manager) SetDefaultHeight(height int) {
|
|||
func (m *Manager) Open(opts ...WindowOption) (PlatformWindow, error) {
|
||||
w, err := ApplyOptions(opts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("window.Manager.Open: %w", err)
|
||||
return nil, corego.Wrap(err, "window.Manager.Open", "failed to apply options")
|
||||
}
|
||||
return m.Create(w)
|
||||
}
|
||||
|
|
@ -288,11 +289,11 @@ func (m *Manager) FindSpace(screenW, screenH, width, height int) SpaceInfo {
|
|||
func (m *Manager) ArrangePair(first, second string, screenW, screenH int) error {
|
||||
left, ok := m.Get(first)
|
||||
if !ok {
|
||||
return fmt.Errorf("window %q not found", first)
|
||||
return corego.E("window.ArrangePair", corego.Sprintf("window %q not found", first), nil)
|
||||
}
|
||||
right, ok := m.Get(second)
|
||||
if !ok {
|
||||
return fmt.Errorf("window %q not found", second)
|
||||
return corego.E("window.ArrangePair", corego.Sprintf("window %q not found", second), nil)
|
||||
}
|
||||
|
||||
leftW := screenW / 2
|
||||
|
|
@ -309,11 +310,11 @@ func (m *Manager) ArrangePair(first, second string, screenW, screenH int) error
|
|||
func (m *Manager) BesideEditor(editorName, windowName string, screenW, screenH int) error {
|
||||
editor, ok := m.Get(editorName)
|
||||
if !ok {
|
||||
return fmt.Errorf("window %q not found", editorName)
|
||||
return corego.E("window.BesideEditor", corego.Sprintf("window %q not found", editorName), nil)
|
||||
}
|
||||
target, ok := m.Get(windowName)
|
||||
if !ok {
|
||||
return fmt.Errorf("window %q not found", windowName)
|
||||
return corego.E("window.BesideEditor", corego.Sprintf("window %q not found", windowName), nil)
|
||||
}
|
||||
|
||||
editorW := screenW * 70 / 100
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue