2026-02-16 13:55:59 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
"context"
|
2026-02-16 13:55:59 +00:00
|
|
|
"embed"
|
|
|
|
|
"io/fs"
|
|
|
|
|
"log"
|
2026-03-14 09:47:59 +00:00
|
|
|
"net/http"
|
2026-02-16 13:55:59 +00:00
|
|
|
"os"
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
"os/signal"
|
2026-02-16 13:55:59 +00:00
|
|
|
"runtime"
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
"syscall"
|
2026-02-16 13:55:59 +00:00
|
|
|
|
2026-03-14 10:10:36 +00:00
|
|
|
"forge.lthn.ai/core/api"
|
|
|
|
|
"forge.lthn.ai/core/api/pkg/provider"
|
2026-03-14 10:28:39 +00:00
|
|
|
"forge.lthn.ai/core/config"
|
2026-03-14 09:47:59 +00:00
|
|
|
process "forge.lthn.ai/core/go-process"
|
|
|
|
|
processapi "forge.lthn.ai/core/go-process/pkg/api"
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
"forge.lthn.ai/core/go-ws"
|
|
|
|
|
"forge.lthn.ai/core/go/pkg/core"
|
|
|
|
|
guiMCP "forge.lthn.ai/core/gui/pkg/mcp"
|
|
|
|
|
"forge.lthn.ai/core/gui/pkg/display"
|
2026-02-16 14:22:26 +00:00
|
|
|
"forge.lthn.ai/core/ide/icons"
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
"forge.lthn.ai/core/mcp/pkg/mcp"
|
|
|
|
|
"forge.lthn.ai/core/mcp/pkg/mcp/brain"
|
|
|
|
|
"forge.lthn.ai/core/mcp/pkg/mcp/ide"
|
2026-02-16 13:55:59 +00:00
|
|
|
"github.com/wailsapp/wails/v3/pkg/application"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
//go:embed all:frontend/dist/wails-angular-template/browser
|
|
|
|
|
var assets embed.FS
|
|
|
|
|
|
|
|
|
|
func main() {
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
// ── Flags ──────────────────────────────────────────────────
|
|
|
|
|
mcpOnly := false
|
2026-02-16 13:55:59 +00:00
|
|
|
for _, arg := range os.Args[1:] {
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
if arg == "--mcp" {
|
|
|
|
|
mcpOnly = true
|
2026-02-16 13:55:59 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
// ── Configuration ──────────────────────────────────────────
|
|
|
|
|
cfg, _ := config.New()
|
|
|
|
|
|
|
|
|
|
cwd, err := os.Getwd()
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("failed to get working directory: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Shared resources (built before Core) ───────────────────
|
|
|
|
|
hub := ws.NewHub()
|
|
|
|
|
|
|
|
|
|
bridgeCfg := ide.DefaultConfig()
|
|
|
|
|
bridgeCfg.WorkspaceRoot = cwd
|
|
|
|
|
if url := os.Getenv("CORE_API_URL"); url != "" {
|
|
|
|
|
bridgeCfg.LaravelWSURL = url
|
|
|
|
|
}
|
|
|
|
|
if token := os.Getenv("CORE_API_TOKEN"); token != "" {
|
|
|
|
|
bridgeCfg.Token = token
|
|
|
|
|
}
|
|
|
|
|
bridge := ide.NewBridge(hub, bridgeCfg)
|
|
|
|
|
|
2026-03-14 09:47:59 +00:00
|
|
|
// ── Service Provider Registry ──────────────────────────────
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(processapi.NewProvider(process.DefaultRegistry(), hub))
|
|
|
|
|
reg.Add(brain.NewProvider(bridge, hub))
|
|
|
|
|
|
|
|
|
|
// ── API Engine ─────────────────────────────────────────────
|
|
|
|
|
apiAddr := ":9880"
|
|
|
|
|
if addr := os.Getenv("CORE_API_ADDR"); addr != "" {
|
|
|
|
|
apiAddr = addr
|
|
|
|
|
}
|
|
|
|
|
engine, _ := api.New(
|
|
|
|
|
api.WithAddr(apiAddr),
|
|
|
|
|
api.WithCORS("*"),
|
|
|
|
|
api.WithWSHandler(http.Handler(hub.Handler())),
|
|
|
|
|
api.WithSwagger("Core IDE", "Service Provider API", "0.1.0"),
|
|
|
|
|
)
|
|
|
|
|
reg.MountAll(engine)
|
|
|
|
|
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
// ── Core framework ─────────────────────────────────────────
|
|
|
|
|
c, err := core.New(
|
|
|
|
|
core.WithName("ws", func(c *core.Core) (any, error) {
|
|
|
|
|
return hub, nil
|
|
|
|
|
}),
|
|
|
|
|
core.WithService(display.Register(nil)), // nil platform until Wails starts
|
|
|
|
|
core.WithName("mcp", func(c *core.Core) (any, error) {
|
|
|
|
|
return mcp.New(
|
|
|
|
|
mcp.WithWorkspaceRoot(cwd),
|
|
|
|
|
mcp.WithWSHub(hub),
|
|
|
|
|
mcp.WithSubsystem(brain.New(bridge)),
|
|
|
|
|
mcp.WithSubsystem(guiMCP.New(c)),
|
|
|
|
|
)
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("failed to create core: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Retrieve the MCP service for transport control
|
|
|
|
|
mcpSvc, err := core.ServiceFor[*mcp.Service](c, "mcp")
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("failed to get MCP service: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Mode selection ─────────────────────────────────────────
|
|
|
|
|
if mcpOnly {
|
|
|
|
|
// stdio mode — Claude Code connects via --mcp flag
|
|
|
|
|
ctx, cancel := signal.NotifyContext(context.Background(),
|
|
|
|
|
syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
|
|
if err := c.ServiceStartup(ctx, nil); err != nil {
|
|
|
|
|
log.Fatalf("core startup failed: %v", err)
|
|
|
|
|
}
|
|
|
|
|
bridge.Start(ctx)
|
2026-03-14 09:47:59 +00:00
|
|
|
go hub.Run(ctx)
|
|
|
|
|
|
|
|
|
|
// Start API server in background for provider endpoints
|
|
|
|
|
go func() {
|
|
|
|
|
if err := engine.Serve(ctx); err != nil {
|
|
|
|
|
log.Printf("API server error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}()
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
|
|
|
|
|
if err := mcpSvc.ServeStdio(ctx); err != nil {
|
|
|
|
|
log.Printf("MCP stdio error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_ = mcpSvc.Shutdown(ctx)
|
|
|
|
|
_ = c.ServiceShutdown(ctx)
|
2026-02-16 13:55:59 +00:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
if !guiEnabled(cfg) {
|
|
|
|
|
// No GUI — run Core with MCP transport in background
|
|
|
|
|
ctx, cancel := signal.NotifyContext(context.Background(),
|
|
|
|
|
syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
|
|
if err := c.ServiceStartup(ctx, nil); err != nil {
|
|
|
|
|
log.Fatalf("core startup failed: %v", err)
|
|
|
|
|
}
|
|
|
|
|
bridge.Start(ctx)
|
2026-03-14 09:47:59 +00:00
|
|
|
go hub.Run(ctx)
|
|
|
|
|
|
|
|
|
|
// Start API server
|
|
|
|
|
go func() {
|
|
|
|
|
log.Printf("API server listening on %s", apiAddr)
|
|
|
|
|
if err := engine.Serve(ctx); err != nil {
|
|
|
|
|
log.Printf("API server error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}()
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
|
if err := mcpSvc.Run(ctx); err != nil {
|
|
|
|
|
log.Printf("MCP error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
<-ctx.Done()
|
|
|
|
|
shutdownCtx := context.Background()
|
|
|
|
|
_ = mcpSvc.Shutdown(shutdownCtx)
|
|
|
|
|
_ = c.ServiceShutdown(shutdownCtx)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── GUI mode ───────────────────────────────────────────────
|
2026-02-16 13:55:59 +00:00
|
|
|
staticAssets, err := fs.Sub(assets, "frontend/dist/wails-angular-template/browser")
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
app := application.New(application.Options{
|
|
|
|
|
Name: "Core IDE",
|
|
|
|
|
Description: "Host UK Core IDE - Development Environment",
|
|
|
|
|
Services: []application.Service{
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
application.NewService(c),
|
2026-02-16 13:55:59 +00:00
|
|
|
},
|
|
|
|
|
Assets: application.AssetOptions{
|
|
|
|
|
Handler: application.AssetFileServerFS(staticAssets),
|
|
|
|
|
},
|
|
|
|
|
Mac: application.MacOptions{
|
|
|
|
|
ActivationPolicy: application.ActivationPolicyAccessory,
|
|
|
|
|
},
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
OnShutdown: func() {
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
_ = mcpSvc.Shutdown(ctx)
|
|
|
|
|
bridge.Shutdown()
|
|
|
|
|
},
|
2026-02-16 13:55:59 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// System tray
|
|
|
|
|
systray := app.SystemTray.New()
|
|
|
|
|
systray.SetTooltip("Core IDE")
|
|
|
|
|
|
|
|
|
|
if runtime.GOOS == "darwin" {
|
|
|
|
|
systray.SetTemplateIcon(icons.AppTray)
|
|
|
|
|
} else {
|
|
|
|
|
systray.SetDarkModeIcon(icons.AppTray)
|
|
|
|
|
systray.SetIcon(icons.AppTray)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Tray panel window
|
|
|
|
|
trayWindow := app.Window.NewWithOptions(application.WebviewWindowOptions{
|
|
|
|
|
Name: "tray-panel",
|
|
|
|
|
Title: "Core IDE",
|
|
|
|
|
Width: 380,
|
|
|
|
|
Height: 480,
|
|
|
|
|
URL: "/tray",
|
|
|
|
|
Hidden: true,
|
|
|
|
|
Frameless: true,
|
|
|
|
|
BackgroundColour: application.NewRGB(26, 27, 38),
|
|
|
|
|
})
|
|
|
|
|
systray.AttachWindow(trayWindow).WindowOffset(5)
|
|
|
|
|
|
|
|
|
|
// Tray menu
|
|
|
|
|
trayMenu := app.Menu.New()
|
|
|
|
|
trayMenu.Add("Quit").OnClick(func(ctx *application.Context) {
|
|
|
|
|
app.Quit()
|
|
|
|
|
})
|
|
|
|
|
systray.SetMenu(trayMenu)
|
|
|
|
|
|
2026-03-14 09:47:59 +00:00
|
|
|
// Start MCP transport and API server alongside Wails
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
go func() {
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
bridge.Start(ctx)
|
2026-03-14 09:47:59 +00:00
|
|
|
go hub.Run(ctx)
|
|
|
|
|
|
|
|
|
|
// Start API server
|
|
|
|
|
go func() {
|
|
|
|
|
log.Printf("API server listening on %s", apiAddr)
|
|
|
|
|
if err := engine.Serve(ctx); err != nil {
|
|
|
|
|
log.Printf("API server error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
if err := mcpSvc.Run(ctx); err != nil {
|
|
|
|
|
log.Printf("MCP error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
2026-02-16 13:55:59 +00:00
|
|
|
log.Println("Starting Core IDE...")
|
|
|
|
|
|
|
|
|
|
if err := app.Run(); err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
}
|
feat: modernise IDE with ecosystem packages
Replace 7 hand-rolled service files (mcp_bridge, webview_svc, brain_mcp,
claude_bridge, headless_mcp, headless, greetservice) with ecosystem
packages from core/gui, core/mcp, and core/go-ws.
Three operating modes: GUI (Wails systray), MCP (--mcp stdio for Claude
Code), and headless (no display). Core framework manages all service
lifecycles via dependency injection.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 09:18:55 +00:00
|
|
|
|
|
|
|
|
// guiEnabled checks whether the GUI should start.
|
|
|
|
|
// Returns false if config says gui.enabled: false, or if no display is available.
|
|
|
|
|
func guiEnabled(cfg *config.Config) bool {
|
|
|
|
|
if cfg != nil {
|
|
|
|
|
var guiCfg struct {
|
|
|
|
|
Enabled *bool `mapstructure:"enabled"`
|
|
|
|
|
}
|
|
|
|
|
if err := cfg.Get("gui", &guiCfg); err == nil && guiCfg.Enabled != nil {
|
|
|
|
|
return *guiCfg.Enabled
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Fall back to display detection
|
|
|
|
|
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return os.Getenv("DISPLAY") != "" || os.Getenv("WAYLAND_DISPLAY") != ""
|
|
|
|
|
}
|