refactor: AX compliance sweep — replace banned stdlib imports with core primitives
Some checks failed
Security Scan / security (push) Has been cancelled
Test / test (push) Has been cancelled

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:
Snider 2026-04-13 09:32:01 +01:00
parent 873eafe7b6
commit 62ec735c10
36 changed files with 324 additions and 312 deletions

2
go.sum
View file

@ -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=

View file

@ -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 ---

View file

@ -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)

View file

@ -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
}

View file

@ -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"
)

View file

@ -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.

View file

@ -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 {

View file

@ -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 {

View file

@ -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)

View file

@ -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"

View file

@ -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"
)

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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"
)

View file

@ -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
}

View file

@ -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"
)

View file

@ -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,

View file

@ -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"
)

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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 {

View file

@ -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"
)

View file

@ -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.

View file

@ -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)
}

View file

@ -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
}

View file

@ -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"
)

View file

@ -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()

View file

@ -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
}
}

View file

@ -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"
)

View file

@ -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)
}

View file

@ -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 {

View file

@ -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