feat(01-01): boot hello app and dispatch greeter:hello

- Add party plugin registry with Register-before-Boot activation
- Add backpack, compass, bonfire, and pact capability interfaces
- Add examples/hello with two compiled plugin modules
This commit is contained in:
Jakub Zych
2026-09-16 12:57:18 +02:00
parent 552cadbdf9
commit 96a8d38be2
26 changed files with 982 additions and 0 deletions

72
compass/config.go Normal file
View File

@@ -0,0 +1,72 @@
package compass
import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/knadh/koanf/parsers/yaml"
"github.com/knadh/koanf/v2"
)
// Config is a YAML configuration tree with dot-path access.
type Config struct {
k *koanf.Koanf
}
// Load reads config/<section>.yaml files from dir. Each filename stem becomes
// the top-level section, so config/app.yaml key name is app.name.
func Load(dir string) (*Config, error) {
k := koanf.New(".")
entries, err := os.ReadDir(dir)
if err != nil {
return nil, fmt.Errorf("compass: read config dir %s: %w", dir, err)
}
parser := yaml.Parser()
for _, entry := range entries {
if entry.IsDir() {
continue
}
name := entry.Name()
section, ok := sectionName(name)
if !ok {
continue
}
path := filepath.Join(dir, name)
raw, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("compass: read %s: %w", path, err)
}
parsed, err := parser.Unmarshal(raw)
if err != nil {
return nil, fmt.Errorf("compass: parse %s: %w", path, err)
}
if parsed == nil {
parsed = map[string]any{}
}
if err := k.Set(section, parsed); err != nil {
return nil, fmt.Errorf("compass: set section %s: %w", section, err)
}
}
return &Config{k: k}, nil
}
// String returns the string value at path, or "" if unset.
func (c *Config) String(path string) string {
if c == nil || c.k == nil {
return ""
}
return c.k.String(path)
}
func sectionName(filename string) (string, bool) {
switch {
case strings.HasSuffix(filename, ".yaml"):
return strings.TrimSuffix(filename, ".yaml"), true
case strings.HasSuffix(filename, ".yml"):
return strings.TrimSuffix(filename, ".yml"), true
default:
return "", false
}
}

23
compass/config_test.go Normal file
View File

@@ -0,0 +1,23 @@
package compass
import (
"os"
"path/filepath"
"testing"
)
func TestLoadStringFromAppSection(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "app.yaml")
if err := os.WriteFile(path, []byte("name: hello-app\n"), 0o644); err != nil {
t.Fatal(err)
}
cfg, err := Load(dir)
if err != nil {
t.Fatalf("Load: %v", err)
}
if got := cfg.String("app.name"); got != "hello-app" {
t.Fatalf("String(app.name) = %q, want hello-app", got)
}
}