diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..a9b5d2b3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,102 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Core is a Web3 Framework written in Go using Wails v3 to replace Electron for desktop applications. It provides a dependency injection framework for managing services with lifecycle support. + +## Build & Development Commands + +This project uses [Task](https://taskfile.dev/) for automation. Key commands: + +```bash +# Run all tests +task test + +# Generate test coverage +task cov +task cov-view # Opens coverage HTML report + +# GUI application (Wails) +task gui:dev # Development mode with hot-reload +task gui:build # Production build + +# CLI application +task cli:build # Build CLI +task cli:run # Build and run CLI + +# Code review +task review # Submit for CodeRabbit review +task check # Run mod tidy + tests + review +``` + +Run a single test: `go test -run TestName ./...` + +## Architecture + +### Core Framework (`core.go`, `interfaces.go`) + +The `Core` struct is the central application container managing: +- **Services**: Named service registry with type-safe retrieval via `ServiceFor[T]()` and `MustServiceFor[T]()` +- **Actions/IPC**: Message-passing system where services communicate via `ACTION(msg Message)` and register handlers via `RegisterAction()` +- **Lifecycle**: Services implementing `Startable` (OnStartup) and/or `Stoppable` (OnShutdown) interfaces are automatically called during app lifecycle + +Creating a Core instance: +```go +core, err := core.New( + core.WithService(myServiceFactory), + core.WithAssets(assets), + core.WithServiceLock(), // Prevents late service registration +) +``` + +### Service Registration Pattern + +Services are registered via factory functions that receive the Core instance: +```go +func NewMyService(c *core.Core) (any, error) { + return &MyService{runtime: core.NewServiceRuntime(c, opts)}, nil +} + +core.New(core.WithService(NewMyService)) +``` + +- `WithService`: Auto-discovers service name from package path, registers IPC handler if service has `HandleIPCEvents` method +- `WithName`: Explicitly names a service + +### Runtime (`runtime_pkg.go`) + +`Runtime` is the Wails service wrapper that bootstraps the Core and its services. Use `NewWithFactories()` for custom service registration or `NewRuntime()` for basic setup. + +### ServiceRuntime Generic Helper (`runtime.go`) + +Embed `ServiceRuntime[T]` in services to get access to Core and typed options: +```go +type MyService struct { + *core.ServiceRuntime[MyServiceOptions] +} +``` + +### Error Handling (`e.go`) + +Use the `E()` helper for contextual errors: +```go +return core.E("service.Method", "what failed", underlyingErr) +``` + +### Test Naming Convention + +Tests use `_Good`, `_Bad`, `_Ugly` suffix pattern: +- `_Good`: Happy path tests +- `_Bad`: Expected error conditions +- `_Ugly`: Panic/edge cases + +## Go Workspace + +Uses Go 1.25 workspaces. The workspace includes: +- Root module (Core framework) +- `cmd/core-gui` (Wails GUI application) +- `cmd/examples/*` (Example applications) + +After adding modules: `go work sync` \ No newline at end of file diff --git a/cmd/examples/core-static-di/main.go b/cmd/examples/core-static-di/main.go index 137fd18e..a9259ea7 100644 --- a/cmd/examples/core-static-di/main.go +++ b/cmd/examples/core-static-di/main.go @@ -4,7 +4,7 @@ import ( "embed" "log" - "github.com/Snider/Core/runtime" + "github.com/Snider/Core "github.com/wailsapp/wails/v3/pkg/application" ) @@ -20,7 +20,7 @@ func main() { }) // 2. Instantiate all services using the static runtime - appServices, err := runtime.New() + appServices, err := core.New() if err != nil { log.Fatalf("Failed to build application with static runtime: %v", err) } diff --git a/go.work b/go.work index 5d542e71..16fe2ec0 100644 --- a/go.work +++ b/go.work @@ -3,4 +3,5 @@ go 1.25 use ( . ./cmd/core-gui + cmd/examples/core-static-di ) diff --git a/go.work.sum b/go.work.sum index 0f015c2d..5fac6786 100644 --- a/go.work.sum +++ b/go.work.sum @@ -315,8 +315,14 @@ github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= +github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= @@ -419,8 +425,6 @@ golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=