From 07bc116abd572edbf78614cb59bf7ddab6a7cf3b Mon Sep 17 00:00:00 2001 From: Snider Date: Fri, 13 Mar 2026 14:52:38 +0000 Subject: [PATCH] feat(display): add contextmenu integration and ActionIDECommand to orchestrator Add HandleIPCEvents cases for contextmenu.ActionItemClicked and ActionIDECommand, WS->IPC bridge cases for contextmenu:add/remove/get/list, EventContextMenuClick and EventIDECommand constants. Co-Authored-By: Claude Opus 4.6 --- pkg/display/display.go | 33 +++++++++++++++++++++++++++++++++ pkg/display/events.go | 1 + pkg/display/messages.go | 12 ++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 pkg/display/messages.go diff --git a/pkg/display/display.go b/pkg/display/display.go index 5707eef..6b1de86 100644 --- a/pkg/display/display.go +++ b/pkg/display/display.go @@ -9,7 +9,10 @@ import ( "forge.lthn.ai/core/go-config" "forge.lthn.ai/core/go/pkg/core" + "encoding/json" + "forge.lthn.ai/core/gui/pkg/browser" + "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" @@ -199,6 +202,20 @@ func (s *Service) HandleIPCEvents(c *core.Core, msg core.Message) error { if s.events != nil { s.events.Emit(Event{Type: EventSystemResume}) } + case contextmenu.ActionItemClicked: + if s.events != nil { + s.events.Emit(Event{Type: EventContextMenuClick, + Data: map[string]any{ + "menuName": m.MenuName, + "actionId": m.ActionID, + "data": m.Data, + }}) + } + case ActionIDECommand: + if s.events != nil { + s.events.Emit(Event{Type: EventIDECommand, + Data: map[string]any{"command": m.Command}}) + } } return nil } @@ -246,6 +263,22 @@ func (s *Service) handleWSMessage(msg WSMessage) (any, bool, error) { result, handled, err = s.Core().PERFORM(dock.TaskRemoveBadge{}) case "dock:visible": result, handled, err = s.Core().QUERY(dock.QueryVisible{}) + case "contextmenu:add": + name, _ := msg.Data["name"].(string) + menuJSON, _ := json.Marshal(msg.Data["menu"]) + var menuDef contextmenu.ContextMenuDef + _ = json.Unmarshal(menuJSON, &menuDef) + result, handled, err = s.Core().PERFORM(contextmenu.TaskAdd{ + Name: name, Menu: menuDef, + }) + case "contextmenu:remove": + name, _ := msg.Data["name"].(string) + result, handled, err = s.Core().PERFORM(contextmenu.TaskRemove{Name: name}) + case "contextmenu:get": + name, _ := msg.Data["name"].(string) + result, handled, err = s.Core().QUERY(contextmenu.QueryGet{Name: name}) + case "contextmenu:list": + result, handled, err = s.Core().QUERY(contextmenu.QueryList{}) default: return nil, false, nil } diff --git a/pkg/display/events.go b/pkg/display/events.go index 52f5987..d95c74c 100644 --- a/pkg/display/events.go +++ b/pkg/display/events.go @@ -37,6 +37,7 @@ const ( EventSystemPowerChange EventType = "system.power-change" EventSystemSuspend EventType = "system.suspend" EventSystemResume EventType = "system.resume" + EventContextMenuClick EventType = "contextmenu.item-clicked" ) // Event represents a display event sent to subscribers. diff --git a/pkg/display/messages.go b/pkg/display/messages.go new file mode 100644 index 0000000..43d4e3f --- /dev/null +++ b/pkg/display/messages.go @@ -0,0 +1,12 @@ +// pkg/display/messages.go +package display + +// ActionIDECommand is broadcast when a menu handler triggers an IDE command +// (save, run, build). Replaces direct s.app.Event().Emit("ide:*") calls. +// Listeners (e.g. editor windows) handle this via HandleIPCEvents. +type ActionIDECommand struct { + Command string `json:"command"` // "save", "run", "build" +} + +// EventIDECommand is the WS event type for IDE commands. +const EventIDECommand EventType = "ide.command"