refactor: move plans to tasks/, framework docs to core-gui

- plans/ → tasks/plans/ (planning documents)
- framework/ → core-gui/docs/framework/ (GUI framework docs)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Snider 2026-01-29 15:01:46 +00:00
parent 8601e5b355
commit 77a7237d71
31 changed files with 0 additions and 3529 deletions

View file

@ -1,134 +0,0 @@
# Architecture
Core follows a modular, service-based architecture designed for maintainability and testability.
## Overview
```
┌─────────────────────────────────────────────────────────┐
│ Wails Application │
├─────────────────────────────────────────────────────────┤
│ Core │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Display │ │ WebView │ │ MCP │ │ Config │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Crypt │ │ I18n │ │ IO │ │Workspace │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
├─────────────────────────────────────────────────────────┤
│ Plugin System │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Plugin A │ │ Plugin B │ │ Plugin C │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────┘
```
## Core Container
The `Core` struct is the central service container:
```go
type Core struct {
services map[string]any // Service registry
actions []ActionHandler // IPC handlers
Features *Features // Feature flags
servicesLocked bool // Prevent late registration
}
```
### Service Registration
Services are registered using factory functions:
```go
core.New(
core.WithService(display.NewService), // Auto-discovered name
core.WithName("custom", myFactory), // Explicit name
)
```
### Service Retrieval
Type-safe service retrieval:
```go
// Returns error if not found
svc, err := core.ServiceFor[*display.Service](c, "display")
// Panics if not found (use in init code)
svc := core.MustServiceFor[*display.Service](c, "display")
```
## Service Lifecycle
Services can implement lifecycle interfaces:
```go
// Called when app starts
type Startable interface {
OnStartup(ctx context.Context) error
}
// Called when app shuts down
type Stoppable interface {
OnShutdown(ctx context.Context) error
}
```
## IPC / Actions
Services communicate via the action system:
```go
// Register a handler
c.RegisterAction(func(c *core.Core, msg core.Message) error {
if msg.Type == "my-action" {
// Handle message
}
return nil
})
// Send a message
c.ACTION(core.Message{
Type: "my-action",
Data: map[string]any{"key": "value"},
})
```
## Frontend Bindings
Wails generates TypeScript bindings automatically:
```typescript
// Auto-generated from Go service
import { ShowNotification } from '@bindings/display/service';
await ShowNotification({
title: "Hello",
message: "From TypeScript!"
});
```
## Package Structure
```
pkg/
├── core/ # Core container and interfaces
├── display/ # Window, tray, dialogs, clipboard
├── webview/ # JS execution, DOM, screenshots
├── mcp/ # Model Context Protocol server
├── config/ # Configuration persistence
├── crypt/ # Encryption and signing
├── i18n/ # Internationalization
├── io/ # File system helpers
├── workspace/ # Project management
├── plugin/ # Plugin system
└── module/ # Module system
```
## Design Principles
1. **Dependency Injection**: Services receive dependencies via constructor
2. **Interface Segregation**: Small, focused interfaces
3. **Testability**: All services are mockable
4. **No Globals**: State contained in Core instance

View file

@ -1,122 +0,0 @@
# Config Service
The Config service (`pkg/config`) provides unified configuration management with automatic persistence, feature flags, and XDG-compliant directory paths.
## Features
- JSON configuration with auto-save
- Feature flag management
- XDG Base Directory support
- Struct serialization helpers
- Type-safe get/set operations
## Basic Usage
```go
import "github.com/Snider/Core/pkg/config"
// Standalone usage
cfg, err := config.New()
if err != nil {
log.Fatal(err)
}
// With Core framework
c, _ := core.New(
core.WithService(config.Register),
)
cfg := core.MustServiceFor[*config.Service](c, "config")
```
## Get & Set Values
```go
// Set a value (auto-saves)
err := cfg.Set("language", "fr")
// Get a value
var lang string
err := cfg.Get("language", &lang)
```
Available configuration keys:
| Key | Type | Description |
|-----|------|-------------|
| `language` | string | UI language code |
| `default_route` | string | Default navigation route |
| `configDir` | string | Config files directory |
| `dataDir` | string | Data files directory |
| `cacheDir` | string | Cache directory |
| `workspaceDir` | string | Workspaces directory |
## Feature Flags
```go
// Enable a feature
cfg.EnableFeature("dark_mode")
// Check if enabled
if cfg.IsFeatureEnabled("dark_mode") {
// Apply dark theme
}
// Disable a feature
cfg.DisableFeature("dark_mode")
```
## Struct Serialization
Store complex data structures in separate JSON files:
```go
type UserPrefs struct {
Theme string `json:"theme"`
Notifications bool `json:"notifications"`
}
// Save struct to config/user_prefs.json
prefs := UserPrefs{Theme: "dark", Notifications: true}
err := cfg.SaveStruct("user_prefs", prefs)
// Load struct from file
var loaded UserPrefs
err := cfg.LoadStruct("user_prefs", &loaded)
```
## Directory Paths
The service automatically creates XDG-compliant directories:
```go
// Access directory paths
fmt.Println(cfg.ConfigDir) // ~/.config/lethean or ~/lethean/config
fmt.Println(cfg.DataDir) // Data storage
fmt.Println(cfg.CacheDir) // Cache files
fmt.Println(cfg.WorkspaceDir) // User workspaces
```
## Manual Save
Changes are auto-saved, but you can save explicitly:
```go
err := cfg.Save()
```
## Frontend Usage (TypeScript)
```typescript
import { Get, Set, IsFeatureEnabled } from '@bindings/config/service';
// Get configuration
const lang = await Get("language");
// Set configuration
await Set("default_route", "/dashboard");
// Check feature flag
if (await IsFeatureEnabled("dark_mode")) {
applyDarkTheme();
}
```

View file

@ -1,312 +0,0 @@
# Core API Reference
Complete API reference for the Core framework (`pkg/core`).
## Core Struct
The central application container.
### Creation
```go
func New(opts ...Option) (*Core, error)
```
Creates a new Core instance with the specified options.
### Methods
#### Service Access
```go
func ServiceFor[T any](c *Core, name string) (T, error)
```
Retrieves a service by name with type safety.
```go
func MustServiceFor[T any](c *Core, name string) T
```
Retrieves a service by name, panics if not found or wrong type.
#### Actions
```go
func (c *Core) ACTION(msg Message) error
```
Broadcasts a message to all registered action handlers.
```go
func (c *Core) RegisterAction(handler func(*Core, Message) error)
```
Registers an action handler.
#### Service Registration
```go
func (c *Core) AddService(name string, svc any) error
```
Manually adds a service to the registry.
#### Config Access
```go
func (c *Core) Config() *config.Service
```
Returns the config service if registered.
## Options
### WithService
```go
func WithService(factory ServiceFactory) Option
```
Registers a service using its factory function.
```go
c, _ := core.New(
core.WithService(config.Register),
core.WithService(display.NewService),
)
```
### WithName
```go
func WithName(name string, factory ServiceFactory) Option
```
Registers a service with an explicit name.
```go
c, _ := core.New(
core.WithName("mydb", database.NewService),
)
```
### WithAssets
```go
func WithAssets(assets embed.FS) Option
```
Sets embedded assets for the application.
### WithServiceLock
```go
func WithServiceLock() Option
```
Prevents late service registration after initialization.
## ServiceFactory
```go
type ServiceFactory func(c *Core) (any, error)
```
Factory function signature for service creation.
## Message
```go
type Message interface{}
```
Messages can be any type. Common patterns:
```go
// Map-based message
c.ACTION(map[string]any{
"action": "user.created",
"id": "123",
})
// Typed message
type UserCreated struct {
ID string
Email string
}
c.ACTION(UserCreated{ID: "123", Email: "user@example.com"})
```
## ServiceRuntime
Generic helper for services that need Core access.
```go
type ServiceRuntime[T any] struct {
core *Core
options T
}
```
### Creation
```go
func NewServiceRuntime[T any](c *Core, opts T) *ServiceRuntime[T]
```
### Methods
```go
func (r *ServiceRuntime[T]) Core() *Core
func (r *ServiceRuntime[T]) Options() T
func (r *ServiceRuntime[T]) Config() *config.Service
```
### Usage
```go
type MyOptions struct {
Timeout time.Duration
}
type MyService struct {
*core.ServiceRuntime[MyOptions]
}
func NewMyService(c *core.Core) (any, error) {
opts := MyOptions{Timeout: 30 * time.Second}
return &MyService{
ServiceRuntime: core.NewServiceRuntime(c, opts),
}, nil
}
func (s *MyService) DoSomething() {
timeout := s.Options().Timeout
cfg := s.Config()
// ...
}
```
## Lifecycle Interfaces
### Startable
```go
type Startable interface {
OnStartup(ctx context.Context) error
}
```
Implement for initialization on app start.
### Stoppable
```go
type Stoppable interface {
OnShutdown(ctx context.Context) error
}
```
Implement for cleanup on app shutdown.
### IPC Handler
```go
type IPCHandler interface {
HandleIPCEvents(c *Core, msg Message) error
}
```
Automatically registered when using `WithService`.
## Built-in Actions
### ActionServiceStartup
```go
type ActionServiceStartup struct{}
```
Sent to all services when application starts.
### ActionServiceShutdown
```go
type ActionServiceShutdown struct{}
```
Sent to all services when application shuts down.
## Error Helpers
```go
func E(service, operation string, err error) error
```
Creates a contextual error with service and operation info.
```go
if err != nil {
return core.E("myservice", "Connect", err)
}
// Error: myservice.Connect: connection refused
```
## Complete Example
```go
package main
import (
"context"
"github.com/Snider/Core/pkg/core"
"github.com/Snider/Core/pkg/config"
)
type MyService struct {
*core.ServiceRuntime[struct{}]
data string
}
func NewMyService(c *core.Core) (any, error) {
return &MyService{
ServiceRuntime: core.NewServiceRuntime(c, struct{}{}),
data: "initialized",
}, nil
}
func (s *MyService) OnStartup(ctx context.Context) error {
// Startup logic
return nil
}
func (s *MyService) OnShutdown(ctx context.Context) error {
// Cleanup logic
return nil
}
func (s *MyService) HandleIPCEvents(c *core.Core, msg core.Message) error {
switch m := msg.(type) {
case map[string]any:
if m["action"] == "myservice.update" {
s.data = m["data"].(string)
}
}
return nil
}
func main() {
c, err := core.New(
core.WithService(config.Register),
core.WithService(NewMyService),
core.WithServiceLock(),
)
if err != nil {
panic(err)
}
svc := core.MustServiceFor[*MyService](c, "main")
_ = svc
}
```

View file

@ -1,133 +0,0 @@
# Crypt Service
The Crypt service (`pkg/crypt`) provides cryptographic utilities including hashing, checksums, RSA encryption, and PGP operations.
## Features
- Multiple hash algorithms (SHA512, SHA256, SHA1, MD5)
- Checksum functions (Fletcher, Luhn)
- RSA key generation and encryption
- PGP encryption, signing, and verification
- Symmetric PGP encryption
## Basic Usage
```go
import "github.com/Snider/Core/pkg/crypt"
// Standalone usage
crypto, err := crypt.New()
// With Core framework
c, _ := core.New(
core.WithService(crypt.Register),
)
crypto := core.MustServiceFor[*crypt.Service](c, "crypt")
```
## Hashing
```go
// Available algorithms: SHA512, SHA256, SHA1, MD5, LTHN
hash := crypto.Hash(crypt.SHA256, "hello world")
// Check if string is valid hash algorithm
isValid := crypto.IsHashAlgo("sha256")
```
## Checksums
```go
// Luhn validation (credit card numbers)
isValid := crypto.Luhn("4532015112830366")
// Fletcher checksums
f16 := crypto.Fletcher16("data")
f32 := crypto.Fletcher32("data")
f64 := crypto.Fletcher64("data")
```
## RSA Encryption
```go
// Generate key pair (2048 or 4096 bits recommended)
publicKey, privateKey, err := crypto.GenerateRSAKeyPair(2048)
// Encrypt with public key
ciphertext, err := crypto.EncryptRSA(publicKey, "secret message")
// Decrypt with private key
plaintext, err := crypto.DecryptRSA(privateKey, ciphertext)
```
## PGP Encryption
### Key Generation
```go
// Generate PGP key pair
publicKey, privateKey, err := crypto.GeneratePGPKeyPair(
"User Name",
"user@example.com",
"Key comment",
)
```
### Asymmetric Encryption
```go
// Encrypt for recipient
ciphertext, err := crypto.EncryptPGPToString(recipientPublicKey, "secret data")
// Decrypt with private key
plaintext, err := crypto.DecryptPGP(privateKey, ciphertext)
```
### Symmetric Encryption
```go
var buf bytes.Buffer
err := crypto.SymmetricallyEncryptPGP(&buf, "data", "passphrase")
```
### Signing & Verification
```go
// Sign data
signature, err := crypto.SignPGP(privateKey, "data to sign")
// Verify signature
err := crypto.VerifyPGP(publicKey, "data to sign", signature)
if err != nil {
// Signature invalid
}
```
## Hash Types
| Constant | Algorithm |
|----------|-----------|
| `crypt.SHA512` | SHA-512 |
| `crypt.SHA256` | SHA-256 |
| `crypt.SHA1` | SHA-1 |
| `crypt.MD5` | MD5 |
| `crypt.LTHN` | Custom LTHN hash |
## Frontend Usage (TypeScript)
```typescript
import {
Hash,
GenerateRSAKeyPair,
EncryptRSA,
DecryptRSA
} from '@bindings/crypt/service';
// Hash data
const hash = await Hash("SHA256", "hello world");
// RSA encryption
const { publicKey, privateKey } = await GenerateRSAKeyPair(2048);
const encrypted = await EncryptRSA(publicKey, "secret");
const decrypted = await DecryptRSA(privateKey, encrypted);
```

View file

@ -1,352 +0,0 @@
# Display API Reference
Complete API reference for the Display service (`pkg/display`).
## Service Creation
```go
func NewService(c *core.Core) (any, error)
```
## Window Management
### CreateWindow
```go
func (s *Service) CreateWindow(opts CreateWindowOptions) (*WindowInfo, error)
```
Creates a new window with the specified options.
```go
type CreateWindowOptions struct {
Name string
Title string
URL string
X int
Y int
Width int
Height int
}
```
### CloseWindow
```go
func (s *Service) CloseWindow(name string) error
```
### GetWindowInfo
```go
func (s *Service) GetWindowInfo(name string) (*WindowInfo, error)
```
Returns:
```go
type WindowInfo struct {
Name string
Title string
X int
Y int
Width int
Height int
IsVisible bool
IsFocused bool
IsMaximized bool
IsMinimized bool
}
```
### ListWindowInfos
```go
func (s *Service) ListWindowInfos() []*WindowInfo
```
### Window Position & Size
```go
func (s *Service) SetWindowPosition(name string, x, y int) error
func (s *Service) SetWindowSize(name string, width, height int) error
func (s *Service) SetWindowBounds(name string, x, y, width, height int) error
```
### Window State
```go
func (s *Service) MaximizeWindow(name string) error
func (s *Service) MinimizeWindow(name string) error
func (s *Service) RestoreWindow(name string) error
func (s *Service) FocusWindow(name string) error
func (s *Service) SetWindowFullscreen(name string, fullscreen bool) error
func (s *Service) SetWindowAlwaysOnTop(name string, onTop bool) error
func (s *Service) SetWindowVisibility(name string, visible bool) error
```
### Window Title
```go
func (s *Service) SetWindowTitle(name, title string) error
func (s *Service) GetWindowTitle(name string) (string, error)
```
### Window Background
```go
func (s *Service) SetWindowBackgroundColour(name string, r, g, b, a uint8) error
```
### Focus
```go
func (s *Service) GetFocusedWindow() string
```
## Screen Management
### GetScreens
```go
func (s *Service) GetScreens() []*Screen
```
Returns:
```go
type Screen struct {
ID string
Name string
X int
Y int
Width int
Height int
ScaleFactor float64
IsPrimary bool
}
```
### GetScreen
```go
func (s *Service) GetScreen(id string) (*Screen, error)
```
### GetPrimaryScreen
```go
func (s *Service) GetPrimaryScreen() (*Screen, error)
```
### GetScreenAtPoint
```go
func (s *Service) GetScreenAtPoint(x, y int) (*Screen, error)
```
### GetScreenForWindow
```go
func (s *Service) GetScreenForWindow(name string) (*Screen, error)
```
### GetWorkAreas
```go
func (s *Service) GetWorkAreas() []*WorkArea
```
Returns usable screen space (excluding dock/taskbar).
## Layout Management
### SaveLayout / RestoreLayout
```go
func (s *Service) SaveLayout(name string) error
func (s *Service) RestoreLayout(name string) error
func (s *Service) ListLayouts() []string
func (s *Service) DeleteLayout(name string) error
func (s *Service) GetLayout(name string) *Layout
```
### TileWindows
```go
func (s *Service) TileWindows(mode TileMode, windows []string) error
```
Tile modes:
```go
const (
TileModeLeft TileMode = "left"
TileModeRight TileMode = "right"
TileModeGrid TileMode = "grid"
TileModeQuadrants TileMode = "quadrants"
)
```
### SnapWindow
```go
func (s *Service) SnapWindow(name string, position SnapPosition) error
```
Snap positions:
```go
const (
SnapPositionLeft SnapPosition = "left"
SnapPositionRight SnapPosition = "right"
SnapPositionTop SnapPosition = "top"
SnapPositionBottom SnapPosition = "bottom"
SnapPositionTopLeft SnapPosition = "top-left"
SnapPositionTopRight SnapPosition = "top-right"
SnapPositionBottomLeft SnapPosition = "bottom-left"
SnapPositionBottomRight SnapPosition = "bottom-right"
)
```
### StackWindows
```go
func (s *Service) StackWindows(windows []string, offsetX, offsetY int) error
```
### ApplyWorkflowLayout
```go
func (s *Service) ApplyWorkflowLayout(workflow WorkflowType) error
```
Workflow types:
```go
const (
WorkflowCoding WorkflowType = "coding"
WorkflowDebugging WorkflowType = "debugging"
WorkflowPresenting WorkflowType = "presenting"
)
```
## Dialogs
### File Dialogs
```go
func (s *Service) OpenSingleFileDialog(opts OpenFileOptions) (string, error)
func (s *Service) OpenFileDialog(opts OpenFileOptions) ([]string, error)
func (s *Service) SaveFileDialog(opts SaveFileOptions) (string, error)
func (s *Service) OpenDirectoryDialog(opts OpenDirectoryOptions) (string, error)
```
Options:
```go
type OpenFileOptions struct {
Title string
DefaultDirectory string
AllowMultiple bool
Filters []FileFilter
}
type SaveFileOptions struct {
Title string
DefaultDirectory string
DefaultFilename string
Filters []FileFilter
}
type FileFilter struct {
DisplayName string
Pattern string // e.g., "*.png;*.jpg"
}
```
### ConfirmDialog
```go
func (s *Service) ConfirmDialog(title, message string) (bool, error)
```
### PromptDialog
```go
func (s *Service) PromptDialog(title, message string) (string, bool, error)
```
## System Tray
```go
func (s *Service) SetTrayIcon(icon []byte) error
func (s *Service) SetTrayTooltip(tooltip string) error
func (s *Service) SetTrayLabel(label string) error
func (s *Service) SetTrayMenu(items []TrayMenuItem) error
func (s *Service) GetTrayInfo() map[string]any
```
Menu item:
```go
type TrayMenuItem struct {
Label string
ActionID string
IsSeparator bool
}
```
## Clipboard
```go
func (s *Service) ReadClipboard() (string, error)
func (s *Service) WriteClipboard(text string) error
func (s *Service) HasClipboard() bool
func (s *Service) ClearClipboard() error
```
## Notifications
```go
func (s *Service) ShowNotification(opts NotificationOptions) error
func (s *Service) ShowInfoNotification(title, message string) error
func (s *Service) ShowWarningNotification(title, message string) error
func (s *Service) ShowErrorNotification(title, message string) error
func (s *Service) RequestNotificationPermission() (bool, error)
func (s *Service) CheckNotificationPermission() (bool, error)
```
Options:
```go
type NotificationOptions struct {
ID string
Title string
Message string
Subtitle string
}
```
## Theme
```go
func (s *Service) GetTheme() *Theme
func (s *Service) GetSystemTheme() string
```
Returns:
```go
type Theme struct {
IsDark bool
}
```
## Events
```go
func (s *Service) GetEventManager() *EventManager
```
The EventManager handles WebSocket connections for real-time events.

View file

@ -1,54 +0,0 @@
---
title: e
---
# Service: `e`
Package e provides a standardized error handling mechanism for the Core library.
It allows for wrapping errors with contextual information, making it easier to
trace the origin of an error and provide meaningful feedback.
The design of this package is influenced by the need for a simple, yet powerful
way to handle errors that can occur in different layers of the application,
from low-level file operations to high-level service interactions.
The key features of this package are:
- Error wrapping: The Op and an optional Msg field provide context about
where and why an error occurred.
- Stack traces: By wrapping errors, we can build a logical stack trace
that is more informative than a raw stack trace.
- Consistent error handling: Encourages a uniform approach to error
handling across the entire codebase.
## Types
### `type Error`
`Error` represents a standardized error with operational context.
```go
type Error struct {
// Op is the operation being performed, e.g., "config.Load".
Op string
// Msg is a human-readable message explaining the error.
Msg string
// Err is the underlying error that was wrapped.
Err error
}
```
#### Methods
- `Error() string`: Error returns the string representation of the error.
- `Unwrap() error`: Unwrap provides compatibility for Go's errors.Is and errors.As functions.
## Functions
- `E(op, msg string, err error) error`: E is a helper function to create a new Error.
This is the primary way to create errors that will be consumed by the system. For example:
```go
return e.E("config.Load", "failed to load config file", err)
```
The `op` parameter should be in the format of `package.function` or `service.method`. The `msg` parameter should be a human-readable message that can be displayed to the user. The `err` parameter is the underlying error that is being wrapped.

View file

@ -1,152 +0,0 @@
# Help Service
The Help service (`pkg/help`) provides an embeddable documentation system that displays MkDocs-based help content in a dedicated window.
## Features
- Embedded help content (MkDocs static site)
- Context-sensitive help navigation
- Works with or without Display service
- Multiple content sources (embedded, filesystem, custom)
## Basic Usage
```go
import "github.com/Snider/Core/pkg/help"
// Create with default embedded content
helpService, err := help.New(help.Options{})
// Initialize with core dependencies
helpService.Init(coreInstance, displayService)
```
## Showing Help
```go
// Show main help window
err := helpService.Show()
// Show specific section
err := helpService.ShowAt("getting-started")
err := helpService.ShowAt("api/config")
```
## Options
```go
type Options struct {
Source string // Path to help content directory
Assets fs.FS // Custom filesystem for assets
}
```
### Default Embedded Content
```go
// Uses embedded MkDocs site
helpService, _ := help.New(help.Options{})
```
### Custom Directory
```go
// Use local directory
helpService, _ := help.New(help.Options{
Source: "/path/to/docs/site",
})
```
### Custom Filesystem
```go
//go:embed docs/*
var docsFS embed.FS
helpService, _ := help.New(help.Options{
Assets: docsFS,
})
```
## Integration with Core
The help service can work standalone or integrated with Core:
### With Display Service
When Display service is available, help opens through the IPC action system:
```go
// Automatically uses display.open_window action
helpService.Init(core, displayService)
helpService.Show()
```
### Without Display Service
Falls back to direct Wails window creation:
```go
// Creates window directly via Wails
helpService.Init(core, nil)
helpService.Show()
```
## Lifecycle
```go
// Called on application startup
err := helpService.ServiceStartup(ctx)
```
## Building Help Content
Help content is a static MkDocs site. To update:
1. Edit documentation in `docs/` directory
2. Build with MkDocs:
```bash
mkdocs build
```
3. The built site goes to `pkg/help/public/`
4. Content is embedded at compile time
## Frontend Usage (TypeScript)
```typescript
import { Show, ShowAt } from '@bindings/help/service';
// Open help window
await Show();
// Open specific section
await ShowAt("configuration");
await ShowAt("api/display");
```
## Help Window Options
The help window opens with default settings:
| Property | Value |
|----------|-------|
| Title | "Help" |
| Width | 800px |
| Height | 600px |
## IPC Action
When using Display service, help triggers this action:
```go
{
"action": "display.open_window",
"name": "help",
"options": {
"Title": "Help",
"Width": 800,
"Height": 600,
"URL": "/#anchor", // When using ShowAt
},
}
```

View file

@ -1,130 +0,0 @@
# I18n Service
The I18n service (`pkg/i18n`) provides internationalization and localization support with automatic language detection and template-based translations.
## Features
- JSON-based locale files
- Embedded locale bundles
- Automatic language detection from environment
- Template variable interpolation
- BCP 47 language tag support
## Basic Usage
```go
import "github.com/Snider/Core/pkg/i18n"
// Create service (defaults to English)
i18n, err := i18n.New()
if err != nil {
log.Fatal(err)
}
```
## Setting Language
```go
// Set language using BCP 47 tag
err := i18n.SetLanguage("fr")
err := i18n.SetLanguage("en-US")
err := i18n.SetLanguage("zh-Hans")
```
## Translating Messages
```go
// Simple translation
msg := i18n.Translate("welcome_message")
// With template data
msg := i18n.Translate("greeting", map[string]string{
"Name": "John",
})
// Template: "Hello, {{.Name}}!"
// Result: "Hello, John!"
```
## Available Languages
```go
// Get list of available language codes
langs := i18n.AvailableLanguages()
// Returns: ["en", "es", "fr", "de", ...]
```
## Get All Messages
```go
// Get all translations for a language
messages, err := i18n.GetAllMessages("en")
for key, value := range messages {
fmt.Printf("%s: %s\n", key, value)
}
```
## Locale File Format
Locale files are JSON stored in `locales/` directory:
```json
// locales/en.json
{
"welcome": "Welcome to the application",
"greeting": "Hello, {{.Name}}!",
"items_count": {
"one": "{{.Count}} item",
"other": "{{.Count}} items"
}
}
```
## Adding New Languages
1. Create a new JSON file in `pkg/i18n/locales/`:
```
locales/es.json
```
2. Add translations:
```json
{
"welcome": "Bienvenido a la aplicación",
"greeting": "¡Hola, {{.Name}}!"
}
```
3. The service automatically loads embedded locales at startup.
## Language Detection
The service can detect system language from the `LANG` environment variable:
```go
// Automatic detection happens internally
// LANG=fr_FR.UTF-8 -> French
// LANG=de_DE.UTF-8 -> German
```
## Frontend Usage (TypeScript)
```typescript
import {
SetLanguage,
Translate,
AvailableLanguages,
GetAllMessages
} from '@bindings/i18n/service';
// Set language
await SetLanguage("fr");
// Translate
const welcome = await Translate("welcome_message");
// Get available languages for a selector
const languages = await AvailableLanguages();
// Load all messages for client-side caching
const messages = await GetAllMessages("en");
```

View file

@ -1,76 +0,0 @@
# Installation
## Prerequisites
### Go 1.22+
```bash
# macOS
brew install go
# Linux
sudo apt install golang-go
# Windows - download from https://go.dev/dl/
```
### Wails v3
```bash
go install github.com/wailsapp/wails/v3/cmd/wails3@latest
```
### Task (Build Automation)
```bash
# macOS
brew install go-task
# Linux
sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d
# Windows
choco install go-task
```
## Install Core
```bash
go get github.com/Snider/Core@latest
```
## Verify Installation
```bash
# Check Go
go version
# Check Wails
wails3 version
# Check Task
task --version
```
## IDE Setup
### VS Code
Install the Go extension and configure:
```json
{
"go.useLanguageServer": true,
"gopls": {
"ui.semanticTokens": true
}
}
```
### GoLand / IntelliJ
Go support is built-in. Enable the Wails plugin for additional features.
## Next Steps
Continue to [Quick Start](quickstart.md) to create your first application.

View file

@ -1,165 +0,0 @@
# IO Service
The IO package (`pkg/io`) provides a unified interface for file operations across different storage backends (local filesystem, S3, SFTP, etc.).
## Features
- Abstract `Medium` interface for storage backends
- Local filesystem implementation
- Copy between different mediums
- Mock implementation for testing
## Medium Interface
All storage backends implement the `Medium` interface:
```go
type Medium interface {
Read(path string) (string, error)
Write(path, content string) error
EnsureDir(path string) error
IsFile(path string) bool
FileGet(path string) (string, error)
FileSet(path, content string) error
}
```
## Local Filesystem
```go
import (
"github.com/Snider/Core/pkg/io"
"github.com/Snider/Core/pkg/io/local"
)
// Pre-initialized global medium (root = "/")
content, err := io.Local.Read("/etc/hosts")
// Create sandboxed medium
medium, err := local.New("/app/data")
content, err := medium.Read("config.json") // Reads /app/data/config.json
```
## Basic Operations
```go
// Read file
content, err := medium.Read("path/to/file.txt")
// Write file
err := medium.Write("path/to/file.txt", "content")
// Check if file exists
if medium.IsFile("config.json") {
// File exists
}
// Ensure directory exists
err := medium.EnsureDir("path/to/dir")
// Convenience methods
content, err := medium.FileGet("file.txt")
err := medium.FileSet("file.txt", "content")
```
## Helper Functions
Package-level functions that work with any Medium:
```go
// Read from medium
content, err := io.Read(medium, "file.txt")
// Write to medium
err := io.Write(medium, "file.txt", "content")
// Ensure directory
err := io.EnsureDir(medium, "path/to/dir")
// Check if file
exists := io.IsFile(medium, "file.txt")
```
## Copy Between Mediums
```go
localMedium, _ := local.New("/local/path")
remoteMedium := s3.New(bucket, region) // hypothetical S3 implementation
// Copy from local to remote
err := io.Copy(localMedium, "data.json", remoteMedium, "backup/data.json")
```
## Mock Medium for Testing
```go
import "github.com/Snider/Core/pkg/io"
func TestMyFunction(t *testing.T) {
mock := io.NewMockMedium()
// Pre-populate files
mock.Files["config.json"] = `{"key": "value"}`
mock.Dirs["data"] = true
// Use in tests
myService := NewService(mock)
// Verify writes
err := myService.SaveData("test")
if mock.Files["data/test.json"] != expectedContent {
t.Error("unexpected content")
}
}
```
## Creating Custom Backends
Implement the `Medium` interface for custom storage:
```go
type S3Medium struct {
bucket string
client *s3.Client
}
func (m *S3Medium) Read(path string) (string, error) {
// Implement S3 read
}
func (m *S3Medium) Write(path, content string) error {
// Implement S3 write
}
// ... implement remaining methods
```
## Error Handling
```go
content, err := medium.Read("missing.txt")
if err != nil {
// File not found or read error
log.Printf("Read failed: %v", err)
}
```
## Frontend Usage
The IO package is primarily used server-side. Frontend file operations should use the Display service dialogs or direct API calls:
```typescript
import { OpenFileDialog, SaveFileDialog } from '@bindings/display/service';
// Open file picker
const path = await OpenFileDialog({
title: "Select File",
filters: [{ displayName: "Text", pattern: "*.txt" }]
});
// Save file picker
const savePath = await SaveFileDialog({
title: "Save As",
defaultFilename: "document.txt"
});
```

View file

@ -1,119 +0,0 @@
# IPC & Actions
Core provides an inter-process communication system for services to communicate without tight coupling.
## Message Structure
```go
type Message struct {
Type string // Message type identifier
Data map[string]any // Message payload
Source string // Originating service (optional)
Timestamp time.Time // When message was created
}
```
## Sending Messages
```go
c.ACTION(core.Message{
Type: "user.created",
Data: map[string]any{
"id": "123",
"email": "user@example.com",
},
})
```
## Handling Messages
Register action handlers during service initialization:
```go
func NewNotificationService(c *core.Core) (any, error) {
svc := &NotificationService{}
// Register handler
c.RegisterAction(func(c *core.Core, msg core.Message) error {
return svc.handleAction(msg)
})
return svc, nil
}
func (s *NotificationService) handleAction(msg core.Message) error {
switch msg.Type {
case "user.created":
email := msg.Data["email"].(string)
return s.sendWelcomeEmail(email)
}
return nil
}
```
## Auto-Discovery
Services implementing `HandleIPCEvents` are automatically registered:
```go
type MyService struct{}
// Automatically registered when using WithService
func (s *MyService) HandleIPCEvents(c *core.Core, msg core.Message) error {
// Handle messages
return nil
}
```
## Common Patterns
### Request/Response
```go
// Sender
responseChan := make(chan any)
c.ACTION(core.Message{
Type: "data.request",
Data: map[string]any{
"query": "SELECT * FROM users",
"response": responseChan,
},
})
result := <-responseChan
// Handler
func (s *DataService) handleAction(msg core.Message) error {
if msg.Type == "data.request" {
query := msg.Data["query"].(string)
respChan := msg.Data["response"].(chan any)
result, err := s.execute(query)
if err != nil {
return err
}
respChan <- result
}
return nil
}
```
### Event Broadcasting
```go
// Broadcast to all listeners
c.ACTION(core.Message{
Type: "system.config.changed",
Data: map[string]any{
"key": "theme",
"value": "dark",
},
})
```
## Best Practices
1. **Use namespaced types** - `service.action` format
2. **Keep payloads simple** - Use primitive types when possible
3. **Handle errors** - Return errors from handlers
4. **Document message types** - Create constants for message types

View file

@ -1,101 +0,0 @@
# Service Lifecycle
Core provides lifecycle hooks for services to initialize and clean up resources.
## Lifecycle Interfaces
### Startable
Called when the application starts:
```go
type Startable interface {
OnStartup(ctx context.Context) error
}
```
### Stoppable
Called when the application shuts down:
```go
type Stoppable interface {
OnShutdown(ctx context.Context) error
}
```
## Implementation Example
```go
type DatabaseService struct {
db *sql.DB
}
func (s *DatabaseService) OnStartup(ctx context.Context) error {
db, err := sql.Open("postgres", os.Getenv("DATABASE_URL"))
if err != nil {
return err
}
// Verify connection
if err := db.PingContext(ctx); err != nil {
return err
}
s.db = db
return nil
}
func (s *DatabaseService) OnShutdown(ctx context.Context) error {
if s.db != nil {
return s.db.Close()
}
return nil
}
```
## Lifecycle Order
1. **Registration**: Services registered via `core.New()`
2. **Wails Binding**: Services bound to Wails app
3. **Startup**: `OnStartup()` called for each Startable service
4. **Running**: Application runs
5. **Shutdown**: `OnShutdown()` called for each Stoppable service
## Context Usage
The context passed to lifecycle methods includes:
- Cancellation signal for graceful shutdown
- Deadline for timeout handling
```go
func (s *Service) OnStartup(ctx context.Context) error {
select {
case <-ctx.Done():
return ctx.Err()
case <-s.initialize():
return nil
}
}
```
## Error Handling
If `OnStartup` returns an error, the application will fail to start:
```go
func (s *Service) OnStartup(ctx context.Context) error {
if err := s.validate(); err != nil {
return fmt.Errorf("validation failed: %w", err)
}
return nil
}
```
## Best Practices
1. **Keep startup fast** - Defer heavy initialization
2. **Handle context cancellation** - Support graceful shutdown
3. **Clean up resources** - Always implement OnShutdown for services with resources
4. **Log lifecycle events** - Helps with debugging

View file

@ -1,220 +0,0 @@
# MCP Bridge
The MCP Bridge (`cmd/core-gui/mcp_bridge.go`) connects the Model Context Protocol server with Display, WebView, and WebSocket services.
## Overview
The MCP Bridge provides an HTTP API for AI assistants to interact with the desktop application, enabling:
- Window and screen management
- JavaScript execution in webviews
- DOM interaction (click, type, select)
- Screenshot capture
- File and process management
- Real-time events via WebSocket
## HTTP Endpoints
| Endpoint | Description |
|----------|-------------|
| `GET /health` | Health check |
| `GET /mcp` | Server capabilities |
| `GET /mcp/tools` | List available tools |
| `POST /mcp/call` | Execute a tool |
| `WS /ws` | WebSocket for GUI clients |
| `WS /events` | WebSocket for display events |
## Server Capabilities
```bash
curl http://localhost:9877/mcp
```
Response:
```json
{
"name": "core",
"version": "0.1.0",
"capabilities": {
"webview": true,
"display": true,
"windowControl": true,
"screenControl": true,
"websocket": "ws://localhost:9877/ws",
"events": "ws://localhost:9877/events"
}
}
```
## Tool Categories
### File Operations
| Tool | Description |
|------|-------------|
| `file_read` | Read file contents |
| `file_write` | Write content to file |
| `file_edit` | Edit file by replacing text |
| `file_delete` | Delete a file |
| `file_exists` | Check if file exists |
| `dir_list` | List directory contents |
| `dir_create` | Create directory |
### Window Control
| Tool | Description |
|------|-------------|
| `window_list` | List all windows |
| `window_create` | Create new window |
| `window_close` | Close window |
| `window_position` | Move window |
| `window_size` | Resize window |
| `window_maximize` | Maximize window |
| `window_minimize` | Minimize window |
| `window_focus` | Bring window to front |
### WebView Interaction
| Tool | Description |
|------|-------------|
| `webview_eval` | Execute JavaScript |
| `webview_click` | Click element |
| `webview_type` | Type into element |
| `webview_screenshot` | Capture page |
| `webview_navigate` | Navigate to URL |
| `webview_console` | Get console messages |
### Screen Management
| Tool | Description |
|------|-------------|
| `screen_list` | List all monitors |
| `screen_primary` | Get primary screen |
| `screen_at_point` | Get screen at coordinates |
| `screen_work_areas` | Get usable screen space |
### Layout Management
| Tool | Description |
|------|-------------|
| `layout_save` | Save window arrangement |
| `layout_restore` | Restore saved layout |
| `layout_tile` | Auto-tile windows |
| `layout_snap` | Snap window to edge |
## Calling Tools
```bash
# List windows
curl -X POST http://localhost:9877/mcp/call \
-H "Content-Type: application/json" \
-d '{"tool": "window_list", "params": {}}'
# Move window
curl -X POST http://localhost:9877/mcp/call \
-H "Content-Type: application/json" \
-d '{
"tool": "window_position",
"params": {"name": "main", "x": 100, "y": 100}
}'
# Execute JavaScript
curl -X POST http://localhost:9877/mcp/call \
-H "Content-Type: application/json" \
-d '{
"tool": "webview_eval",
"params": {
"window": "main",
"code": "document.title"
}
}'
# Click element
curl -X POST http://localhost:9877/mcp/call \
-H "Content-Type: application/json" \
-d '{
"tool": "webview_click",
"params": {
"window": "main",
"selector": "#submit-button"
}
}'
# Take screenshot
curl -X POST http://localhost:9877/mcp/call \
-H "Content-Type: application/json" \
-d '{
"tool": "webview_screenshot",
"params": {"window": "main"}
}'
```
## WebSocket Events
Connect to `/events` for real-time display events:
```javascript
const ws = new WebSocket('ws://localhost:9877/events');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
switch (data.type) {
case 'window.focus':
console.log('Window focused:', data.name);
break;
case 'window.move':
console.log('Window moved:', data.name, data.x, data.y);
break;
case 'theme.change':
console.log('Theme changed:', data.isDark);
break;
}
};
```
Event types:
- `window.focus` - Window received focus
- `window.blur` - Window lost focus
- `window.move` - Window position changed
- `window.resize` - Window size changed
- `window.close` - Window was closed
- `window.create` - New window created
- `theme.change` - System theme changed
- `screen.change` - Screen configuration changed
## Go Integration
```go
import "github.com/Snider/Core/cmd/core-gui"
// Create bridge
bridge := NewMCPBridge(9877, displayService)
// Access services
mcpSvc := bridge.GetMCPService()
webview := bridge.GetWebView()
display := bridge.GetDisplay()
```
## Configuration
The bridge starts automatically on Wails app startup via the `ServiceStartup` lifecycle hook:
```go
func (b *MCPBridge) ServiceStartup(ctx context.Context, options application.ServiceOptions) error {
b.app = application.Get()
b.webview.SetApp(b.app)
go b.startHTTPServer()
return nil
}
```
## Security
The MCP server binds to localhost only by default. For production:
- Consider firewall rules
- Add authentication if needed
- Limit exposed tools

View file

@ -1,151 +0,0 @@
# MCP Service
The MCP service (`pkg/mcp`) implements the [Model Context Protocol](https://modelcontextprotocol.io/), enabling AI assistants like Claude to interact with your application.
## Overview
MCP provides a standardized way for AI tools to:
- Execute operations in your application
- Query application state
- Interact with the UI
- Manage files and processes
## Basic Setup
```go
import "github.com/Snider/Core/pkg/mcp"
// Create standalone MCP server
mcpService := mcp.NewStandaloneWithPort(9877)
// Or integrate with Core
c, _ := core.New(
core.WithService(mcp.NewService),
)
```
## Available Tools
The MCP service exposes numerous tools organized by category:
### File Operations
| Tool | Description |
|------|-------------|
| `file_read` | Read file contents |
| `file_write` | Write content to file |
| `file_edit` | Replace text in file |
| `file_delete` | Delete a file |
| `file_exists` | Check if file exists |
| `dir_list` | List directory contents |
| `dir_create` | Create directory |
### Window Control
| Tool | Description |
|------|-------------|
| `window_list` | List all windows |
| `window_create` | Create new window |
| `window_close` | Close window |
| `window_position` | Move window |
| `window_size` | Resize window |
| `window_maximize` | Maximize window |
| `window_minimize` | Minimize window |
| `window_focus` | Bring to front |
### WebView Interaction
| Tool | Description |
|------|-------------|
| `webview_eval` | Execute JavaScript |
| `webview_click` | Click element |
| `webview_type` | Type into element |
| `webview_screenshot` | Capture page |
| `webview_navigate` | Navigate to URL |
| `webview_console` | Get console logs |
### Process Management
| Tool | Description |
|------|-------------|
| `process_start` | Start a process |
| `process_stop` | Stop a process |
| `process_list` | List running processes |
| `process_output` | Get process output |
## HTTP API
The MCP service exposes an HTTP API:
```bash
# Health check
curl http://localhost:9877/health
# List available tools
curl http://localhost:9877/mcp/tools
# Call a tool
curl -X POST http://localhost:9877/mcp/call \
-H "Content-Type: application/json" \
-d '{"tool": "window_list", "params": {}}'
```
## WebSocket Events
Connect to `/events` for real-time updates:
```javascript
const ws = new WebSocket('ws://localhost:9877/events');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Event:', data.type, data.data);
};
```
## Integration with Display Service
```go
mcpService := mcp.NewStandaloneWithPort(9877)
mcpService.SetDisplay(displayService)
mcpService.SetWebView(webviewService)
```
## Example: Claude Integration
When Claude connects via MCP, it can:
```
User: "Move the settings window to the left side of the screen"
Claude uses: window_position("settings", 0, 100)
```
```
User: "Take a screenshot of the app"
Claude uses: webview_screenshot("main")
```
```
User: "Click the submit button"
Claude uses: webview_click("main", "#submit-btn")
```
## Security Considerations
- MCP server binds to localhost by default
- No authentication (designed for local AI assistants)
- Consider firewall rules for production
## Configuration
```go
// Custom port
mcp.NewStandaloneWithPort(8080)
// With all services
bridge := NewMCPBridge(9877, displayService)
bridge.SetWebView(webviewService)
```

View file

@ -1,271 +0,0 @@
# Module System
The Module system (`pkg/module`) provides a declarative way to register UI menus, routes, and API endpoints using the `.itw3.json` configuration format.
## Features
- Declarative module configuration
- UI menu contributions
- Frontend route registration
- API endpoint declarations
- Multi-context support (developer, retail, miner)
- Binary/daemon management
- Module dependencies
## Module Config Format
Modules are defined using `.itw3.json` files:
```json
{
"code": "wallet",
"type": "core",
"name": "Wallet Manager",
"version": "1.0.0",
"namespace": "finance",
"description": "Cryptocurrency wallet management",
"author": "Your Name",
"contexts": ["default", "retail"],
"menu": [...],
"routes": [...],
"api": [...],
"config": {...}
}
```
## Module Types
| Type | Description |
|------|-------------|
| `core` | Built-in core functionality |
| `app` | External web application |
| `bin` | Binary/daemon wrapper |
## UI Contexts
Modules can target specific UI contexts:
| Context | Description |
|---------|-------------|
| `default` | Standard user interface |
| `developer` | Developer tools and debugging |
| `retail` | Point-of-sale interface |
| `miner` | Mining operations interface |
## Menu Contributions
Add items to the application menu:
```json
{
"menu": [
{
"id": "wallet-send",
"label": "Send Funds",
"icon": "send",
"route": "/wallet/send",
"accelerator": "CmdOrCtrl+Shift+S",
"contexts": ["default", "retail"],
"order": 10
},
{
"id": "wallet-receive",
"label": "Receive",
"icon": "receive",
"route": "/wallet/receive",
"order": 20
},
{
"separator": true
},
{
"id": "wallet-settings",
"label": "Settings",
"action": "wallet.open_settings",
"children": [
{"id": "wallet-backup", "label": "Backup", "action": "wallet.backup"},
{"id": "wallet-restore", "label": "Restore", "action": "wallet.restore"}
]
}
]
}
```
## Route Contributions
Register frontend routes:
```json
{
"routes": [
{
"path": "/wallet",
"component": "wallet-dashboard",
"title": "Wallet",
"icon": "wallet",
"contexts": ["default"]
},
{
"path": "/wallet/send",
"component": "wallet-send-form",
"title": "Send Funds"
}
]
}
```
## API Declarations
Declare API endpoints the module provides:
```json
{
"api": [
{
"method": "GET",
"path": "/balance",
"description": "Get wallet balance"
},
{
"method": "POST",
"path": "/send",
"description": "Send transaction"
}
]
}
```
## Binary Downloads
For `bin` type modules, specify platform binaries:
```json
{
"downloads": {
"app": "https://example.com/wallet-ui.tar.gz",
"x86_64": {
"darwin": {
"url": "https://example.com/wallet-darwin-x64",
"checksum": "sha256:abc123..."
},
"linux": {
"url": "https://example.com/wallet-linux-x64",
"checksum": "sha256:def456..."
},
"windows": {
"url": "https://example.com/wallet-win-x64.exe",
"checksum": "sha256:ghi789..."
}
},
"aarch64": {
"darwin": {
"url": "https://example.com/wallet-darwin-arm64"
}
}
}
}
```
## Web App Configuration
For `app` type modules:
```json
{
"app": {
"url": "https://example.com/wallet-app.tar.gz",
"type": "spa",
"hooks": [
{
"type": "rename",
"from": "dist",
"to": "wallet"
}
]
}
}
```
## Dependencies
Declare module dependencies:
```json
{
"depends": ["core", "crypto"]
}
```
## Using in Go
### Module Registration
```go
import "github.com/Snider/Core/pkg/module"
// Create from config
cfg := module.Config{
Code: "wallet",
Type: module.TypeCore,
Name: "Wallet",
Namespace: "finance",
}
mod := module.Module{
Config: cfg,
Handler: myHandler,
}
```
### Gin Router Integration
```go
type WalletModule struct{}
func (m *WalletModule) RegisterRoutes(group *gin.RouterGroup) {
group.GET("/balance", m.getBalance)
group.POST("/send", m.sendTransaction)
}
// Register with Gin
router := gin.Default()
apiGroup := router.Group("/api/finance/wallet")
walletModule.RegisterRoutes(apiGroup)
```
## Registry Service
The registry manages all modules:
```go
import "github.com/Snider/Core/pkg/module"
registry := module.NewRegistry()
// Register module
registry.Register(walletModule)
// Get module by code
mod := registry.Get("wallet")
// List all modules
modules := registry.List()
// Get modules for context
devModules := registry.ForContext(module.ContextDeveloper)
```
## Built-in Modules
Core provides several built-in modules:
- System information
- Configuration management
- Process management
- File operations
Access via:
```go
builtins := module.BuiltinModules()
```

View file

@ -1,175 +0,0 @@
# GUI Application
The Core GUI (`cmd/core-gui`) is a Wails v3 desktop application that demonstrates the Core framework capabilities with integrated MCP support.
## Features
- Angular frontend with Wails bindings
- MCP HTTP server for AI tool integration
- WebView automation capabilities
- Real-time WebSocket communication
- System tray support
- Multi-window management
## Architecture
```
┌─────────────────────────────────────────┐
│ Angular Frontend │
│ (TypeScript + Wails Bindings) │
└─────────────────┬───────────────────────┘
│ IPC
┌─────────────────┴───────────────────────┐
│ Wails Runtime │
│ (Window, Events, Bindings) │
└─────────────────┬───────────────────────┘
┌─────────────────┴───────────────────────┐
│ MCP Bridge │
│ ┌─────────┬──────────┬─────────────┐ │
│ │ Display │ WebView │ WebSocket │ │
│ │ Service │ Service │ Hub │ │
│ └─────────┴──────────┴─────────────┘ │
└─────────────────────────────────────────┘
```
## Running the GUI
### Development Mode
```bash
# From project root
task gui:dev
# Or directly
cd cmd/core-gui
wails3 dev
```
### Production Build
```bash
task gui:build
```
## Directory Structure
```
cmd/core-gui/
├── main.go # Application entry point
├── mcp_bridge.go # MCP HTTP server and tool handler
├── claude_bridge.go # Claude MCP client (optional)
├── frontend/ # Angular application
│ ├── src/
│ │ ├── app/ # Angular components
│ │ └── lib/ # Shared utilities
│ └── bindings/ # Generated Wails bindings
└── public/ # Static assets
```
## Services Integrated
The GUI integrates several Core services:
| Service | Purpose |
|---------|---------|
| Display | Window management, dialogs, tray |
| WebView | JavaScript execution, DOM interaction |
| MCP | AI tool protocol server |
| WebSocket | Real-time communication |
## Configuration
The application uses the Config service for settings:
```go
// Default settings
DefaultRoute: "/"
Language: "en"
Features: []
```
## Frontend Bindings
Wails generates TypeScript bindings for Go services:
```typescript
import { CreateWindow, ShowNotification } from '@bindings/display/service';
import { Translate, SetLanguage } from '@bindings/i18n/service';
// Create a new window
await CreateWindow({
name: "settings",
title: "Settings",
width: 800,
height: 600
});
// Show notification
await ShowNotification({
title: "Success",
message: "Operation completed!"
});
```
## WebSocket Communication
Connect to the WebSocket endpoint for real-time updates:
```typescript
const ws = new WebSocket('ws://localhost:9877/ws');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Received:', data);
};
ws.send(JSON.stringify({
type: 'ping',
data: {}
}));
```
## System Tray
The application includes system tray support:
```go
// Set tray menu
display.SetTrayMenu([]display.TrayMenuItem{
{Label: "Open", ActionID: "open"},
{Label: "Settings", ActionID: "settings"},
{IsSeparator: true},
{Label: "Quit", ActionID: "quit"},
})
```
## Building for Distribution
### macOS
```bash
task gui:build
# Creates: build/bin/core-gui.app
```
### Windows
```bash
task gui:build
# Creates: build/bin/core-gui.exe
```
### Linux
```bash
task gui:build
# Creates: build/bin/core-gui
```
## Environment Variables
| Variable | Description |
|----------|-------------|
| `MCP_PORT` | MCP server port (default: 9877) |
| `DEBUG` | Enable debug logging |

View file

@ -1,172 +0,0 @@
# Plugin System
The Plugin system (`pkg/plugin`) allows you to extend Core applications with HTTP-based plugins that register routes under `/api/{namespace}/{name}/`.
## Features
- Namespace-based organization
- HTTP handler registration
- Lifecycle hooks (OnRegister, OnUnregister)
- Wails service integration
## Plugin Interface
All plugins implement the `Plugin` interface:
```go
type Plugin interface {
// Name returns the unique identifier for this plugin
Name() string
// Namespace returns the plugin's namespace (e.g., "core", "mining")
Namespace() string
// ServeHTTP handles HTTP requests routed to this plugin
http.Handler
// OnRegister is called when the plugin is registered
OnRegister(ctx context.Context) error
// OnUnregister is called when the plugin is being removed
OnUnregister(ctx context.Context) error
}
```
## Using BasePlugin
For simple plugins, embed `BasePlugin`:
```go
import "github.com/Snider/Core/pkg/plugin"
func NewMyPlugin() *plugin.BasePlugin {
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello from plugin!"))
})
return plugin.NewBasePlugin("myapp", "greeting", handler).
WithDescription("A simple greeting plugin").
WithVersion("1.0.0")
}
```
## Custom Plugin Implementation
For more control, implement the full interface:
```go
type DataPlugin struct {
db *sql.DB
}
func (p *DataPlugin) Name() string { return "data" }
func (p *DataPlugin) Namespace() string { return "myapp" }
func (p *DataPlugin) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/users":
p.handleUsers(w, r)
case "/items":
p.handleItems(w, r)
default:
http.NotFound(w, r)
}
}
func (p *DataPlugin) OnRegister(ctx context.Context) error {
// Initialize database connection
db, err := sql.Open("postgres", os.Getenv("DATABASE_URL"))
if err != nil {
return err
}
p.db = db
return nil
}
func (p *DataPlugin) OnUnregister(ctx context.Context) error {
if p.db != nil {
return p.db.Close()
}
return nil
}
```
## Plugin Info
Access plugin metadata:
```go
info := myPlugin.Info()
fmt.Println(info.Name) // "greeting"
fmt.Println(info.Namespace) // "myapp"
fmt.Println(info.Description) // "A simple greeting plugin"
fmt.Println(info.Version) // "1.0.0"
```
## Wails Integration
Register plugins as Wails services:
```go
app := application.New(application.Options{
Services: []application.Service{
application.NewServiceWithOptions(
myPlugin,
plugin.ServiceOptionsForPlugin(myPlugin),
),
},
})
```
## URL Routing
Plugins receive requests at:
```
/api/{namespace}/{name}/{path}
```
Examples:
- `/api/myapp/greeting/` → GreetingPlugin
- `/api/myapp/data/users` → DataPlugin (path: "/users")
- `/api/core/system/health` → SystemPlugin (path: "/health")
## Built-in Plugins
### System Plugin
Located at `pkg/plugin/builtin/system`:
```go
// Provides system information endpoints
/api/core/system/info - Application info
/api/core/system/health - Health check
```
## Plugin Router
The Router manages plugin registration:
```go
import "github.com/Snider/Core/pkg/plugin"
router := plugin.NewRouter()
// Register plugins
router.Register(ctx, myPlugin)
router.Register(ctx, dataPlugin)
// Get all registered plugins
plugins := router.List()
// Unregister a plugin
router.Unregister(ctx, "myapp", "greeting")
```
## Best Practices
1. **Use namespaces** to group related plugins
2. **Implement OnRegister** for initialization that can fail
3. **Implement OnUnregister** to clean up resources
4. **Return meaningful errors** from lifecycle hooks
5. **Use standard HTTP patterns** in ServeHTTP

View file

@ -1,128 +0,0 @@
# Quick Start
Build a simple Core application in 5 minutes.
## Create Project
```bash
mkdir myapp && cd myapp
go mod init myapp
```
## Install Dependencies
```bash
go get github.com/Snider/Core@latest
go get github.com/wailsapp/wails/v3@latest
```
## Create Main File
Create `main.go`:
```go
package main
import (
"context"
"embed"
"log"
"github.com/Snider/Core/pkg/core"
"github.com/Snider/Core/pkg/display"
"github.com/wailsapp/wails/v3/pkg/application"
)
//go:embed all:frontend/dist
var assets embed.FS
func main() {
// Initialize Core with display service
c, err := core.New(
core.WithAssets(assets),
core.WithService(display.NewService),
)
if err != nil {
log.Fatal(err)
}
// Get display service for window creation
displaySvc := core.MustServiceFor[*display.Service](c, "display")
// Create Wails application
app := application.New(application.Options{
Name: "My App",
Assets: application.AssetOptions{
FS: assets,
},
})
// Create main window
app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{
Title: "My App",
Width: 1200,
Height: 800,
URL: "/",
})
// Register display service with Wails
app.RegisterService(displaySvc)
// Run application
if err := app.Run(); err != nil {
log.Fatal(err)
}
}
```
## Create Frontend
Create a minimal frontend:
```bash
mkdir -p frontend/dist
```
Create `frontend/dist/index.html`:
```html
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
<style>
body {
font-family: system-ui, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background: #1a1a2e;
color: #eee;
}
</style>
</head>
<body>
<h1>Hello from Core!</h1>
</body>
</html>
```
## Run Development Mode
```bash
wails3 dev
```
## Build for Production
```bash
wails3 build
```
## Next Steps
- [Architecture](architecture.md) - Understand how Core works
- [Display Service](../services/display.md) - Window and dialog management
- [MCP Integration](../services/mcp.md) - AI tool support

View file

@ -1,76 +0,0 @@
---
title: runtime
---
# Service: `runtime`
The `runtime` service provides the main entry point for the application and a helper structure for services to interact with the `Core`.
## Types
### `type Runtime`
`Runtime` is the top-level container that holds the `Core` instance and the Wails application. It serves as the bridge between Wails and the Core framework.
```go
type Runtime struct {
// Core is the central service manager
Core *Core
// app is the Wails application instance
app *application.App
}
```
### `type ServiceRuntime[T any]`
`ServiceRuntime` is a generic helper struct designed to be embedded in service implementations. It provides easy access to the `Core` and service-specific options.
```go
type ServiceRuntime[T any] struct {
core *Core
opts T
}
```
### `type ServiceFactory`
`ServiceFactory` is a function type that creates a service instance.
```go
type ServiceFactory func() (any, error)
```
## Functions
### `func NewRuntime(app *application.App) (*Runtime, error)`
`NewRuntime` creates and wires together all application services using default settings. It is the standard way to initialize the runtime.
### `func NewWithFactories(app *application.App, factories map[string]ServiceFactory) (*Runtime, error)`
`NewWithFactories` creates a new `Runtime` instance using a provided map of service factories. This allows for flexible, dynamic service registration.
### `func NewServiceRuntime[T any](c *Core, opts T) *ServiceRuntime[T]`
`NewServiceRuntime` creates a new `ServiceRuntime` instance. This is typically used in a service's factory or constructor.
## Methods
### `func (r *Runtime) ServiceName() string`
`ServiceName` returns the name of the service ("Core"). This is used by Wails for service identification.
### `func (r *Runtime) ServiceStartup(ctx context.Context, options application.ServiceOptions)`
`ServiceStartup` delegates the startup lifecycle event to the underlying `Core`, which in turn initializes all registered services.
### `func (r *Runtime) ServiceShutdown(ctx context.Context)`
`ServiceShutdown` delegates the shutdown lifecycle event to the underlying `Core`.
### `func (r *ServiceRuntime[T]) Core() *Core`
`Core` returns the central `Core` instance, giving the service access to other services and features.
### `func (r *ServiceRuntime[T]) Config() Config`
`Config` returns the registered `Config` service from the `Core`. It is a convenience method for accessing configuration.

View file

@ -1,119 +0,0 @@
# Services
Services are the building blocks of a Core application. Each service encapsulates a specific domain of functionality.
## Creating a Service
```go
package myservice
import (
"context"
"github.com/Snider/Core/pkg/core"
)
type Service struct {
core *core.Core
}
// Factory function for registration
func NewService(c *core.Core) (any, error) {
return &Service{core: c}, nil
}
// Implement Startable for startup logic
func (s *Service) OnStartup(ctx context.Context) error {
// Initialize resources
return nil
}
// Implement Stoppable for cleanup
func (s *Service) OnShutdown(ctx context.Context) error {
// Release resources
return nil
}
```
## Registering Services
```go
c, err := core.New(
// Auto-discover name from package path
core.WithService(myservice.NewService),
// Explicit name
core.WithName("custom", func(c *core.Core) (any, error) {
return &CustomService{}, nil
}),
)
```
## Retrieving Services
```go
// Safe retrieval with error
svc, err := core.ServiceFor[*myservice.Service](c, "myservice")
if err != nil {
log.Printf("Service not found: %v", err)
}
// Must retrieval (panics if not found)
svc := core.MustServiceFor[*myservice.Service](c, "myservice")
```
## Service Dependencies
Services can depend on other services:
```go
func NewOrderService(c *core.Core) (any, error) {
// Get required dependencies
userSvc := core.MustServiceFor[*user.Service](c, "user")
paymentSvc := core.MustServiceFor[*payment.Service](c, "payment")
return &OrderService{
users: userSvc,
payments: paymentSvc,
}, nil
}
```
!!! warning "Dependency Order"
Register dependencies before services that use them. Core does not automatically resolve dependency order.
## Exposing to Frontend
Services are automatically exposed to the frontend via Wails bindings:
```go
// Go service method
func (s *Service) GetUser(id string) (*User, error) {
return s.db.FindUser(id)
}
```
```typescript
// TypeScript (auto-generated)
import { GetUser } from '@bindings/myservice/service';
const user = await GetUser("123");
```
## Testing Services
```go
func TestMyService(t *testing.T) {
// Create mock core
c, _ := core.New()
// Create service
svc, err := NewService(c)
if err != nil {
t.Fatal(err)
}
// Test methods
result := svc.(*Service).DoSomething()
assert.Equal(t, expected, result)
}
```

View file

@ -1,215 +0,0 @@
# WebView Service
The WebView service (`pkg/webview`) provides programmatic interaction with web content in your application windows.
## Features
- JavaScript execution
- DOM manipulation
- Element interaction (click, type, select)
- Console message capture
- Screenshots
- Network request monitoring
- Performance metrics
## Basic Usage
```go
import "github.com/Snider/Core/pkg/webview"
// Create service
wv := webview.New()
// Set Wails app reference
wv.SetApp(app)
```
## JavaScript Execution
```go
// Execute JavaScript and get result
result, err := wv.ExecJS("main", `
document.title
`)
// Execute complex scripts
result, err := wv.ExecJS("main", `
const items = document.querySelectorAll('.item');
Array.from(items).map(el => el.textContent);
`)
```
## DOM Interaction
### Click Element
```go
err := wv.Click("main", "#submit-button")
err := wv.Click("main", ".nav-link:first-child")
```
### Type Text
```go
err := wv.Type("main", "#search-input", "hello world")
```
### Select Option
```go
err := wv.Select("main", "#country-select", "US")
```
### Check/Uncheck
```go
err := wv.Check("main", "#agree-checkbox", true)
```
### Hover
```go
err := wv.Hover("main", ".dropdown-trigger")
```
### Scroll
```go
// Scroll to element
err := wv.Scroll("main", "#section-3", 0, 0)
// Scroll by coordinates
err := wv.Scroll("main", "", 0, 500)
```
## Element Information
### Query Selector
```go
elements, err := wv.QuerySelector("main", ".list-item")
```
### Element Info
```go
info, err := wv.GetElementInfo("main", "#user-card")
// Returns: tag, id, classes, text, attributes, bounds
```
### Computed Styles
```go
styles, err := wv.GetComputedStyle("main", ".button",
[]string{"color", "background-color", "font-size"})
```
### DOM Tree
```go
tree, err := wv.GetDOMTree("main", 5) // max depth 5
```
## Console Messages
```go
// Setup console listener
wv.SetupConsoleListener()
// Inject capture script
wv.InjectConsoleCapture("main")
// Get messages
messages := wv.GetConsoleMessages("all", 100)
messages := wv.GetConsoleMessages("error", 50)
// Clear buffer
wv.ClearConsole()
// Get errors only
errors := wv.GetErrors(50)
```
## Screenshots
```go
// Full page screenshot (base64 PNG)
data, err := wv.Screenshot("main")
// Element screenshot
data, err := wv.ScreenshotElement("main", "#chart")
// Export as PDF
pdfData, err := wv.ExportToPDF("main", map[string]any{
"margin": 20,
})
```
## Page Information
```go
// Get current URL
url, err := wv.GetURL("main")
// Get page title
title, err := wv.GetTitle("main")
// Get page source
source, err := wv.GetPageSource("main")
// Navigate
err := wv.Navigate("main", "https://example.com")
```
## Network Monitoring
```go
// Inject network interceptor
wv.InjectNetworkInterceptor("main")
// Get captured requests
requests, err := wv.GetNetworkRequests("main", 100)
// Clear request log
wv.ClearNetworkRequests("main")
```
## Performance Metrics
```go
metrics, err := wv.GetPerformance("main")
// Returns: loadTime, domContentLoaded, firstPaint, etc.
```
## Resource Listing
```go
resources, err := wv.GetResources("main")
// Returns: scripts, stylesheets, images, fonts, etc.
```
## Visual Debugging
```go
// Highlight element temporarily
err := wv.Highlight("main", "#target-element", 2000) // 2 seconds
```
## Window Listing
```go
windows := wv.ListWindows()
for _, w := range windows {
fmt.Println(w.Name)
}
```
## Frontend Usage
The WebView service is primarily used server-side for:
- Automated testing
- AI assistant interactions (via MCP)
- Scripted UI interactions
For normal frontend development, use standard DOM APIs directly.

View file

@ -1,152 +0,0 @@
# Workspace Service
The Workspace service (`pkg/workspace`) manages isolated user workspaces with encrypted storage and PGP key pairs.
## Features
- Isolated workspace environments
- PGP key pair generation per workspace
- Encrypted workspace identification
- File operations within workspace context
- Multiple workspace support
## Basic Usage
```go
import "github.com/Snider/Core/pkg/workspace"
// With IO medium (standalone)
medium, _ := local.New("/app/workspaces")
ws, err := workspace.New(medium)
// With Core framework (recommended)
c, _ := core.New(
core.WithService(workspace.Register),
)
ws := core.MustServiceFor[*workspace.Service](c, "workspace")
```
## Creating Workspaces
```go
// Create a new encrypted workspace
workspaceID, err := ws.CreateWorkspace("my-project", "secure-password")
// Returns obfuscated workspace ID
// Workspace structure created:
// workspaces/
// <workspace-id>/
// config/
// log/
// data/
// files/
// keys/
// key.pub (PGP public key)
// key.priv (PGP private key)
```
## Switching Workspaces
```go
// Switch to a workspace
err := ws.SwitchWorkspace(workspaceID)
// Switch to default workspace
err := ws.SwitchWorkspace("default")
```
## Workspace File Operations
```go
// Write file to active workspace
err := ws.WorkspaceFileSet("config/settings.json", jsonData)
// Read file from active workspace
content, err := ws.WorkspaceFileGet("config/settings.json")
```
## Listing Workspaces
```go
// Get all workspace IDs
workspaces := ws.ListWorkspaces()
for _, id := range workspaces {
fmt.Println(id)
}
```
## Active Workspace
```go
// Get current workspace info
active := ws.ActiveWorkspace()
if active != nil {
fmt.Println("Name:", active.Name)
fmt.Println("Path:", active.Path)
}
```
## Workspace Structure
Each workspace contains:
| Directory | Purpose |
|-----------|---------|
| `config/` | Workspace configuration files |
| `log/` | Workspace logs |
| `data/` | Application data |
| `files/` | User files |
| `keys/` | PGP key pair |
## Security Model
Workspaces use a two-level hashing scheme:
1. **Real Name**: Hash of the identifier
2. **Workspace ID**: Hash of `workspace/{real_name}`
This prevents workspace enumeration while allowing consistent access.
## IPC Events
The workspace service responds to IPC messages:
```go
// Switch workspace via IPC
c.ACTION(core.Message{
Type: "workspace.switch_workspace",
Data: map[string]any{
"name": workspaceID,
},
})
```
## Frontend Usage (TypeScript)
```typescript
import {
CreateWorkspace,
SwitchWorkspace,
WorkspaceFileGet,
WorkspaceFileSet,
ListWorkspaces,
ActiveWorkspace
} from '@bindings/workspace/service';
// Create workspace
const wsId = await CreateWorkspace("my-project", "password");
// Switch workspace
await SwitchWorkspace(wsId);
// Read/write files
const config = await WorkspaceFileGet("config/app.json");
await WorkspaceFileSet("config/app.json", JSON.stringify(newConfig));
// List all workspaces
const workspaces = await ListWorkspaces();
// Get active workspace
const active = await ActiveWorkspace();
console.log(`Current: ${active.Name} at ${active.Path}`);
```