docs(ax): align workspace reference usage examples

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-03-30 00:52:39 +00:00
parent 620f702591
commit f32720b692
7 changed files with 135 additions and 1 deletions

View file

@ -342,6 +342,58 @@ func TestLib_ExtractWorkspace_Good_ReferenceHeaders(t *testing.T) {
}
}
func TestLib_ExtractWorkspace_Good_ReferenceUsageExamples(t *testing.T) {
dir := t.TempDir()
data := &WorkspaceData{Repo: "test-repo", Task: "carry AX usage examples into workspace references"}
if err := ExtractWorkspace("default", dir, data); err != nil {
t.Fatalf("ExtractWorkspace failed: %v", err)
}
cases := map[string][]string{
core.JoinPath(dir, ".core", "reference", "array.go"): {
`arr := core.NewArray("prep", "dispatch")`,
`arr.Add("verify", "merge")`,
`arr.AddUnique("verify", "verify", "merge")`,
},
core.JoinPath(dir, ".core", "reference", "config.go"): {
`timeout := core.ConfigGet[int](c.Config(), "agent.timeout")`,
},
core.JoinPath(dir, ".core", "reference", "embed.go"): {
`core.AddAsset("docs", "RFC.md", packed)`,
`r := core.GeneratePack(pkg)`,
},
core.JoinPath(dir, ".core", "reference", "error.go"): {
`if core.Is(err, context.Canceled) { return }`,
`stack := core.FormatStackTrace(err)`,
`r := c.Error().Reports(10)`,
},
core.JoinPath(dir, ".core", "reference", "log.go"): {
`log := core.NewLog(core.LogOptions{Level: core.LevelDebug, Output: os.Stdout})`,
`core.SetRedactKeys("token", "password")`,
`core.Security("entitlement.denied", "action", "process.run")`,
},
core.JoinPath(dir, ".core", "reference", "runtime.go"): {
`r := c.ServiceStartup(context.Background(), nil)`,
`r := core.NewRuntime(app)`,
`name := runtime.ServiceName()`,
},
}
for path, snippets := range cases {
r := testFs.Read(path)
if !r.OK {
t.Fatalf("failed to read %s", path)
}
text := r.Value.(string)
for _, snippet := range snippets {
if !core.Contains(text, snippet) {
t.Errorf("%s missing usage example snippet %q", path, snippet)
}
}
}
}
func TestLib_MountEmbed_Bad(t *testing.T) {
result := mountEmbed(promptFiles, "missing-dir")
if result.OK {

View file

@ -10,17 +10,23 @@ type Array[T comparable] struct {
items []T
}
// NewArray creates an empty Array.
// NewArray creates an Array with the provided items.
//
// arr := core.NewArray("prep", "dispatch")
func NewArray[T comparable](items ...T) *Array[T] {
return &Array[T]{items: items}
}
// Add appends values.
//
// arr.Add("verify", "merge")
func (s *Array[T]) Add(values ...T) {
s.items = append(s.items, values...)
}
// AddUnique appends values only if not already present.
//
// arr.AddUnique("verify", "verify", "merge")
func (s *Array[T]) AddUnique(values ...T) {
for _, v := range values {
if !s.Contains(v) {
@ -40,6 +46,8 @@ func (s *Array[T]) Contains(val T) bool {
}
// Filter returns a new Array with elements matching the predicate.
//
// r := arr.Filter(func(step string) bool { return core.Contains(step, "prep") })
func (s *Array[T]) Filter(fn func(T) bool) Result {
filtered := &Array[T]{}
for _, v := range s.items {
@ -68,6 +76,8 @@ func (s *Array[T]) Remove(val T) {
}
// Deduplicate removes duplicate values, preserving order.
//
// arr.Deduplicate()
func (s *Array[T]) Deduplicate() {
seen := make(map[T]struct{})
result := make([]T, 0, len(s.items))
@ -91,6 +101,8 @@ func (s *Array[T]) Clear() {
}
// AsSlice returns a copy of the underlying slice.
//
// items := arr.AsSlice()
func (s *Array[T]) AsSlice() []T {
if s.items == nil {
return nil

View file

@ -117,6 +117,8 @@ func (e *Config) Int(key string) int { return ConfigGet[int](e, key) }
func (e *Config) Bool(key string) bool { return ConfigGet[bool](e, key) }
// ConfigGet retrieves a typed configuration value.
//
// timeout := core.ConfigGet[int](c.Config(), "agent.timeout")
func ConfigGet[T any](e *Config, key string) T {
r := e.Get(key)
if !r.OK {

View file

@ -51,6 +51,8 @@ var (
)
// AddAsset registers a packed asset at runtime (called from generated init()).
//
// core.AddAsset("docs", "RFC.md", packed)
func AddAsset(group, name, data string) {
assetGroupsMu.Lock()
defer assetGroupsMu.Unlock()
@ -214,6 +216,8 @@ func ScanAssets(filenames []string) Result {
}
// GeneratePack creates Go source code that embeds the scanned assets.
//
// r := core.GeneratePack(pkg)
func GeneratePack(pkg ScannedPackage) Result {
b := NewBuilder()

View file

@ -120,18 +120,25 @@ func NewCode(code, msg string) error {
// Is reports whether any error in err's tree matches target.
// Wrapper around errors.Is for convenience.
//
// if core.Is(err, context.Canceled) { return }
func Is(err, target error) bool {
return errors.Is(err, target)
}
// As finds the first error in err's tree that matches target.
// Wrapper around errors.As for convenience.
//
// var typed *core.Err
// if core.As(err, &typed) { core.Println(typed.Operation) }
func As(err error, target any) bool {
return errors.As(err, target)
}
// NewError creates a simple error with the given text.
// Wrapper around errors.New for convenience.
//
// err := core.NewError("workspace not found")
func NewError(text string) error {
return errors.New(text)
}
@ -147,6 +154,8 @@ func ErrorJoin(errs ...error) error {
// Operation extracts the operation name from an error.
// Returns empty string if the error is not an *Err.
//
// op := core.Operation(err)
func Operation(err error) string {
var e *Err
if As(err, &e) {
@ -157,6 +166,8 @@ func Operation(err error) string {
// ErrorCode extracts the error code from an error.
// Returns empty string if the error is not an *Err or has no code.
//
// code := core.ErrorCode(err)
func ErrorCode(err error) string {
var e *Err
if As(err, &e) {
@ -180,6 +191,8 @@ func ErrorMessage(err error) string {
// Root returns the root cause of an error chain.
// Unwraps until no more wrapped errors are found.
//
// cause := core.Root(err)
func Root(err error) error {
if err == nil {
return nil
@ -212,6 +225,8 @@ func AllOperations(err error) iter.Seq[string] {
// StackTrace returns the logical stack trace (chain of operations) from an error.
// It returns an empty slice if no operational context is found.
//
// trace := core.StackTrace(err)
func StackTrace(err error) []string {
var stack []string
for op := range AllOperations(err) {
@ -221,6 +236,8 @@ func StackTrace(err error) []string {
}
// FormatStackTrace returns a pretty-printed logical stack trace.
//
// stack := core.FormatStackTrace(err)
func FormatStackTrace(err error) string {
var ops []string
for op := range AllOperations(err) {
@ -338,6 +355,8 @@ func (h *ErrorPanic) Recover() {
}
// SafeGo runs a function in a goroutine with panic recovery.
//
// c.Error().SafeGo(func() { runWorker() })
func (h *ErrorPanic) SafeGo(fn func()) {
go func() {
defer h.Recover()
@ -346,6 +365,8 @@ func (h *ErrorPanic) SafeGo(fn func()) {
}
// Reports returns the last n crash reports from the file.
//
// r := c.Error().Reports(10)
func (h *ErrorPanic) Reports(n int) Result {
if h.filePath == "" {
return Result{}

View file

@ -110,6 +110,8 @@ type LogOptions struct {
var RotationWriterFactory func(RotationLogOptions) goio.WriteCloser
// New creates a new Log with the given options.
//
// log := core.NewLog(core.LogOptions{Level: core.LevelDebug, Output: os.Stdout})
func NewLog(opts LogOptions) *Log {
output := opts.Output
if opts.Rotation != nil && opts.Rotation.Filename != "" && RotationWriterFactory != nil {
@ -286,6 +288,8 @@ func (l *Log) Security(msg string, keyvals ...any) {
// Username returns the current system username.
// It uses os/user for reliability and falls back to environment variables.
//
// user := core.Username()
func Username() string {
if u, err := user.Current(); err == nil {
return u.Username
@ -307,46 +311,64 @@ func init() {
}
// Default returns the default logger.
//
// log := core.Default()
func Default() *Log {
return defaultLogPtr.Load()
}
// SetDefault sets the default logger.
//
// core.SetDefault(core.NewLog(core.LogOptions{Level: core.LevelWarn}))
func SetDefault(l *Log) {
defaultLogPtr.Store(l)
}
// SetLevel sets the default logger's level.
//
// core.SetLevel(core.LevelDebug)
func SetLevel(level Level) {
Default().SetLevel(level)
}
// SetRedactKeys sets the default logger's redaction keys.
//
// core.SetRedactKeys("token", "password")
func SetRedactKeys(keys ...string) {
Default().SetRedactKeys(keys...)
}
// Debug logs to the default logger.
//
// core.Debug("agent dispatched", "repo", "core/agent")
func Debug(msg string, keyvals ...any) {
Default().Debug(msg, keyvals...)
}
// Info logs to the default logger.
//
// core.Info("workspace ready", "path", "/srv/ws-42")
func Info(msg string, keyvals ...any) {
Default().Info(msg, keyvals...)
}
// Warn logs to the default logger.
//
// core.Warn("queue delay increased", "seconds", 30)
func Warn(msg string, keyvals ...any) {
Default().Warn(msg, keyvals...)
}
// Error logs to the default logger.
//
// core.Error("dispatch failed", "err", err)
func Error(msg string, keyvals ...any) {
Default().Error(msg, keyvals...)
}
// Security logs to the default logger.
//
// core.Security("entitlement.denied", "action", "process.run")
func Security(msg string, keyvals ...any) {
Default().Security(msg, keyvals...)
}
@ -360,6 +382,8 @@ type LogErr struct {
}
// NewLogErr creates a LogErr bound to the given logger.
//
// logErr := core.NewLogErr(core.Default())
func NewLogErr(log *Log) *LogErr {
return &LogErr{log: log}
}
@ -381,6 +405,8 @@ type LogPanic struct {
}
// NewLogPanic creates a LogPanic bound to the given logger.
//
// panicLog := core.NewLogPanic(core.Default())
func NewLogPanic(log *Log) *LogPanic {
return &LogPanic{log: log}
}

View file

@ -21,6 +21,8 @@ type ServiceRuntime[T any] struct {
}
// NewServiceRuntime creates a ServiceRuntime for a service constructor.
//
// svc.ServiceRuntime = core.NewServiceRuntime(c, ServiceOptions{Queue: "default"})
func NewServiceRuntime[T any](c *Core, opts T) *ServiceRuntime[T] {
return &ServiceRuntime[T]{core: c, opts: opts}
}
@ -43,6 +45,8 @@ func (r *ServiceRuntime[T]) Config() *Config { return r.core.Config() }
// --- Lifecycle ---
// ServiceStartup runs OnStart for all registered services that have one.
//
// r := c.ServiceStartup(context.Background(), nil)
func (c *Core) ServiceStartup(ctx context.Context, options any) Result {
c.shutdown.Store(false)
c.context, c.cancel = context.WithCancel(ctx)
@ -63,6 +67,8 @@ func (c *Core) ServiceStartup(ctx context.Context, options any) Result {
}
// ServiceShutdown drains background tasks, then stops all registered services.
//
// r := c.ServiceShutdown(context.Background())
func (c *Core) ServiceShutdown(ctx context.Context) Result {
c.shutdown.Store(true)
c.cancel() // signal all context-aware tasks to stop
@ -116,6 +122,8 @@ type Runtime struct {
type ServiceFactory func() Result
// NewWithFactories creates a Runtime with the provided service factories.
//
// r := core.NewWithFactories(app, map[string]core.ServiceFactory{"brain": newBrainService})
func NewWithFactories(app any, factories map[string]ServiceFactory) Result {
c := New(WithOptions(NewOptions(Option{Key: "name", Value: "core"})))
c.app.Runtime = app
@ -144,18 +152,27 @@ func NewWithFactories(app any, factories map[string]ServiceFactory) Result {
}
// NewRuntime creates a Runtime with no custom services.
//
// r := core.NewRuntime(app)
func NewRuntime(app any) Result {
return NewWithFactories(app, map[string]ServiceFactory{})
}
// ServiceName returns "Core" — the Runtime's service identity.
//
// name := runtime.ServiceName()
func (r *Runtime) ServiceName() string { return "Core" }
// ServiceStartup starts all services via the embedded Core.
//
// runtime.ServiceStartup(context.Background(), nil)
func (r *Runtime) ServiceStartup(ctx context.Context, options any) Result {
return r.Core.ServiceStartup(ctx, options)
}
// ServiceShutdown stops all services via the embedded Core.
//
// runtime.ServiceShutdown(context.Background())
func (r *Runtime) ServiceShutdown(ctx context.Context) Result {
if r.Core != nil {
return r.Core.ServiceShutdown(ctx)